@zodiac-os/sdk 1.8.0 → 1.9.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/cli.mjs CHANGED
@@ -8,7 +8,7 @@ import { invariant } from "@epic-web/invariant";
8
8
  import { getAddress } from "ethers";
9
9
  import { Command } from "commander";
10
10
  import { config } from "dotenv";
11
- import { randomBytes } from "node:crypto";
11
+ import { createHash, randomBytes } from "node:crypto";
12
12
  import { createServer } from "node:http";
13
13
  import open from "open";
14
14
  import { join as join$1 } from "path";
@@ -21,87 +21,83 @@ const init = async (options = {}) => {
21
21
  const rootDir = options.rootDir ?? process.cwd();
22
22
  const appUrl = (options.appUrl ?? process.env.ZODIAC_APP_URL ?? DEFAULT_APP_URL).replace(/\/$/, "");
23
23
  const label = basename(resolve(rootDir)) || "zodiac-cli";
24
+ const codeVerifier = randomBytes(32).toString("base64url");
25
+ const codeChallenge = createHash("sha256").update(codeVerifier).digest("base64url");
24
26
  const state = randomBytes(32).toString("base64url");
25
- const appOrigin = new URL(appUrl).origin;
26
- const { port, waitForKey, close } = await startCallbackServer({
27
- appOrigin,
28
- expectedState: state
27
+ const { port, waitForCode, close } = await startCallbackServer({
28
+ expectedState: state,
29
+ appUrl
29
30
  });
30
31
  const callbackUrl = `http://127.0.0.1:${port}/callback`;
31
32
  const authUrl = new URL("/cli-auth", appUrl);
32
33
  authUrl.searchParams.set("callback", callbackUrl);
33
34
  authUrl.searchParams.set("state", state);
35
+ authUrl.searchParams.set("code_challenge", codeChallenge);
34
36
  authUrl.searchParams.set("label", label);
35
37
  console.log(`Opening ${authUrl} in your browser. Approve the request to receive an API key.`);
36
38
  await open(authUrl.toString());
37
- let key;
39
+ let code;
38
40
  try {
39
- key = await waitForKey(CALLBACK_TIMEOUT_MS);
41
+ code = await waitForCode(CALLBACK_TIMEOUT_MS);
40
42
  } finally {
41
43
  await close();
42
44
  }
45
+ const apiKey = await exchangeCodeForKey(appUrl, code, codeVerifier);
43
46
  const envPath = join(rootDir, ".env");
44
- const apiUrl = `${appUrl}/api/v1`;
45
47
  writeEnv(envPath, {
46
- ZODIAC_API_KEY: key,
47
- ZODIAC_API_URL: apiUrl
48
+ ZODIAC_API_KEY: apiKey,
49
+ ZODIAC_API_URL: `${appUrl}/api/v1`
48
50
  });
49
51
  console.log(`✅ API key written to ${envPath}`);
52
+ return apiKey;
53
+ };
54
+ const exchangeCodeForKey = async (appUrl, code, codeVerifier) => {
55
+ const response = await fetch(`${appUrl}/cli-auth/exchange`, {
56
+ method: "POST",
57
+ headers: { "content-type": "application/json" },
58
+ body: JSON.stringify({
59
+ code,
60
+ code_verifier: codeVerifier
61
+ })
62
+ });
63
+ if (!response.ok) {
64
+ let detail = "";
65
+ try {
66
+ const body = await response.json();
67
+ detail = body.error ? `: ${body.error}` : "";
68
+ } catch {}
69
+ throw new Error(`Failed to exchange auth code (${response.status})${detail}`);
70
+ }
71
+ const { key } = await response.json();
72
+ if (typeof key !== "string" || !key.startsWith("zodiac_")) throw new Error("Exchange endpoint returned an unexpected response (missing or malformed key)");
50
73
  return key;
51
74
  };
52
- const startCallbackServer = async ({ appOrigin, expectedState }) => {
53
- let resolveKey = () => {};
54
- let rejectKey = () => {};
55
- const keyPromise = new Promise((res, rej) => {
56
- resolveKey = res;
57
- rejectKey = rej;
75
+ const startCallbackServer = async ({ expectedState, appUrl }) => {
76
+ let resolveCode = () => {};
77
+ let rejectCode = () => {};
78
+ const codePromise = new Promise((res, rej) => {
79
+ resolveCode = res;
80
+ rejectCode = rej;
58
81
  });
59
82
  const handler = (req, res) => {
60
- const isAllowedOrigin = req.headers.origin === appOrigin;
61
- if (isAllowedOrigin) {
62
- res.setHeader("Access-Control-Allow-Origin", appOrigin);
63
- res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
64
- res.setHeader("Access-Control-Allow-Headers", "content-type");
65
- if (req.headers["access-control-request-private-network"] === "true") res.setHeader("Access-Control-Allow-Private-Network", "true");
66
- }
67
- if (req.method === "OPTIONS") {
68
- res.statusCode = isAllowedOrigin ? 204 : 403;
83
+ if (req.method !== "GET" || !req.url?.startsWith("/callback")) {
84
+ res.statusCode = 404;
69
85
  res.end();
70
86
  return;
71
87
  }
72
- if (req.method !== "POST" || req.url !== "/callback") {
73
- res.statusCode = 404;
74
- res.end();
88
+ const url = new URL(req.url, `http://127.0.0.1`);
89
+ const code = url.searchParams.get("code");
90
+ if (url.searchParams.get("state") !== expectedState) {
91
+ respondHtml(res, 403, renderHtml("Mismatched state", `<p>This callback didn't match the running <code>zodiac init</code> session. You can close this tab.</p>`));
75
92
  return;
76
93
  }
77
- if (!isAllowedOrigin) {
78
- res.statusCode = 403;
79
- res.end();
94
+ if (typeof code !== "string" || code.length === 0) {
95
+ respondHtml(res, 400, renderHtml("Missing code", `<p>The callback URL didn't include an auth <code>code</code>. Please re-run <code>zodiac init</code>.</p>`));
80
96
  return;
81
97
  }
82
- const chunks = [];
83
- req.on("data", (chunk) => chunks.push(chunk));
84
- req.on("end", () => {
85
- try {
86
- const body = JSON.parse(Buffer.concat(chunks).toString("utf8"));
87
- if (typeof body.state !== "string" || body.state !== expectedState) {
88
- res.statusCode = 403;
89
- res.end();
90
- return;
91
- }
92
- if (typeof body.key !== "string" || !body.key.startsWith("zodiac_")) {
93
- res.statusCode = 400;
94
- res.end();
95
- return;
96
- }
97
- res.setHeader("Connection", "close");
98
- res.statusCode = 200;
99
- res.end(() => resolveKey(body.key));
100
- } catch {
101
- res.statusCode = 400;
102
- res.end();
103
- }
104
- });
98
+ respondHtml(res, 200, renderHtml("Authorized", `<p>Your CLI now has its API key. You can close this tab and return to your terminal.</p>
99
+ <p><a href="${escapeHtml(appUrl)}">Back to Zodiac</a></p>`));
100
+ resolveCode(code);
105
101
  };
106
102
  const server = createServer(handler);
107
103
  await new Promise((res) => server.listen(0, "127.0.0.1", res));
@@ -111,16 +107,42 @@ const startCallbackServer = async ({ appOrigin, expectedState }) => {
111
107
  const close = () => new Promise((resolve) => {
112
108
  server.close(() => resolve());
113
109
  });
114
- const waitForKey = (timeoutMs) => Promise.race([keyPromise, new Promise((_, rej) => setTimeout(() => {
115
- rejectKey(/* @__PURE__ */ new Error(`Timed out waiting for CLI auth callback`));
110
+ const waitForCode = (timeoutMs) => Promise.race([codePromise, new Promise((_, rej) => setTimeout(() => {
111
+ rejectCode(/* @__PURE__ */ new Error(`Timed out waiting for CLI auth callback`));
116
112
  rej(/* @__PURE__ */ new Error(`Timed out waiting for CLI auth callback`));
117
113
  }, timeoutMs))]);
118
114
  return {
119
115
  port,
120
- waitForKey,
116
+ waitForCode,
121
117
  close
122
118
  };
123
119
  };
120
+ const respondHtml = (res, status, body) => {
121
+ res.setHeader("Connection", "close");
122
+ res.setHeader("content-type", "text/html; charset=utf-8");
123
+ res.statusCode = status;
124
+ res.end(body);
125
+ };
126
+ const renderHtml = (title, bodyHtml) => `<!doctype html>
127
+ <html lang="en">
128
+ <head>
129
+ <meta charset="utf-8" />
130
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
131
+ <title>${escapeHtml(title)} — Zodiac CLI</title>
132
+ <style>
133
+ body { font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; max-width: 32rem; margin: 4rem auto; padding: 0 1rem; color: #1f2937; }
134
+ h1 { font-weight: 300; font-size: 1.75rem; margin-bottom: 1rem; }
135
+ code { background: #f3f4f6; padding: 0.125rem 0.375rem; border-radius: 0.25rem; }
136
+ a { color: #1d4ed8; }
137
+ </style>
138
+ </head>
139
+ <body>
140
+ <h1>${escapeHtml(title)}</h1>
141
+ ${bodyHtml}
142
+ </body>
143
+ </html>
144
+ `;
145
+ const escapeHtml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
124
146
  const writeEnv = (envPath, vars) => {
125
147
  let contents = existsSync(envPath) ? readFileSync(envPath, "utf8") : "";
126
148
  for (const [key, value] of Object.entries(vars)) contents = upsertEnvLine(contents, key, value);
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":["join","loadDotenv"],"sources":["../src/cli/commands/init.ts","../src/cli/commands/pullOrg.ts","../src/allow/fetch.ts","../src/allow/codegen.ts","../src/cli/commands/pullContracts.ts","../src/cli/run.ts","../src/cli/index.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto'\nimport {\n createServer,\n type IncomingMessage,\n type ServerResponse,\n} from 'node:http'\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { basename, join, resolve } from 'node:path'\nimport open from 'open'\n\nconst DEFAULT_APP_URL = 'https://app.zodiac.eco'\nconst CALLBACK_TIMEOUT_MS = 5 * 60 * 1000 // 5 minutes\n\ntype InitOptions = {\n rootDir?: string\n /** Override the Zodiac app base URL (defaults to ZODIAC_APP_URL env or app.zodiac.eco). */\n appUrl?: string\n}\n\nexport const init = async (options: InitOptions = {}): Promise<string> => {\n const rootDir = options.rootDir ?? process.cwd()\n const appUrl = (\n options.appUrl ??\n process.env.ZODIAC_APP_URL ??\n DEFAULT_APP_URL\n ).replace(/\\/$/, '')\n\n const label = basename(resolve(rootDir)) || 'zodiac-cli'\n const state = randomBytes(32).toString('base64url')\n\n const appOrigin = new URL(appUrl).origin\n\n const { port, waitForKey, close } = await startCallbackServer({\n appOrigin,\n expectedState: state,\n })\n\n const callbackUrl = `http://127.0.0.1:${port}/callback`\n const authUrl = new URL('/cli-auth', appUrl)\n authUrl.searchParams.set('callback', callbackUrl)\n authUrl.searchParams.set('state', state)\n authUrl.searchParams.set('label', label)\n\n console.log(\n `Opening ${authUrl} in your browser. Approve the request to receive an API key.`\n )\n await open(authUrl.toString())\n\n let key: string\n try {\n key = await waitForKey(CALLBACK_TIMEOUT_MS)\n } finally {\n await close()\n }\n\n const envPath = join(rootDir, '.env')\n const apiUrl = `${appUrl}/api/v1`\n writeEnv(envPath, { ZODIAC_API_KEY: key, ZODIAC_API_URL: apiUrl })\n\n console.log(`✅ API key written to ${envPath}`)\n\n return key\n}\n\ntype StartServerOptions = {\n appOrigin: string\n expectedState: string\n}\n\ntype StartServerResult = {\n port: number\n waitForKey: (timeoutMs: number) => Promise<string>\n close: () => Promise<void>\n}\n\nconst startCallbackServer = async ({\n appOrigin,\n expectedState,\n}: StartServerOptions): Promise<StartServerResult> => {\n let resolveKey: (key: string) => void = () => {}\n let rejectKey: (err: Error) => void = () => {}\n const keyPromise = new Promise<string>((res, rej) => {\n resolveKey = res\n rejectKey = rej\n })\n\n const handler = (req: IncomingMessage, res: ServerResponse) => {\n const origin = req.headers.origin\n const isAllowedOrigin = origin === appOrigin\n\n // CORS / Private Network Access preflight + actual response headers.\n if (isAllowedOrigin) {\n res.setHeader('Access-Control-Allow-Origin', appOrigin)\n res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS')\n res.setHeader('Access-Control-Allow-Headers', 'content-type')\n // Required for Chrome's Private Network Access preflight when an\n // HTTPS page targets http://localhost.\n if (req.headers['access-control-request-private-network'] === 'true') {\n res.setHeader('Access-Control-Allow-Private-Network', 'true')\n }\n }\n\n if (req.method === 'OPTIONS') {\n res.statusCode = isAllowedOrigin ? 204 : 403\n res.end()\n return\n }\n\n if (req.method !== 'POST' || req.url !== '/callback') {\n res.statusCode = 404\n res.end()\n return\n }\n\n if (!isAllowedOrigin) {\n res.statusCode = 403\n res.end()\n return\n }\n\n const chunks: Buffer[] = []\n req.on('data', (chunk: Buffer) => chunks.push(chunk))\n req.on('end', () => {\n try {\n const body = JSON.parse(Buffer.concat(chunks).toString('utf8'))\n if (typeof body.state !== 'string' || body.state !== expectedState) {\n // Don't reject — could be a stray request from a malicious local\n // process. Stay silent and keep waiting for the real one.\n res.statusCode = 403\n res.end()\n return\n }\n if (typeof body.key !== 'string' || !body.key.startsWith('zodiac_')) {\n res.statusCode = 400\n res.end()\n return\n }\n // Force the connection to close after the response so the browser\n // doesn't keep waiting on a keep-alive socket once the CLI exits.\n // Resolve only after 'finish' (response handed to the OS) so the\n // bytes can flush before the process tears down.\n res.setHeader('Connection', 'close')\n res.statusCode = 200\n res.end(() => resolveKey(body.key))\n } catch {\n res.statusCode = 400\n res.end()\n }\n })\n }\n\n const server = createServer(handler)\n await new Promise<void>((res) => server.listen(0, '127.0.0.1', res))\n const address = server.address()\n if (address == null || typeof address === 'string') {\n throw new Error('Failed to bind loopback callback server')\n }\n const port = address.port\n\n const close = (): Promise<void> =>\n new Promise<void>((resolve) => {\n server.close(() => resolve())\n })\n\n const waitForKey = (timeoutMs: number) =>\n Promise.race<string>([\n keyPromise,\n new Promise<string>((_, rej) =>\n setTimeout(() => {\n rejectKey(new Error(`Timed out waiting for CLI auth callback`))\n rej(new Error(`Timed out waiting for CLI auth callback`))\n }, timeoutMs)\n ),\n ])\n\n return { port, waitForKey, close }\n}\n\nconst writeEnv = (envPath: string, vars: Record<string, string>): void => {\n let contents = existsSync(envPath) ? readFileSync(envPath, 'utf8') : ''\n\n for (const [key, value] of Object.entries(vars)) {\n contents = upsertEnvLine(contents, key, value)\n }\n\n writeFileSync(envPath, contents, 'utf8')\n}\n\nconst upsertEnvLine = (\n contents: string,\n key: string,\n value: string\n): string => {\n const line = `${key}=${value}`\n const lines = contents.split(/\\r?\\n/)\n const idx = lines.findIndex((l) => new RegExp(`^\\\\s*${key}\\\\s*=`).test(l))\n\n if (idx >= 0) {\n lines[idx] = line\n return lines.join('\\n')\n }\n\n return contents.length === 0 || contents.endsWith('\\n')\n ? `${contents}${line}\\n`\n : `${contents}\\n${line}\\n`\n}\n","import type { ResolvedConfig } from '../config'\nimport { ApiClient } from '../../api'\nimport { invariant } from '@epic-web/invariant'\nimport { getAddress } from 'ethers'\nimport {\n ModuleKind,\n Project,\n ScriptTarget,\n VariableDeclarationKind,\n} from 'ts-morph'\nimport { mkdirSync, writeFileSync } from 'fs'\nimport { join } from 'path'\nimport { resolveZodiacDir } from '../../paths'\n\nconst toLiteral = (value: unknown, indent = 0): string => {\n const pad = ' '.repeat(indent)\n const childPad = ' '.repeat(indent + 1)\n\n if (value === null) return 'null'\n if (typeof value === 'bigint') return `${value}n`\n if (typeof value === 'string') return JSON.stringify(value)\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value)\n if (Array.isArray(value)) {\n if (value.length === 0) return '[]'\n return `[\\n${value.map((v) => `${childPad}${toLiteral(v, indent + 1)}`).join(',\\n')},\\n${pad}]`\n }\n if (typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>)\n if (entries.length === 0) return '{}'\n const props = entries.map(\n ([k, v]) =>\n `${childPad}${/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k) ? k : JSON.stringify(k)}: ${toLiteral(v, indent + 1)}`\n )\n return `{\\n${props.join(',\\n')},\\n${pad}}`\n }\n return String(value)\n}\n\nexport const pullOrg = async (config: ResolvedConfig) => {\n const client = new ApiClient({\n apiKey: config.apiKey,\n })\n\n const [users, workspaceAccounts] = await Promise.all([\n client.listUsers(),\n client.listAccounts(),\n ])\n\n // Fetch fresh on-chain state via `resolveConstellation` for every\n // account we can resolve:\n // - `spec` present → pass the stored apply-time node verbatim\n // (deployed nodes match on-chain; undeployed ones derive via\n // CREATE2 from the stored nonce + config).\n // - `vault: true` with no spec → treat as a pre-existing on-chain\n // SAFE (e.g. a workspace vault created outside the\n // constellation-as-code flow). The resolver finds it on-chain.\n // - `vault: false` with no spec → a constituent of a still-pending\n // constellation that's never been deployed. We can't usefully\n // resolve it, so skip; the codegen emits minimal fields.\n const allAccounts = workspaceAccounts.flatMap((ws) => ws.accounts)\n const resolvableAccounts = allAccounts.filter(\n (a) => a.spec != null || a.vault\n )\n const resolved = new Map<\n string,\n Awaited<ReturnType<typeof client.resolveConstellation>>['result'][number]\n >()\n if (resolvableAccounts.length > 0) {\n const response = await client.resolveConstellation(\n workspaceAccounts[0].workspaceId, // any workspace works for the resolve route\n {\n specification: resolvableAccounts.map((account, i) =>\n account.spec != null\n ? account.spec\n : {\n // Synthesize a ref for vault-fallback entries (no stored\n // spec). The /resolve payload requires a ref on every\n // entry; the value isn't used downstream beyond echoing\n // back into the response, so a positional id is fine.\n ref: `vault_${i}` as Lowercase<string>,\n type: 'SAFE',\n chain: account.chain,\n address: account.address,\n }\n ),\n }\n )\n invariant(\n response?.result?.length === resolvableAccounts.length,\n `resolveConstellation returned ${response?.result?.length ?? 0} accounts for ${resolvableAccounts.length} accounts`\n )\n resolvableAccounts.forEach((account, i) => {\n resolved.set(account.id, response.result[i])\n })\n }\n\n // Group accounts by type into separate bracket-access namespaces:\n // `safes`, `rolesMods`, `delays`. This way `eth.safe[...]`\n // IntelliSense only suggests SAFE labels, and the label-collision\n // suffix only kicks in when two accounts **of the same type** share\n // a label.\n const accountsRecord: Record<string, unknown> = {}\n for (const ws of workspaceAccounts) {\n const safes: Record<string, unknown> = {}\n const rolesMods: Record<string, unknown> = {}\n const delays: Record<string, unknown> = {}\n\n const bucketsByType = {\n SAFE: safes,\n ROLES: rolesMods,\n DELAY: delays,\n } as const\n\n type NodeType = 'SAFE' | 'ROLES' | 'DELAY'\n const isNodeType = (type: string): type is NodeType =>\n type === 'SAFE' || type === 'ROLES' || type === 'DELAY'\n\n // Count labels per type so we only suffix within-type collisions.\n const labelCountByType: Record<NodeType, Map<string, number>> = {\n SAFE: new Map(),\n ROLES: new Map(),\n DELAY: new Map(),\n }\n for (const account of ws.accounts) {\n if (!isNodeType(account.type)) continue\n const counts = labelCountByType[account.type]\n counts.set(account.label, (counts.get(account.label) ?? 0) + 1)\n }\n\n for (const account of ws.accounts) {\n if (!isNodeType(account.type)) continue\n const onChain = resolved.get(account.id)\n const counts = labelCountByType[account.type]\n const key =\n (counts.get(account.label) ?? 0) > 1\n ? `${account.label} (${getAddress(account.address)})`\n : account.label\n bucketsByType[account.type][key] = {\n id: account.id,\n label: account.label,\n address: account.address,\n chain: account.chain,\n vault: account.vault,\n ...(onChain?.type === 'SAFE' && {\n threshold: onChain.threshold,\n owners: [...onChain.owners],\n modules: [...onChain.modules],\n }),\n }\n }\n\n accountsRecord[ws.workspaceName] = {\n workspaceId: ws.workspaceId,\n workspaceName: ws.workspaceName,\n safes,\n rolesMods,\n delays,\n }\n }\n\n const nameCount = new Map<string, number>()\n for (const user of users) {\n nameCount.set(user.fullName, (nameCount.get(user.fullName) ?? 0) + 1)\n }\n\n const usersRecord: Record<string, unknown> = {}\n for (const user of users) {\n const handle =\n nameCount.get(user.fullName)! > 1\n ? `${user.fullName} (${user.id})`\n : user.fullName\n usersRecord[handle] = {\n id: user.id,\n fullName: user.fullName,\n personalSafes: user.personalSafes,\n }\n }\n\n const outDir = resolveZodiacDir(config.rootDir)\n\n mkdirSync(outDir, { recursive: true })\n\n // Pin CJS so `require()` works regardless of the parent package.json's type\n writeFileSync(\n join(outDir, 'package.json'),\n JSON.stringify(\n {\n type: 'commonjs',\n main: 'index.js',\n types: 'index.d.ts',\n },\n null,\n 2\n )\n )\n\n // Use ts-morph to generate TS, then emit JS + d.ts\n const project = new Project({\n compilerOptions: {\n declaration: true,\n module: ModuleKind.CommonJS,\n target: ScriptTarget.ESNext,\n outDir,\n },\n useInMemoryFileSystem: true,\n })\n\n const sourceFile = project.createSourceFile('index.ts', '')\n\n sourceFile.addVariableStatement({\n isExported: true,\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: 'users',\n initializer: `${toLiteral(usersRecord)} as const`,\n },\n ],\n })\n\n sourceFile.addVariableStatement({\n isExported: true,\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: 'accounts',\n initializer: `${toLiteral(accountsRecord)} as const`,\n },\n ],\n })\n\n const emitResult = sourceFile.getEmitOutput()\n for (const outputFile of emitResult.getOutputFiles()) {\n const filePath = outputFile.getFilePath()\n const fileName = filePath.includes('.d.ts') ? 'index.d.ts' : 'index.js'\n let contents = outputFile.getText()\n // Augment the SDK's global `ZodiacGeneratedCodegen` interface so\n // `constellation()`'s default type parameter picks up these literal\n // shapes automatically.\n if (fileName === 'index.d.ts') {\n contents += `\ndeclare global {\n interface ZodiacGeneratedCodegen {\n users: typeof users;\n accounts: typeof accounts;\n }\n}\n`\n }\n writeFileSync(join(outDir, fileName), contents)\n }\n}\n","import { chainIdFor, type ChainPrefix } from './networks'\n\nexport type AbiFragment = Record<string, any>\nexport type Abi = AbiFragment[]\n\n// Returns null on any failure so callers can fall back to a manual ABI file.\nexport async function fetchAbi(\n chainId: number,\n address: `0x${string}`\n): Promise<Abi | null> {\n const url = `https://api.abi.pub/v1/chains/${chainId}/etherscan?module=contract&action=getabi&address=${address}`\n let body: { status?: string; message?: string; result?: string }\n try {\n const resp = await fetch(url)\n if (!resp.ok) return null\n body = (await resp.json()) as typeof body\n } catch {\n return null\n }\n if (body.status !== '1' || typeof body.result !== 'string') return null\n try {\n const parsed = JSON.parse(body.result)\n if (!Array.isArray(parsed) || parsed.length === 0) return null\n return parsed as Abi\n } catch {\n return null\n }\n}\n\nexport const fetchAbiForPrefix = (\n prefix: ChainPrefix,\n address: `0x${string}`\n) => fetchAbi(chainIdFor(prefix), address)\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { walkContracts, readAbi, type ContractNode } from './abi'\nimport type { Abi, AbiFragment } from './fetch'\n\n// Emits named tuple elements per ABI input — this is the reason we don't rely\n// on viem/abitype, which produces unnamed tuples (microsoft/TypeScript#44939).\nexport function generateAllowTypes(\n abisDir: string,\n contractsConfig: Record<string, any>\n): string {\n type Tree = Map<string, Tree | { node: ContractNode; abi: Abi }>\n\n const root: Tree = new Map()\n for (const node of walkContracts(contractsConfig)) {\n const abi = readAbi(abisDir, node)\n if (!abi) continue\n insertIntoTree(root, [node.chain, ...node.segments], { node, abi })\n }\n\n const out: string[] = []\n out.push('// AUTO-GENERATED by `zodiac pull-contracts`. Do not edit.')\n out.push('/* eslint-disable */')\n out.push('')\n out.push(\n `import type { FunctionPermission, TargetPermission } from \"zodiac-roles-sdk\";`\n )\n out.push(\n `import type { Scoping, Options, EVERYTHING } from \"@zodiac-os/sdk/allow\";`\n )\n out.push('')\n out.push('declare global {')\n out.push(' interface AllowKit ' + renderTree(root, ' '))\n out.push('}')\n out.push('')\n out.push('export {};')\n out.push('')\n return out.join('\\n')\n}\n\nfunction insertIntoTree(\n tree: Map<string, any>,\n segments: string[],\n leaf: { node: ContractNode; abi: Abi }\n): void {\n const [first, ...rest] = segments\n if (!first) throw new Error('empty segments')\n if (rest.length === 0) {\n tree.set(first, leaf)\n return\n }\n let child = tree.get(first)\n if (!child || child.node) {\n child = new Map()\n tree.set(first, child)\n }\n insertIntoTree(child, rest, leaf)\n}\n\nfunction renderTree(tree: Map<string, any>, indent: string): string {\n const lines: string[] = ['{']\n for (const [key, value] of tree) {\n const safeKey = renderPropKey(key)\n if (value instanceof Map) {\n lines.push(`${indent} ${safeKey}: ${renderTree(value, indent + ' ')};`)\n } else {\n const { node, abi } = value as { node: ContractNode; abi: Abi }\n lines.push(\n `${indent} ${safeKey}: ${renderContractType(node, abi, indent + ' ')};`\n )\n }\n }\n lines.push(`${indent}}`)\n return lines.join('\\n')\n}\n\nfunction renderPropKey(name: string): string {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name)\n}\n\nfunction renderContractType(\n node: ContractNode,\n abi: Abi,\n indent: string\n): string {\n const members: string[] = []\n const seen = new Set<string>()\n members.push(\n `${indent} [EVERYTHING]: (options?: Options) => TargetPermission;`\n )\n for (const fragment of abi) {\n if (fragment.type !== 'function') continue\n if (\n fragment.stateMutability === 'view' ||\n fragment.stateMutability === 'pure'\n ) {\n continue\n }\n const name = fragment.name as string\n if (!name || seen.has(name)) continue\n seen.add(name)\n members.push(renderFunctionSignature(fragment, indent + ' '))\n }\n return ['{', ...members, `${indent}}`].join('\\n')\n}\n\nfunction renderFunctionSignature(\n fragment: AbiFragment,\n indent: string\n): string {\n const name = renderPropKey(fragment.name as string)\n const params: string[] = []\n for (const input of (fragment.inputs as AbiFragment[]) ?? []) {\n const paramName = sanitizeParamName(\n input.name || `arg${params.length}`,\n params.length\n )\n params.push(`${paramName}?: Scoping<${tsTypeFor(input)}>`)\n }\n params.push(`options?: Options`)\n return `${indent}${name}: (${params.join(', ')}) => FunctionPermission;`\n}\n\nfunction sanitizeParamName(name: string, index: number): string {\n const cleaned = name.replace(/[^A-Za-z0-9_$]/g, '_')\n if (!cleaned || /^[0-9]/.test(cleaned)) return `arg${index}`\n // Named tuple element labels can't collide with TS reserved words.\n const reserved = new Set([\n 'function',\n 'class',\n 'new',\n 'number',\n 'string',\n 'object',\n 'boolean',\n 'symbol',\n 'default',\n 'return',\n 'this',\n 'void',\n 'delete',\n 'in',\n 'of',\n 'for',\n 'while',\n 'switch',\n 'case',\n 'if',\n 'else',\n 'null',\n 'true',\n 'false',\n 'undefined',\n 'any',\n 'never',\n 'unknown',\n ])\n return reserved.has(cleaned) ? `_${cleaned}` : cleaned\n}\n\nfunction tsTypeFor(fragment: AbiFragment): string {\n const type = fragment.type as string\n\n const arrayMatch = /^(.*)\\[(\\d*)\\]$/.exec(type)\n if (arrayMatch) {\n const inner: AbiFragment = { ...fragment, type: arrayMatch[1] }\n return `readonly (${tsTypeFor(inner)})[]`\n }\n\n if (type === 'tuple') {\n const components = (fragment.components as AbiFragment[]) ?? []\n if (components.length === 0) return 'Record<string, unknown>'\n const fields = components.map((c, i) => {\n const key = sanitizeParamName(c.name || `f${i}`, i)\n return `${renderPropKey(key)}: ${tsTypeFor(c)}`\n })\n return `{ ${fields.join('; ')} }`\n }\n\n if (type === 'address') return '`0x${string}`'\n if (type === 'bool') return 'boolean'\n if (type === 'string') return 'string'\n if (type === 'bytes') return 'import(\"ethers\").BytesLike'\n if (/^bytes\\d+$/.test(type)) return '`0x${string}`'\n if (/^u?int\\d*$/.test(type)) return 'import(\"ethers\").BigNumberish'\n return 'unknown'\n}\n\nexport function writeGenerated(outFile: string, source: string): void {\n fs.mkdirSync(path.dirname(outFile), { recursive: true })\n fs.writeFileSync(outFile, source, 'utf8')\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport type { ResolvedConfig } from '../config'\nimport { resolveAbisDir } from '../config'\nimport { resolveZodiacDir } from '../../paths'\nimport { abiFilePath, walkContracts, writeAbi } from '../../allow/abi'\nimport { fetchAbi } from '../../allow/fetch'\nimport { chainIdFor } from '../../allow/networks'\nimport { generateAllowTypes, writeGenerated } from '../../allow/codegen'\n\ntype Status = 'ok' | 'fetched' | 'missing'\n\nexport const pullContracts = async (config: ResolvedConfig) => {\n if (!config.contracts || Object.keys(config.contracts).length === 0) {\n console.log('No contracts defined in config, skipping.')\n return\n }\n\n const abisDir = resolveAbisDir(config)\n const generatedFile = path.join(\n resolveZodiacDir(config.rootDir),\n 'allow.d.ts'\n )\n\n let missing = 0\n let fetched = 0\n let existing = 0\n\n for (const node of walkContracts(config.contracts)) {\n const file = abiFilePath(abisDir, node)\n\n if (fs.existsSync(file)) {\n existing++\n report(node.chain, node.segments, node.address, 'ok', file)\n continue\n }\n\n let chainId: number\n try {\n chainId = chainIdFor(node.chain)\n } catch (error) {\n missing++\n report(\n node.chain,\n node.segments,\n node.address,\n 'missing',\n file,\n (error as Error).message\n )\n continue\n }\n\n const abi = await fetchAbi(chainId, node.address)\n if (!abi) {\n missing++\n report(\n node.chain,\n node.segments,\n node.address,\n 'missing',\n file,\n `api.abi.pub returned no ABI for chain ${chainId}`\n )\n continue\n }\n writeAbi(abisDir, node, abi)\n fetched++\n report(node.chain, node.segments, node.address, 'fetched', file)\n }\n\n console.log('')\n console.log(\n `Contracts summary: ${existing} existing, ${fetched} fetched, ${missing} missing.`\n )\n if (missing > 0) {\n console.log('')\n console.log('Missing ABIs must be provided manually. Paste the contract')\n console.log(\n 'ABI JSON at the paths listed above and re-run `zodiac pull-contracts`.'\n )\n }\n\n const source = generateAllowTypes(abisDir, config.contracts)\n writeGenerated(generatedFile, source)\n console.log('')\n console.log(`Wrote typings to ${path.relative(process.cwd(), generatedFile)}`)\n\n if (missing > 0) process.exit(1)\n}\n\nfunction report(\n chain: string,\n segments: string[],\n address: string,\n status: Status,\n file: string,\n reason?: string\n) {\n const label = `${chain}.${segments.join('.')}`.padEnd(40, ' ')\n const tag = {\n ok: ' cached ',\n fetched: ' fetched ',\n missing: ' MISSING ',\n }[status]\n const suffix = reason ? ` — ${reason}` : ''\n console.log(`${tag} ${label} ${address}${suffix}`)\n if (status === 'missing') {\n console.log(` → paste ABI at ${file}`)\n }\n}\n","import { Command } from 'commander'\nimport { config as loadDotenv } from 'dotenv'\nimport { init } from './commands/init'\nimport { loadConfig } from './config'\nimport { pullOrg } from './commands/pullOrg'\nimport { pullContracts } from './commands/pullContracts'\n\n// Load `.env` from the current working directory before reading any env vars.\nloadDotenv({ quiet: true })\n\nconst loadConfigOrInit = (configPath: string) =>\n loadConfig(configPath, {\n onMissingKey: async (rootDir) => {\n console.log(\n 'No ZODIAC_API_KEY found. Starting authorization to mint one for this directory…'\n )\n return init({ rootDir })\n },\n })\n\nexport const run = async (argv: string[] = process.argv) => {\n const program = new Command()\n\n program\n .name('zodiac')\n .description('Zodiac SDK CLI – pull org data and contract ABIs')\n .version('1.0.0')\n .option(\n '-c, --config <path>',\n 'path to the config file',\n 'zodiac.config.ts'\n )\n\n program\n .command('init')\n .description(\n 'Authorize this directory with a Zodiac org. Opens a browser to mint an API key and writes it to .env.'\n )\n .option(\n '--app-url <url>',\n 'Override the Zodiac app URL (defaults to ZODIAC_APP_URL or app.zodiac.eco)'\n )\n .action(async (opts) => {\n await init({ appUrl: opts.appUrl })\n })\n\n program\n .command('pull-org')\n .description('Fetch Zodiac users and accounts, generate TypeScript types')\n .action(async (_opts, cmd) => {\n const config = await loadConfigOrInit(cmd.optsWithGlobals().config)\n await pullOrg(config)\n })\n\n program\n .command('pull-contracts')\n .description('Fetch contract ABIs, generate typed permissions kit')\n .action(async (_opts, cmd) => {\n const config = await loadConfigOrInit(cmd.optsWithGlobals().config)\n await pullContracts(config)\n })\n\n program\n .command('pull')\n .description('Fetch Zodiac org and contracts ABI, generate SDK functions')\n .action(async (_opts, cmd) => {\n const config = await loadConfigOrInit(cmd.optsWithGlobals().config)\n await Promise.all([pullOrg(config), pullContracts(config)])\n })\n\n await program.parseAsync(argv)\n}\n","#!/usr/bin/env node\nimport { run } from './run'\n\nrun().then(\n () => {\n process.exit(0)\n },\n (error: unknown) => {\n if (error) console.error(error)\n process.exit(1)\n }\n)\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":["join","loadDotenv"],"sources":["../src/cli/commands/init.ts","../src/cli/commands/pullOrg.ts","../src/allow/fetch.ts","../src/allow/codegen.ts","../src/cli/commands/pullContracts.ts","../src/cli/run.ts","../src/cli/index.ts"],"sourcesContent":["import { createHash, randomBytes } from 'node:crypto'\nimport {\n createServer,\n type IncomingMessage,\n type ServerResponse,\n} from 'node:http'\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { basename, join, resolve } from 'node:path'\nimport open from 'open'\n\nconst DEFAULT_APP_URL = 'https://app.zodiac.eco'\nconst CALLBACK_TIMEOUT_MS = 5 * 60 * 1000 // 5 minutes\n\ntype InitOptions = {\n rootDir?: string\n /** Override the Zodiac app base URL (defaults to ZODIAC_APP_URL env or app.zodiac.eco). */\n appUrl?: string\n}\n\nexport const init = async (options: InitOptions = {}): Promise<string> => {\n const rootDir = options.rootDir ?? process.cwd()\n const appUrl = (\n options.appUrl ??\n process.env.ZODIAC_APP_URL ??\n DEFAULT_APP_URL\n ).replace(/\\/$/, '')\n\n const label = basename(resolve(rootDir)) || 'zodiac-cli'\n\n // PKCE: keep `code_verifier` private to this process. Send only the\n // SHA-256 hash (`code_challenge`) over the wire.\n const codeVerifier = randomBytes(32).toString('base64url')\n const codeChallenge = createHash('sha256')\n .update(codeVerifier)\n .digest('base64url')\n\n // `state` binds the redirect we receive on the loopback to this CLI\n // invocation, defending against a stray local process trying to inject\n // an auth code into our callback.\n const state = randomBytes(32).toString('base64url')\n\n const { port, waitForCode, close } = await startCallbackServer({\n expectedState: state,\n appUrl,\n })\n\n const callbackUrl = `http://127.0.0.1:${port}/callback`\n const authUrl = new URL('/cli-auth', appUrl)\n authUrl.searchParams.set('callback', callbackUrl)\n authUrl.searchParams.set('state', state)\n authUrl.searchParams.set('code_challenge', codeChallenge)\n authUrl.searchParams.set('label', label)\n\n console.log(\n `Opening ${authUrl} in your browser. Approve the request to receive an API key.`\n )\n await open(authUrl.toString())\n\n let code: string\n try {\n code = await waitForCode(CALLBACK_TIMEOUT_MS)\n } finally {\n await close()\n }\n\n const apiKey = await exchangeCodeForKey(appUrl, code, codeVerifier)\n\n const envPath = join(rootDir, '.env')\n const apiUrl = `${appUrl}/api/v1`\n writeEnv(envPath, { ZODIAC_API_KEY: apiKey, ZODIAC_API_URL: apiUrl })\n\n console.log(`✅ API key written to ${envPath}`)\n\n return apiKey\n}\n\nconst exchangeCodeForKey = async (\n appUrl: string,\n code: string,\n codeVerifier: string\n): Promise<string> => {\n const response = await fetch(`${appUrl}/cli-auth/exchange`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ code, code_verifier: codeVerifier }),\n })\n\n if (!response.ok) {\n let detail = ''\n try {\n const body = (await response.json()) as { error?: string }\n detail = body.error ? `: ${body.error}` : ''\n } catch {\n // ignore — fall through to a generic message\n }\n throw new Error(\n `Failed to exchange auth code (${response.status})${detail}`\n )\n }\n\n const { key } = (await response.json()) as { key: unknown }\n if (typeof key !== 'string' || !key.startsWith('zodiac_')) {\n throw new Error(\n 'Exchange endpoint returned an unexpected response (missing or malformed key)'\n )\n }\n return key\n}\n\ntype StartServerOptions = {\n expectedState: string\n appUrl: string\n}\n\ntype StartServerResult = {\n port: number\n waitForCode: (timeoutMs: number) => Promise<string>\n close: () => Promise<void>\n}\n\nconst startCallbackServer = async ({\n expectedState,\n appUrl,\n}: StartServerOptions): Promise<StartServerResult> => {\n let resolveCode: (code: string) => void = () => {}\n let rejectCode: (err: Error) => void = () => {}\n const codePromise = new Promise<string>((res, rej) => {\n resolveCode = res\n rejectCode = rej\n })\n\n const handler = (req: IncomingMessage, res: ServerResponse) => {\n if (req.method !== 'GET' || !req.url?.startsWith('/callback')) {\n res.statusCode = 404\n res.end()\n return\n }\n\n const url = new URL(req.url, `http://127.0.0.1`)\n const code = url.searchParams.get('code')\n const state = url.searchParams.get('state')\n\n if (state !== expectedState) {\n // A stray request — could be a stale browser tab, a malicious\n // local process, etc. Silently 403 and keep waiting for the right\n // one. Don't reject the CLI promise.\n respondHtml(\n res,\n 403,\n renderHtml(\n 'Mismatched state',\n `<p>This callback didn't match the running <code>zodiac init</code> session. You can close this tab.</p>`\n )\n )\n return\n }\n\n if (typeof code !== 'string' || code.length === 0) {\n respondHtml(\n res,\n 400,\n renderHtml(\n 'Missing code',\n `<p>The callback URL didn't include an auth <code>code</code>. Please re-run <code>zodiac init</code>.</p>`\n )\n )\n return\n }\n\n respondHtml(\n res,\n 200,\n renderHtml(\n 'Authorized',\n `<p>Your CLI now has its API key. You can close this tab and return to your terminal.</p>\n <p><a href=\"${escapeHtml(appUrl)}\">Back to Zodiac</a></p>`\n )\n )\n resolveCode(code)\n }\n\n const server = createServer(handler)\n await new Promise<void>((res) => server.listen(0, '127.0.0.1', res))\n const address = server.address()\n if (address == null || typeof address === 'string') {\n throw new Error('Failed to bind loopback callback server')\n }\n const port = address.port\n\n const close = (): Promise<void> =>\n new Promise<void>((resolve) => {\n server.close(() => resolve())\n })\n\n const waitForCode = (timeoutMs: number) =>\n Promise.race<string>([\n codePromise,\n new Promise<string>((_, rej) =>\n setTimeout(() => {\n rejectCode(new Error(`Timed out waiting for CLI auth callback`))\n rej(new Error(`Timed out waiting for CLI auth callback`))\n }, timeoutMs)\n ),\n ])\n\n return { port, waitForCode, close }\n}\n\nconst respondHtml = (res: ServerResponse, status: number, body: string) => {\n // Force the connection to close after the response so the browser\n // doesn't keep waiting on a keep-alive socket once the CLI exits.\n // Resolve only after 'finish' (response handed to the OS) so the\n // bytes can flush before the process tears down.\n res.setHeader('Connection', 'close')\n res.setHeader('content-type', 'text/html; charset=utf-8')\n res.statusCode = status\n res.end(body)\n}\n\nconst renderHtml = (title: string, bodyHtml: string) => `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>${escapeHtml(title)} — Zodiac CLI</title>\n <style>\n body { font: 16px/1.5 -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; max-width: 32rem; margin: 4rem auto; padding: 0 1rem; color: #1f2937; }\n h1 { font-weight: 300; font-size: 1.75rem; margin-bottom: 1rem; }\n code { background: #f3f4f6; padding: 0.125rem 0.375rem; border-radius: 0.25rem; }\n a { color: #1d4ed8; }\n </style>\n </head>\n <body>\n <h1>${escapeHtml(title)}</h1>\n ${bodyHtml}\n </body>\n</html>\n`\n\nconst escapeHtml = (value: string) =>\n value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n\nconst writeEnv = (envPath: string, vars: Record<string, string>): void => {\n let contents = existsSync(envPath) ? readFileSync(envPath, 'utf8') : ''\n\n for (const [key, value] of Object.entries(vars)) {\n contents = upsertEnvLine(contents, key, value)\n }\n\n writeFileSync(envPath, contents, 'utf8')\n}\n\nconst upsertEnvLine = (\n contents: string,\n key: string,\n value: string\n): string => {\n const line = `${key}=${value}`\n const lines = contents.split(/\\r?\\n/)\n const idx = lines.findIndex((l) => new RegExp(`^\\\\s*${key}\\\\s*=`).test(l))\n\n if (idx >= 0) {\n lines[idx] = line\n return lines.join('\\n')\n }\n\n return contents.length === 0 || contents.endsWith('\\n')\n ? `${contents}${line}\\n`\n : `${contents}\\n${line}\\n`\n}\n","import type { ResolvedConfig } from '../config'\nimport { ApiClient } from '../../api'\nimport { invariant } from '@epic-web/invariant'\nimport { getAddress } from 'ethers'\nimport {\n ModuleKind,\n Project,\n ScriptTarget,\n VariableDeclarationKind,\n} from 'ts-morph'\nimport { mkdirSync, writeFileSync } from 'fs'\nimport { join } from 'path'\nimport { resolveZodiacDir } from '../../paths'\n\nconst toLiteral = (value: unknown, indent = 0): string => {\n const pad = ' '.repeat(indent)\n const childPad = ' '.repeat(indent + 1)\n\n if (value === null) return 'null'\n if (typeof value === 'bigint') return `${value}n`\n if (typeof value === 'string') return JSON.stringify(value)\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value)\n if (Array.isArray(value)) {\n if (value.length === 0) return '[]'\n return `[\\n${value.map((v) => `${childPad}${toLiteral(v, indent + 1)}`).join(',\\n')},\\n${pad}]`\n }\n if (typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>)\n if (entries.length === 0) return '{}'\n const props = entries.map(\n ([k, v]) =>\n `${childPad}${/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k) ? k : JSON.stringify(k)}: ${toLiteral(v, indent + 1)}`\n )\n return `{\\n${props.join(',\\n')},\\n${pad}}`\n }\n return String(value)\n}\n\nexport const pullOrg = async (config: ResolvedConfig) => {\n const client = new ApiClient({\n apiKey: config.apiKey,\n })\n\n const [users, workspaceAccounts] = await Promise.all([\n client.listUsers(),\n client.listAccounts(),\n ])\n\n // Fetch fresh on-chain state via `resolveConstellation` for every\n // account we can resolve:\n // - `spec` present → pass the stored apply-time node verbatim\n // (deployed nodes match on-chain; undeployed ones derive via\n // CREATE2 from the stored nonce + config).\n // - `vault: true` with no spec → treat as a pre-existing on-chain\n // SAFE (e.g. a workspace vault created outside the\n // constellation-as-code flow). The resolver finds it on-chain.\n // - `vault: false` with no spec → a constituent of a still-pending\n // constellation that's never been deployed. We can't usefully\n // resolve it, so skip; the codegen emits minimal fields.\n const allAccounts = workspaceAccounts.flatMap((ws) => ws.accounts)\n const resolvableAccounts = allAccounts.filter(\n (a) => a.spec != null || a.vault\n )\n const resolved = new Map<\n string,\n Awaited<ReturnType<typeof client.resolveConstellation>>['result'][number]\n >()\n if (resolvableAccounts.length > 0) {\n const response = await client.resolveConstellation(\n workspaceAccounts[0].workspaceId, // any workspace works for the resolve route\n {\n specification: resolvableAccounts.map((account, i) =>\n account.spec != null\n ? account.spec\n : {\n // Synthesize a ref for vault-fallback entries (no stored\n // spec). The /resolve payload requires a ref on every\n // entry; the value isn't used downstream beyond echoing\n // back into the response, so a positional id is fine.\n ref: `vault_${i}` as Lowercase<string>,\n type: 'SAFE',\n chain: account.chain,\n address: account.address,\n }\n ),\n }\n )\n invariant(\n response?.result?.length === resolvableAccounts.length,\n `resolveConstellation returned ${response?.result?.length ?? 0} accounts for ${resolvableAccounts.length} accounts`\n )\n resolvableAccounts.forEach((account, i) => {\n resolved.set(account.id, response.result[i])\n })\n }\n\n // Group accounts by type into separate bracket-access namespaces:\n // `safes`, `rolesMods`, `delays`. This way `eth.safe[...]`\n // IntelliSense only suggests SAFE labels, and the label-collision\n // suffix only kicks in when two accounts **of the same type** share\n // a label.\n const accountsRecord: Record<string, unknown> = {}\n for (const ws of workspaceAccounts) {\n const safes: Record<string, unknown> = {}\n const rolesMods: Record<string, unknown> = {}\n const delays: Record<string, unknown> = {}\n\n const bucketsByType = {\n SAFE: safes,\n ROLES: rolesMods,\n DELAY: delays,\n } as const\n\n type NodeType = 'SAFE' | 'ROLES' | 'DELAY'\n const isNodeType = (type: string): type is NodeType =>\n type === 'SAFE' || type === 'ROLES' || type === 'DELAY'\n\n // Count labels per type so we only suffix within-type collisions.\n const labelCountByType: Record<NodeType, Map<string, number>> = {\n SAFE: new Map(),\n ROLES: new Map(),\n DELAY: new Map(),\n }\n for (const account of ws.accounts) {\n if (!isNodeType(account.type)) continue\n const counts = labelCountByType[account.type]\n counts.set(account.label, (counts.get(account.label) ?? 0) + 1)\n }\n\n for (const account of ws.accounts) {\n if (!isNodeType(account.type)) continue\n const onChain = resolved.get(account.id)\n const counts = labelCountByType[account.type]\n const key =\n (counts.get(account.label) ?? 0) > 1\n ? `${account.label} (${getAddress(account.address)})`\n : account.label\n bucketsByType[account.type][key] = {\n id: account.id,\n label: account.label,\n address: account.address,\n chain: account.chain,\n vault: account.vault,\n ...(onChain?.type === 'SAFE' && {\n threshold: onChain.threshold,\n owners: [...onChain.owners],\n modules: [...onChain.modules],\n }),\n }\n }\n\n accountsRecord[ws.workspaceName] = {\n workspaceId: ws.workspaceId,\n workspaceName: ws.workspaceName,\n safes,\n rolesMods,\n delays,\n }\n }\n\n const nameCount = new Map<string, number>()\n for (const user of users) {\n nameCount.set(user.fullName, (nameCount.get(user.fullName) ?? 0) + 1)\n }\n\n const usersRecord: Record<string, unknown> = {}\n for (const user of users) {\n const handle =\n nameCount.get(user.fullName)! > 1\n ? `${user.fullName} (${user.id})`\n : user.fullName\n usersRecord[handle] = {\n id: user.id,\n fullName: user.fullName,\n personalSafes: user.personalSafes,\n }\n }\n\n const outDir = resolveZodiacDir(config.rootDir)\n\n mkdirSync(outDir, { recursive: true })\n\n // Pin CJS so `require()` works regardless of the parent package.json's type\n writeFileSync(\n join(outDir, 'package.json'),\n JSON.stringify(\n {\n type: 'commonjs',\n main: 'index.js',\n types: 'index.d.ts',\n },\n null,\n 2\n )\n )\n\n // Use ts-morph to generate TS, then emit JS + d.ts\n const project = new Project({\n compilerOptions: {\n declaration: true,\n module: ModuleKind.CommonJS,\n target: ScriptTarget.ESNext,\n outDir,\n },\n useInMemoryFileSystem: true,\n })\n\n const sourceFile = project.createSourceFile('index.ts', '')\n\n sourceFile.addVariableStatement({\n isExported: true,\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: 'users',\n initializer: `${toLiteral(usersRecord)} as const`,\n },\n ],\n })\n\n sourceFile.addVariableStatement({\n isExported: true,\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: 'accounts',\n initializer: `${toLiteral(accountsRecord)} as const`,\n },\n ],\n })\n\n const emitResult = sourceFile.getEmitOutput()\n for (const outputFile of emitResult.getOutputFiles()) {\n const filePath = outputFile.getFilePath()\n const fileName = filePath.includes('.d.ts') ? 'index.d.ts' : 'index.js'\n let contents = outputFile.getText()\n // Augment the SDK's global `ZodiacGeneratedCodegen` interface so\n // `constellation()`'s default type parameter picks up these literal\n // shapes automatically.\n if (fileName === 'index.d.ts') {\n contents += `\ndeclare global {\n interface ZodiacGeneratedCodegen {\n users: typeof users;\n accounts: typeof accounts;\n }\n}\n`\n }\n writeFileSync(join(outDir, fileName), contents)\n }\n}\n","import { chainIdFor, type ChainPrefix } from './networks'\n\nexport type AbiFragment = Record<string, any>\nexport type Abi = AbiFragment[]\n\n// Returns null on any failure so callers can fall back to a manual ABI file.\nexport async function fetchAbi(\n chainId: number,\n address: `0x${string}`\n): Promise<Abi | null> {\n const url = `https://api.abi.pub/v1/chains/${chainId}/etherscan?module=contract&action=getabi&address=${address}`\n let body: { status?: string; message?: string; result?: string }\n try {\n const resp = await fetch(url)\n if (!resp.ok) return null\n body = (await resp.json()) as typeof body\n } catch {\n return null\n }\n if (body.status !== '1' || typeof body.result !== 'string') return null\n try {\n const parsed = JSON.parse(body.result)\n if (!Array.isArray(parsed) || parsed.length === 0) return null\n return parsed as Abi\n } catch {\n return null\n }\n}\n\nexport const fetchAbiForPrefix = (\n prefix: ChainPrefix,\n address: `0x${string}`\n) => fetchAbi(chainIdFor(prefix), address)\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { walkContracts, readAbi, type ContractNode } from './abi'\nimport type { Abi, AbiFragment } from './fetch'\n\n// Emits named tuple elements per ABI input — this is the reason we don't rely\n// on viem/abitype, which produces unnamed tuples (microsoft/TypeScript#44939).\nexport function generateAllowTypes(\n abisDir: string,\n contractsConfig: Record<string, any>\n): string {\n type Tree = Map<string, Tree | { node: ContractNode; abi: Abi }>\n\n const root: Tree = new Map()\n for (const node of walkContracts(contractsConfig)) {\n const abi = readAbi(abisDir, node)\n if (!abi) continue\n insertIntoTree(root, [node.chain, ...node.segments], { node, abi })\n }\n\n const out: string[] = []\n out.push('// AUTO-GENERATED by `zodiac pull-contracts`. Do not edit.')\n out.push('/* eslint-disable */')\n out.push('')\n out.push(\n `import type { FunctionPermission, TargetPermission } from \"zodiac-roles-sdk\";`\n )\n out.push(\n `import type { Scoping, Options, EVERYTHING } from \"@zodiac-os/sdk/allow\";`\n )\n out.push('')\n out.push('declare global {')\n out.push(' interface AllowKit ' + renderTree(root, ' '))\n out.push('}')\n out.push('')\n out.push('export {};')\n out.push('')\n return out.join('\\n')\n}\n\nfunction insertIntoTree(\n tree: Map<string, any>,\n segments: string[],\n leaf: { node: ContractNode; abi: Abi }\n): void {\n const [first, ...rest] = segments\n if (!first) throw new Error('empty segments')\n if (rest.length === 0) {\n tree.set(first, leaf)\n return\n }\n let child = tree.get(first)\n if (!child || child.node) {\n child = new Map()\n tree.set(first, child)\n }\n insertIntoTree(child, rest, leaf)\n}\n\nfunction renderTree(tree: Map<string, any>, indent: string): string {\n const lines: string[] = ['{']\n for (const [key, value] of tree) {\n const safeKey = renderPropKey(key)\n if (value instanceof Map) {\n lines.push(`${indent} ${safeKey}: ${renderTree(value, indent + ' ')};`)\n } else {\n const { node, abi } = value as { node: ContractNode; abi: Abi }\n lines.push(\n `${indent} ${safeKey}: ${renderContractType(node, abi, indent + ' ')};`\n )\n }\n }\n lines.push(`${indent}}`)\n return lines.join('\\n')\n}\n\nfunction renderPropKey(name: string): string {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name)\n}\n\nfunction renderContractType(\n node: ContractNode,\n abi: Abi,\n indent: string\n): string {\n const members: string[] = []\n const seen = new Set<string>()\n members.push(\n `${indent} [EVERYTHING]: (options?: Options) => TargetPermission;`\n )\n for (const fragment of abi) {\n if (fragment.type !== 'function') continue\n if (\n fragment.stateMutability === 'view' ||\n fragment.stateMutability === 'pure'\n ) {\n continue\n }\n const name = fragment.name as string\n if (!name || seen.has(name)) continue\n seen.add(name)\n members.push(renderFunctionSignature(fragment, indent + ' '))\n }\n return ['{', ...members, `${indent}}`].join('\\n')\n}\n\nfunction renderFunctionSignature(\n fragment: AbiFragment,\n indent: string\n): string {\n const name = renderPropKey(fragment.name as string)\n const params: string[] = []\n for (const input of (fragment.inputs as AbiFragment[]) ?? []) {\n const paramName = sanitizeParamName(\n input.name || `arg${params.length}`,\n params.length\n )\n params.push(`${paramName}?: Scoping<${tsTypeFor(input)}>`)\n }\n params.push(`options?: Options`)\n return `${indent}${name}: (${params.join(', ')}) => FunctionPermission;`\n}\n\nfunction sanitizeParamName(name: string, index: number): string {\n const cleaned = name.replace(/[^A-Za-z0-9_$]/g, '_')\n if (!cleaned || /^[0-9]/.test(cleaned)) return `arg${index}`\n // Named tuple element labels can't collide with TS reserved words.\n const reserved = new Set([\n 'function',\n 'class',\n 'new',\n 'number',\n 'string',\n 'object',\n 'boolean',\n 'symbol',\n 'default',\n 'return',\n 'this',\n 'void',\n 'delete',\n 'in',\n 'of',\n 'for',\n 'while',\n 'switch',\n 'case',\n 'if',\n 'else',\n 'null',\n 'true',\n 'false',\n 'undefined',\n 'any',\n 'never',\n 'unknown',\n ])\n return reserved.has(cleaned) ? `_${cleaned}` : cleaned\n}\n\nfunction tsTypeFor(fragment: AbiFragment): string {\n const type = fragment.type as string\n\n const arrayMatch = /^(.*)\\[(\\d*)\\]$/.exec(type)\n if (arrayMatch) {\n const inner: AbiFragment = { ...fragment, type: arrayMatch[1] }\n return `readonly (${tsTypeFor(inner)})[]`\n }\n\n if (type === 'tuple') {\n const components = (fragment.components as AbiFragment[]) ?? []\n if (components.length === 0) return 'Record<string, unknown>'\n const fields = components.map((c, i) => {\n const key = sanitizeParamName(c.name || `f${i}`, i)\n return `${renderPropKey(key)}: ${tsTypeFor(c)}`\n })\n return `{ ${fields.join('; ')} }`\n }\n\n if (type === 'address') return '`0x${string}`'\n if (type === 'bool') return 'boolean'\n if (type === 'string') return 'string'\n if (type === 'bytes') return 'import(\"ethers\").BytesLike'\n if (/^bytes\\d+$/.test(type)) return '`0x${string}`'\n if (/^u?int\\d*$/.test(type)) return 'import(\"ethers\").BigNumberish'\n return 'unknown'\n}\n\nexport function writeGenerated(outFile: string, source: string): void {\n fs.mkdirSync(path.dirname(outFile), { recursive: true })\n fs.writeFileSync(outFile, source, 'utf8')\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport type { ResolvedConfig } from '../config'\nimport { resolveAbisDir } from '../config'\nimport { resolveZodiacDir } from '../../paths'\nimport { abiFilePath, walkContracts, writeAbi } from '../../allow/abi'\nimport { fetchAbi } from '../../allow/fetch'\nimport { chainIdFor } from '../../allow/networks'\nimport { generateAllowTypes, writeGenerated } from '../../allow/codegen'\n\ntype Status = 'ok' | 'fetched' | 'missing'\n\nexport const pullContracts = async (config: ResolvedConfig) => {\n if (!config.contracts || Object.keys(config.contracts).length === 0) {\n console.log('No contracts defined in config, skipping.')\n return\n }\n\n const abisDir = resolveAbisDir(config)\n const generatedFile = path.join(\n resolveZodiacDir(config.rootDir),\n 'allow.d.ts'\n )\n\n let missing = 0\n let fetched = 0\n let existing = 0\n\n for (const node of walkContracts(config.contracts)) {\n const file = abiFilePath(abisDir, node)\n\n if (fs.existsSync(file)) {\n existing++\n report(node.chain, node.segments, node.address, 'ok', file)\n continue\n }\n\n let chainId: number\n try {\n chainId = chainIdFor(node.chain)\n } catch (error) {\n missing++\n report(\n node.chain,\n node.segments,\n node.address,\n 'missing',\n file,\n (error as Error).message\n )\n continue\n }\n\n const abi = await fetchAbi(chainId, node.address)\n if (!abi) {\n missing++\n report(\n node.chain,\n node.segments,\n node.address,\n 'missing',\n file,\n `api.abi.pub returned no ABI for chain ${chainId}`\n )\n continue\n }\n writeAbi(abisDir, node, abi)\n fetched++\n report(node.chain, node.segments, node.address, 'fetched', file)\n }\n\n console.log('')\n console.log(\n `Contracts summary: ${existing} existing, ${fetched} fetched, ${missing} missing.`\n )\n if (missing > 0) {\n console.log('')\n console.log('Missing ABIs must be provided manually. Paste the contract')\n console.log(\n 'ABI JSON at the paths listed above and re-run `zodiac pull-contracts`.'\n )\n }\n\n const source = generateAllowTypes(abisDir, config.contracts)\n writeGenerated(generatedFile, source)\n console.log('')\n console.log(`Wrote typings to ${path.relative(process.cwd(), generatedFile)}`)\n\n if (missing > 0) process.exit(1)\n}\n\nfunction report(\n chain: string,\n segments: string[],\n address: string,\n status: Status,\n file: string,\n reason?: string\n) {\n const label = `${chain}.${segments.join('.')}`.padEnd(40, ' ')\n const tag = {\n ok: ' cached ',\n fetched: ' fetched ',\n missing: ' MISSING ',\n }[status]\n const suffix = reason ? ` — ${reason}` : ''\n console.log(`${tag} ${label} ${address}${suffix}`)\n if (status === 'missing') {\n console.log(` → paste ABI at ${file}`)\n }\n}\n","import { Command } from 'commander'\nimport { config as loadDotenv } from 'dotenv'\nimport { init } from './commands/init'\nimport { loadConfig } from './config'\nimport { pullOrg } from './commands/pullOrg'\nimport { pullContracts } from './commands/pullContracts'\n\n// Load `.env` from the current working directory before reading any env vars.\nloadDotenv({ quiet: true })\n\nconst loadConfigOrInit = (configPath: string) =>\n loadConfig(configPath, {\n onMissingKey: async (rootDir) => {\n console.log(\n 'No ZODIAC_API_KEY found. Starting authorization to mint one for this directory…'\n )\n return init({ rootDir })\n },\n })\n\nexport const run = async (argv: string[] = process.argv) => {\n const program = new Command()\n\n program\n .name('zodiac')\n .description('Zodiac SDK CLI – pull org data and contract ABIs')\n .version('1.0.0')\n .option(\n '-c, --config <path>',\n 'path to the config file',\n 'zodiac.config.ts'\n )\n\n program\n .command('init')\n .description(\n 'Authorize this directory with a Zodiac org. Opens a browser to mint an API key and writes it to .env.'\n )\n .option(\n '--app-url <url>',\n 'Override the Zodiac app URL (defaults to ZODIAC_APP_URL or app.zodiac.eco)'\n )\n .action(async (opts) => {\n await init({ appUrl: opts.appUrl })\n })\n\n program\n .command('pull-org')\n .description('Fetch Zodiac users and accounts, generate TypeScript types')\n .action(async (_opts, cmd) => {\n const config = await loadConfigOrInit(cmd.optsWithGlobals().config)\n await pullOrg(config)\n })\n\n program\n .command('pull-contracts')\n .description('Fetch contract ABIs, generate typed permissions kit')\n .action(async (_opts, cmd) => {\n const config = await loadConfigOrInit(cmd.optsWithGlobals().config)\n await pullContracts(config)\n })\n\n program\n .command('pull')\n .description('Fetch Zodiac org and contracts ABI, generate SDK functions')\n .action(async (_opts, cmd) => {\n const config = await loadConfigOrInit(cmd.optsWithGlobals().config)\n await Promise.all([pullOrg(config), pullContracts(config)])\n })\n\n await program.parseAsync(argv)\n}\n","#!/usr/bin/env node\nimport { run } from './run'\n\nrun().then(\n () => {\n process.exit(0)\n },\n (error: unknown) => {\n if (error) console.error(error)\n process.exit(1)\n }\n)\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodiac-os/sdk",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "author": "Gnosis Guild",
5
5
  "license": "LGPL-3.0-only",
6
6
  "homepage": "https://github.com/gnosisguild/zodiac-os-sdk",
@@ -62,7 +62,7 @@
62
62
  "ethers": "^6.13.0",
63
63
  "prettier": "^3.6.2",
64
64
  "rimraf": "^6.1.0",
65
- "tsdown": "^0.21.4",
65
+ "tsdown": "~0.21.9",
66
66
  "typescript": "^5.9.2"
67
67
  }
68
68
  }