@zodiaceco/sdk 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +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 { 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'\nimport { ensureConfigStub } from '../config'\nimport { findProjectRoot } from '../projectRoot'\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 ?? findProjectRoot()\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 // So a same-run `pull` targets the org we just authorized, not the default.\n process.env.ZODIAC_API_KEY = apiKey\n process.env.ZODIAC_API_URL = apiUrl\n\n console.log(`✅ API key written to ${envPath}`)\n\n const configPath = join(rootDir, 'zodiac.config.ts')\n if (ensureConfigStub(configPath)) {\n console.log(`✅ Created ${configPath}`)\n }\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 // Accounts we only know by address — Safe owners, external role\n // members, route targets — carry no label. They can't key a\n // label-addressed namespace, so they stay out of the codegen.\n // Vault entries always carry one.\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 const { label } = account\n if (label == null || !isNodeType(account.type)) continue\n const counts = labelCountByType[account.type]\n counts.set(label, (counts.get(label) ?? 0) + 1)\n }\n\n for (const account of ws.accounts) {\n const { label } = account\n if (label == null || !isNodeType(account.type)) continue\n const onChain = resolved.get(account.id)\n const counts = labelCountByType[account.type]\n const key =\n (counts.get(label) ?? 0) > 1\n ? `${label} (${getAddress(account.address)})`\n : label\n bucketsByType[account.type][key] = {\n id: account.id,\n 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 \"@zodiaceco/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 createIfMissing: true,\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('pull')\n .description(\n 'Fetch Zodiac org data and contract ABIs, generating typed SDK functions. Authorizes this directory automatically on first run.'\n )\n .action(async (_opts, cmd) => {\n const config = await loadConfigOrInit(cmd.optsWithGlobals().config)\n await Promise.all([pullOrg(config), pullContracts(config)])\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('init')\n .description(\n 'Re-authorize this directory / mint a new API key (run automatically by `pull` on first use).'\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 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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"}
@@ -0,0 +1,126 @@
1
+ import { existsSync, writeFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { pathToFileURL } from "url";
4
+ import { dirname as dirname$1, resolve as resolve$1 } from "path";
5
+ //#region src/cli/projectRoot.ts
6
+ /**
7
+ * Walk up from `startDir` looking for a `package.json`. Returns the
8
+ * directory that contains it. Falls back to `startDir` if no ancestor
9
+ * has a `package.json` (e.g. when running outside any project).
10
+ */
11
+ const findProjectRoot = (startDir = process.cwd()) => {
12
+ const absoluteStart = resolve(startDir);
13
+ let dir = absoluteStart;
14
+ while (true) {
15
+ if (existsSync(resolve(dir, "package.json"))) return dir;
16
+ const parent = dirname(dir);
17
+ if (parent === dir) return absoluteStart;
18
+ dir = parent;
19
+ }
20
+ };
21
+ //#endregion
22
+ //#region src/cli/config.ts
23
+ const defineConfig = (config) => config;
24
+ const CONFIG_BASENAME = "zodiac.config";
25
+ /**
26
+ * Extensions probed (in priority order) when the user doesn't pass an
27
+ * explicit `--config` path. Mirrors what vite / vitest / tailwind accept.
28
+ */
29
+ const CONFIG_EXTENSIONS = [
30
+ ".ts",
31
+ ".mts",
32
+ ".cts",
33
+ ".js",
34
+ ".mjs",
35
+ ".cjs"
36
+ ];
37
+ const DEFAULT_CONFIG_PATH = `${CONFIG_BASENAME}.ts`;
38
+ const CONFIG_STUB = `import { defineConfig } from "@zodiaceco/sdk/cli/config";
39
+
40
+ export default defineConfig({
41
+ contracts: {
42
+ // Add contracts the \`allow\` kit should know about, keyed by chain prefix.
43
+ // Run \`zodiac pull-contracts\` after editing.
44
+ //
45
+ // eth: {
46
+ // weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
47
+ // },
48
+ },
49
+ });
50
+ `;
51
+ /**
52
+ * Write a starter `zodiac.config.ts` if no file exists at `absolutePath`.
53
+ * Returns `true` if a file was written.
54
+ */
55
+ const ensureConfigStub = (absolutePath) => {
56
+ if (existsSync(absolutePath)) return false;
57
+ writeFileSync(absolutePath, CONFIG_STUB, "utf8");
58
+ return true;
59
+ };
60
+ /**
61
+ * Turn a (possibly-default) config path into an absolute path under
62
+ * `projectRoot`. When the caller didn't pass an explicit path, probe
63
+ * for `zodiac.config.{ts,mts,cts,js,mjs,cjs}` and use whichever exists;
64
+ * fall back to the canonical `.ts` name so a not-found error is
65
+ * still phrased in terms users recognise.
66
+ */
67
+ const resolveConfigPath = (projectRoot, configPath) => {
68
+ const explicit = resolve$1(projectRoot, configPath);
69
+ if (configPath !== DEFAULT_CONFIG_PATH) return explicit;
70
+ for (const ext of CONFIG_EXTENSIONS) {
71
+ const candidate = resolve$1(projectRoot, `${CONFIG_BASENAME}${ext}`);
72
+ if (existsSync(candidate)) return candidate;
73
+ }
74
+ return explicit;
75
+ };
76
+ async function loadConfig(configPath = DEFAULT_CONFIG_PATH, options = {}) {
77
+ const absolutePath = resolveConfigPath(findProjectRoot(), configPath);
78
+ if (options.createIfMissing && ensureConfigStub(absolutePath)) console.log(`✅ Created ${absolutePath}`);
79
+ let mod;
80
+ try {
81
+ mod = await import(pathToFileURL(absolutePath).href);
82
+ } catch (error) {
83
+ if (error?.code === "ERR_MODULE_NOT_FOUND" || error?.code === "ENOENT") throw new Error(`Config file not found: ${absolutePath}`);
84
+ throw error;
85
+ }
86
+ const config = mod.default ?? mod.config;
87
+ if (!config) throw new Error(`Config file must export a default value or a named "config" export: ${absolutePath}`);
88
+ const rootDir = dirname$1(absolutePath);
89
+ const apiKey = await resolveApiKey(config, rootDir, options);
90
+ return {
91
+ ...config,
92
+ apiKey,
93
+ rootDir
94
+ };
95
+ }
96
+ const resolveApiKey = async (config, rootDir, { onMissingKey }) => {
97
+ if (config.apiKey != null) {
98
+ if (!isApiKey(config.apiKey)) throw new Error("`apiKey` in zodiac.config.ts is malformed: a valid Zodiac API key starts with \"zodiac_\". Either remove the field to use ZODIAC_API_KEY, or run `zodiac init` to mint a fresh key.");
99
+ return config.apiKey;
100
+ }
101
+ const fromEnv = process.env.ZODIAC_API_KEY;
102
+ if (fromEnv != null && fromEnv !== "") {
103
+ if (!isApiKey(fromEnv)) throw new Error("ZODIAC_API_KEY is set but malformed: a valid Zodiac API key starts with \"zodiac_\". Run `zodiac init` to mint a fresh key.");
104
+ return fromEnv;
105
+ }
106
+ if (onMissingKey == null) throw new Error("No Zodiac API key found. Set ZODIAC_API_KEY in your environment, or run `zodiac init` to generate one.");
107
+ const minted = await onMissingKey(rootDir);
108
+ if (!isApiKey(minted)) throw new Error(`onMissingKey returned an invalid Zodiac API key (expected a value starting with "zodiac_").`);
109
+ return minted;
110
+ };
111
+ const isApiKey = (value) => value != null && value.startsWith("zodiac_");
112
+ const DEFAULT_ABIS_DIR = "abis";
113
+ /**
114
+ * Resolves the absolute path to the ABIs directory. Only `rootDir` (and
115
+ * optionally `abisDir`) are read, so the parameter is intentionally narrower
116
+ * than `ResolvedConfig`: userland code can pass `{ ...config, rootDir }`
117
+ * without first satisfying `apiKey` (normally supplied via the
118
+ * `ZODIAC_API_KEY` env var at runtime).
119
+ */
120
+ function resolveAbisDir(config) {
121
+ return resolve$1(config.rootDir, config.abisDir ?? "abis");
122
+ }
123
+ //#endregion
124
+ export { resolveAbisDir as a, loadConfig as i, defineConfig as n, findProjectRoot as o, ensureConfigStub as r, DEFAULT_ABIS_DIR as t };
125
+
126
+ //# sourceMappingURL=config-D5ArAp07.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-D5ArAp07.mjs","names":["resolve","dirname"],"sources":["../src/cli/projectRoot.ts","../src/cli/config.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\n\n/**\n * Walk up from `startDir` looking for a `package.json`. Returns the\n * directory that contains it. Falls back to `startDir` if no ancestor\n * has a `package.json` (e.g. when running outside any project).\n */\nexport const findProjectRoot = (startDir: string = process.cwd()): string => {\n const absoluteStart = resolve(startDir)\n let dir = absoluteStart\n\n while (true) {\n if (existsSync(resolve(dir, 'package.json'))) {\n return dir\n }\n const parent = dirname(dir)\n if (parent === dir) {\n return absoluteStart\n }\n dir = parent\n }\n}\n","import { existsSync, writeFileSync } from 'node:fs'\nimport { pathToFileURL } from 'url'\nimport { dirname, resolve } from 'path'\nimport { findProjectRoot } from './projectRoot'\n\nexport type Contracts = {\n [chain: string]: ContractsNode\n}\nexport type ContractsNode = `0x${string}` | { [name: string]: ContractsNode }\n\nexport interface ZodiacConfig {\n /**\n * API key authorizing this directory against a Zodiac org.\n *\n * Optional — defaults to `process.env.ZODIAC_API_KEY` (populated by\n * `zodiac init`). Set this explicitly only when you need to override\n * the env var from inside the config file.\n */\n apiKey?: `zodiac_${string}`\n /**\n * Contracts the `allow` kit should know about, keyed by chain prefix.\n * Nested objects are allowed for grouping related addresses.\n */\n contracts?: Contracts\n /**\n * Directory where fetched ABIs are stored and read from.\n * Resolved relative to the project root (config file's directory).\n * Defaults to `./abis`.\n */\n abisDir?: string\n}\n\n/** User-provided config plus the resolved API key + project root. */\nexport interface ResolvedConfig extends Omit<ZodiacConfig, 'apiKey'> {\n apiKey: `zodiac_${string}`\n rootDir: string\n}\n\n/**\n * Loose base used as the *inference* constraint for `defineConfig`.\n * `contracts` is `Record<string, unknown>` here so `const T` can preserve the\n * caller's exact address literals rather than collapsing them into the\n * recursive `ContractsNode` union.\n */\ntype DefineConfigInput = {\n apiKey?: `zodiac_${string}`\n contracts?: Record<string, unknown>\n abisDir?: string\n}\n\n/**\n * Recursive leaf-level check: every leaf in `contracts` must be\n * `` `0x${string}` ``; any other value collapses the branch to `never`,\n * which surfaces as a type error at the call site.\n */\ntype ValidateContracts<C> = {\n [K in keyof C]: C[K] extends `0x${string}`\n ? C[K]\n : C[K] extends object\n ? ValidateContracts<C[K]>\n : never\n}\n\nexport const defineConfig = <const T extends DefineConfigInput>(\n config: T & {\n contracts?: ValidateContracts<NonNullable<T['contracts']>>\n }\n): T => config\n\nconst CONFIG_BASENAME = 'zodiac.config'\n\n/**\n * Extensions probed (in priority order) when the user doesn't pass an\n * explicit `--config` path. Mirrors what vite / vitest / tailwind accept.\n */\nconst CONFIG_EXTENSIONS = [\n '.ts',\n '.mts',\n '.cts',\n '.js',\n '.mjs',\n '.cjs',\n] as const\n\nconst DEFAULT_CONFIG_PATH = `${CONFIG_BASENAME}.ts`\n\nconst CONFIG_STUB = `import { defineConfig } from \"@zodiaceco/sdk/cli/config\";\n\nexport default defineConfig({\n contracts: {\n // Add contracts the \\`allow\\` kit should know about, keyed by chain prefix.\n // Run \\`zodiac pull-contracts\\` after editing.\n //\n // eth: {\n // weth: \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n // },\n },\n});\n`\n\ntype LoadConfigOptions = {\n /**\n * Called when neither `config.apiKey` nor `process.env.ZODIAC_API_KEY` is\n * set. Receives the resolved project root and must return a freshly minted\n * API key. Typically wired to the interactive `init()` flow.\n *\n * If omitted, `loadConfig` throws when no key is found.\n */\n onMissingKey?: (rootDir: string) => Promise<string>\n /**\n * When the config file doesn't exist, write a minimal stub before\n * loading. Used by the CLI's `pull` commands so first-time setup\n * works without the user having to scaffold the file themselves.\n */\n createIfMissing?: boolean\n}\n\n/**\n * Write a starter `zodiac.config.ts` if no file exists at `absolutePath`.\n * Returns `true` if a file was written.\n */\nexport const ensureConfigStub = (absolutePath: string): boolean => {\n if (existsSync(absolutePath)) return false\n writeFileSync(absolutePath, CONFIG_STUB, 'utf8')\n return true\n}\n\n/**\n * Turn a (possibly-default) config path into an absolute path under\n * `projectRoot`. When the caller didn't pass an explicit path, probe\n * for `zodiac.config.{ts,mts,cts,js,mjs,cjs}` and use whichever exists;\n * fall back to the canonical `.ts` name so a not-found error is\n * still phrased in terms users recognise.\n */\nconst resolveConfigPath = (projectRoot: string, configPath: string): string => {\n const explicit = resolve(projectRoot, configPath)\n if (configPath !== DEFAULT_CONFIG_PATH) return explicit\n\n for (const ext of CONFIG_EXTENSIONS) {\n const candidate = resolve(projectRoot, `${CONFIG_BASENAME}${ext}`)\n if (existsSync(candidate)) return candidate\n }\n return explicit\n}\n\nexport async function loadConfig(\n configPath: string = DEFAULT_CONFIG_PATH,\n options: LoadConfigOptions = {}\n): Promise<ResolvedConfig> {\n // Resolve relative paths (including the default) against the nearest\n // package.json ancestor — that's where users expect the config to live,\n // regardless of which subdir they ran the CLI from.\n const projectRoot = findProjectRoot()\n const absolutePath = resolveConfigPath(projectRoot, configPath)\n\n if (options.createIfMissing && ensureConfigStub(absolutePath)) {\n console.log(`✅ Created ${absolutePath}`)\n }\n\n let mod: Record<string, unknown>\n try {\n mod = await import(pathToFileURL(absolutePath).href)\n } catch (error: any) {\n if (error?.code === 'ERR_MODULE_NOT_FOUND' || error?.code === 'ENOENT') {\n throw new Error(`Config file not found: ${absolutePath}`)\n }\n throw error\n }\n\n const config = (mod.default ?? mod.config) as ZodiacConfig | undefined\n if (!config) {\n throw new Error(\n `Config file must export a default value or a named \"config\" export: ${absolutePath}`\n )\n }\n\n const rootDir = dirname(absolutePath)\n const apiKey = await resolveApiKey(config, rootDir, options)\n\n return { ...config, apiKey, rootDir }\n}\n\nconst resolveApiKey = async (\n config: ZodiacConfig,\n rootDir: string,\n { onMissingKey }: LoadConfigOptions\n): Promise<`zodiac_${string}`> => {\n if (config.apiKey != null) {\n if (!isApiKey(config.apiKey)) {\n throw new Error(\n '`apiKey` in zodiac.config.ts is malformed: a valid Zodiac API key starts with \"zodiac_\". Either remove the field to use ZODIAC_API_KEY, or run `zodiac init` to mint a fresh key.'\n )\n }\n return config.apiKey\n }\n\n const fromEnv = process.env.ZODIAC_API_KEY\n if (fromEnv != null && fromEnv !== '') {\n if (!isApiKey(fromEnv)) {\n throw new Error(\n 'ZODIAC_API_KEY is set but malformed: a valid Zodiac API key starts with \"zodiac_\". Run `zodiac init` to mint a fresh key.'\n )\n }\n return fromEnv\n }\n\n if (onMissingKey == null) {\n throw new Error(\n 'No Zodiac API key found. Set ZODIAC_API_KEY in your environment, or run `zodiac init` to generate one.'\n )\n }\n\n const minted = await onMissingKey(rootDir)\n if (!isApiKey(minted)) {\n throw new Error(\n `onMissingKey returned an invalid Zodiac API key (expected a value starting with \"zodiac_\").`\n )\n }\n return minted\n}\n\nconst isApiKey = (value: string | undefined): value is `zodiac_${string}` =>\n value != null && value.startsWith('zodiac_')\n\nexport const DEFAULT_ABIS_DIR = 'abis'\n\n/**\n * Resolves the absolute path to the ABIs directory. Only `rootDir` (and\n * optionally `abisDir`) are read, so the parameter is intentionally narrower\n * than `ResolvedConfig`: userland code can pass `{ ...config, rootDir }`\n * without first satisfying `apiKey` (normally supplied via the\n * `ZODIAC_API_KEY` env var at runtime).\n */\nexport function resolveAbisDir(config: {\n rootDir: string\n abisDir?: string\n}): string {\n return resolve(config.rootDir, config.abisDir ?? DEFAULT_ABIS_DIR)\n}\n"],"mappings":";;;;;;;;;;AAQA,MAAa,mBAAmB,WAAmB,QAAQ,KAAK,KAAa;CAC3E,MAAM,gBAAgB,QAAQ,SAAS;CACvC,IAAI,MAAM;AAEV,QAAO,MAAM;AACX,MAAI,WAAW,QAAQ,KAAK,eAAe,CAAC,CAC1C,QAAO;EAET,MAAM,SAAS,QAAQ,IAAI;AAC3B,MAAI,WAAW,IACb,QAAO;AAET,QAAM;;;;;AC2CV,MAAa,gBACX,WAGM;AAER,MAAM,kBAAkB;;;;;AAMxB,MAAM,oBAAoB;CACxB;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,sBAAsB,GAAG,gBAAgB;AAE/C,MAAM,cAAc;;;;;;;;;;;;;;;;;AAmCpB,MAAa,oBAAoB,iBAAkC;AACjE,KAAI,WAAW,aAAa,CAAE,QAAO;AACrC,eAAc,cAAc,aAAa,OAAO;AAChD,QAAO;;;;;;;;;AAUT,MAAM,qBAAqB,aAAqB,eAA+B;CAC7E,MAAM,WAAWA,UAAQ,aAAa,WAAW;AACjD,KAAI,eAAe,oBAAqB,QAAO;AAE/C,MAAK,MAAM,OAAO,mBAAmB;EACnC,MAAM,YAAYA,UAAQ,aAAa,GAAG,kBAAkB,MAAM;AAClE,MAAI,WAAW,UAAU,CAAE,QAAO;;AAEpC,QAAO;;AAGT,eAAsB,WACpB,aAAqB,qBACrB,UAA6B,EAAE,EACN;CAKzB,MAAM,eAAe,kBADD,iBAAiB,EACe,WAAW;AAE/D,KAAI,QAAQ,mBAAmB,iBAAiB,aAAa,CAC3D,SAAQ,IAAI,aAAa,eAAe;CAG1C,IAAI;AACJ,KAAI;AACF,QAAM,MAAM,OAAO,cAAc,aAAa,CAAC;UACxC,OAAY;AACnB,MAAI,OAAO,SAAS,0BAA0B,OAAO,SAAS,SAC5D,OAAM,IAAI,MAAM,0BAA0B,eAAe;AAE3D,QAAM;;CAGR,MAAM,SAAU,IAAI,WAAW,IAAI;AACnC,KAAI,CAAC,OACH,OAAM,IAAI,MACR,uEAAuE,eACxE;CAGH,MAAM,UAAUC,UAAQ,aAAa;CACrC,MAAM,SAAS,MAAM,cAAc,QAAQ,SAAS,QAAQ;AAE5D,QAAO;EAAE,GAAG;EAAQ;EAAQ;EAAS;;AAGvC,MAAM,gBAAgB,OACpB,QACA,SACA,EAAE,mBAC8B;AAChC,KAAI,OAAO,UAAU,MAAM;AACzB,MAAI,CAAC,SAAS,OAAO,OAAO,CAC1B,OAAM,IAAI,MACR,sLACD;AAEH,SAAO,OAAO;;CAGhB,MAAM,UAAU,QAAQ,IAAI;AAC5B,KAAI,WAAW,QAAQ,YAAY,IAAI;AACrC,MAAI,CAAC,SAAS,QAAQ,CACpB,OAAM,IAAI,MACR,8HACD;AAEH,SAAO;;AAGT,KAAI,gBAAgB,KAClB,OAAM,IAAI,MACR,yGACD;CAGH,MAAM,SAAS,MAAM,aAAa,QAAQ;AAC1C,KAAI,CAAC,SAAS,OAAO,CACnB,OAAM,IAAI,MACR,8FACD;AAEH,QAAO;;AAGT,MAAM,YAAY,UAChB,SAAS,QAAQ,MAAM,WAAW,UAAU;AAE9C,MAAa,mBAAmB;;;;;;;;AAShC,SAAgB,eAAe,QAGpB;AACT,QAAOD,UAAQ,OAAO,SAAS,OAAO,WAAA,OAA4B"}
@@ -0,0 +1,63 @@
1
+ import { Condition, FunctionPermission, TargetPermission } from "zodiac-roles-sdk";
2
+ import { BigNumberish, BytesLike, ParamType } from "ethers";
3
+
4
+ //#region src/allow/runtime.d.ts
5
+ declare function buildAllowKit(abisDir: string, contractsConfig: Record<string, any>): Record<string, any>;
6
+ //#endregion
7
+ //#region src/allow/types.d.ts
8
+ type Options = {
9
+ send?: boolean;
10
+ delegatecall?: boolean;
11
+ etherWithinAllowance?: `0x${string}`;
12
+ callWithinAllowance?: `0x${string}`;
13
+ };
14
+ type PrimitiveValue = BigNumberish | BytesLike | string | boolean;
15
+ type ConditionFunction<T = unknown> = (abiType: ParamType, _?: T) => Condition;
16
+ type RequireAtLeastOne<T> = { [K in keyof T]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<keyof T, K>>> }[keyof T];
17
+ type ArrayElement<T extends readonly unknown[]> = T extends readonly (infer U)[] ? U : never;
18
+ type PrimitiveScoping<T extends PrimitiveValue> = T | ConditionFunction<T>;
19
+ type ArrayScoping<T extends readonly any[]> = readonly Scoping<ArrayElement<T>>[] | ConditionFunction<T>;
20
+ type StructScoping<T extends {
21
+ [key: string]: any;
22
+ }> = RequireAtLeastOne<{ [K in keyof T]?: Scoping<T[K]> }> | ConditionFunction<T>;
23
+ type Scoping<T> = T extends PrimitiveValue ? PrimitiveScoping<T> : T extends readonly any[] ? ArrayScoping<T> : T extends {
24
+ [key: string]: any;
25
+ } ? StructScoping<T> : unknown;
26
+ declare const EVERYTHING: unique symbol;
27
+ type EVERYTHING = typeof EVERYTHING;
28
+ //#endregion
29
+ //#region src/allow/networks.d.ts
30
+ declare const CHAIN_IDS: {
31
+ readonly eth: 1;
32
+ readonly oeth: 10;
33
+ readonly gno: 100;
34
+ readonly sep: 11155111;
35
+ readonly matic: 137;
36
+ readonly zkevm: 1101;
37
+ readonly arb1: 42161;
38
+ readonly avax: 43114;
39
+ readonly base: 8453;
40
+ readonly basesep: 84532;
41
+ readonly bnb: 56;
42
+ readonly celo: 42220;
43
+ readonly sonic: 146;
44
+ readonly berachain: 80094;
45
+ readonly unichain: 130;
46
+ readonly worldchain: 480;
47
+ readonly bob: 60808;
48
+ readonly mantle: 5000;
49
+ readonly hemi: 43111;
50
+ readonly katana: 747474;
51
+ readonly linea: 59144;
52
+ readonly ink: 57073;
53
+ readonly hyperevm: 999;
54
+ readonly flare: 14;
55
+ readonly scroll: 534352;
56
+ readonly plasma: 9745;
57
+ readonly megaeth: 4326;
58
+ };
59
+ type ChainPrefix = keyof typeof CHAIN_IDS;
60
+ declare const chainIdFor: (prefix: string) => number;
61
+ //#endregion
62
+ export { EVERYTHING as a, Scoping as c, ConditionFunction as i, TargetPermission as l, ChainPrefix as n, FunctionPermission as o, chainIdFor as r, Options as s, CHAIN_IDS as t, buildAllowKit as u };
63
+ //# sourceMappingURL=index-DoZbhpS6.d.mts.map
@@ -0,0 +1,256 @@
1
+ /// <reference path="./zodiac-os-codegen.d.ts" />
2
+ import { a as EVERYTHING, c as Scoping, i as ConditionFunction, l as TargetPermission, n as ChainPrefix, o as FunctionPermission, s as Options, u as buildAllowKit } from "./index-DoZbhpS6.mjs";
3
+ import { Annotation, Permission, PermissionSet, c, forAll } from "zodiac-roles-sdk";
4
+ import { Address, ApplyConstellationPayload, ApplyConstellationResult, ChainId, ListAccountsResult, ListUsersResult, ResolveConstellationPayload, ResolveConstellationResult } from "@zodiaceco/api-types";
5
+ import { UUID } from "crypto";
6
+
7
+ //#region src/types.d.ts
8
+ type ApiNewRolesSpec = Extract<ApplyConstellationPayload['specification'][number], {
9
+ type: 'ROLES';
10
+ nonce: string;
11
+ }>;
12
+ /** A role definition in the API's serialized format (bigints as template literal strings). */
13
+ /** An allowance definition in the API's serialized format (bigints as template literal strings). */
14
+ type ApiAllowanceSpec = Extract<NonNullable<ApiNewRolesSpec['allowances']>, readonly any[]>[number];
15
+ /** Recursively converts `${bigint}` template literal strings to `bigint`. */
16
+ type RealBigints<T> = T extends `${bigint}` ? bigint : T extends readonly (infer U)[] ? RealBigints<U>[] : T extends Record<string, any> ? { [K in keyof T]: RealBigints<T[K]> } : T;
17
+ /** A role definition with bigint fields as actual bigints. */
18
+ /** An allowance definition with bigint fields as actual bigints. */
19
+ type AllowanceSpec = RealBigints<ApiAllowanceSpec>;
20
+ //#endregion
21
+ //#region src/constellation.d.ts
22
+ /**
23
+ * A role definition keyed by role name. Permissions are expanded into
24
+ * `{ targets, annotations }` via `processPermissions` at `push()` time.
25
+ */
26
+ type RoleDef = {
27
+ members: readonly AddressOrRef[];
28
+ permissions: readonly (Permission | PermissionSet | Promise<PermissionSet>)[];
29
+ annotations?: readonly Annotation[];
30
+ };
31
+ type User = {
32
+ id: UUID;
33
+ fullName: string;
34
+ personalSafes: Record<number, {
35
+ address: Lowercase<Address>;
36
+ active: boolean;
37
+ }>;
38
+ };
39
+ type Account = {
40
+ id: UUID;
41
+ label: string;
42
+ address: Lowercase<Address>;
43
+ chain: ChainId; /** True for accounts promoted to a workspace vault. */
44
+ vault: boolean;
45
+ };
46
+ /**
47
+ * Accounts grouped by node type within a workspace. Per-type maps keep
48
+ * bracket-accessor namespaces separate: a SAFE and a ROLES mod sharing a
49
+ * label don't collide, and `eth.safe[...]` IntelliSense doesn't suggest
50
+ * ROLES mod labels (and vice versa).
51
+ */
52
+ type WorkspaceAccounts = {
53
+ workspaceId: UUID;
54
+ workspaceName: string;
55
+ safes: Readonly<Record<string, Account>>;
56
+ rolesMods: Readonly<Record<string, Account>>;
57
+ delays: Readonly<Record<string, Account>>;
58
+ };
59
+ /** Shape of the codegen data produced by `zodiac pull-org`. */
60
+ type CodegenData = {
61
+ users: Readonly<Record<string, User>>;
62
+ accounts: Readonly<Record<string, WorkspaceAccounts>>;
63
+ };
64
+ type GeneratedCodegen = ZodiacGeneratedCodegen extends CodegenData ? ZodiacGeneratedCodegen : CodegenData;
65
+ type ConstellationOpts<C extends CodegenData> = {
66
+ /** Workspace to scope accounts and roles to. */workspace: keyof C['accounts'] & string; /** Human-readable label for this constellation. */
67
+ label: string; /** Target chain for all nodes in this constellation. */
68
+ chain: ChainId;
69
+ };
70
+ type ConstellationInternalOpts<C extends CodegenData> = {
71
+ /** Injected codegen data (used for testing). */codegen?: C;
72
+ };
73
+ type Prettify<T> = { readonly [K in keyof T]: T[K] } & {};
74
+ type SafeEntries<C extends CodegenData, W extends keyof C['accounts']> = C['accounts'][W]['safes'];
75
+ type RolesEntries<C extends CodegenData, W extends keyof C['accounts']> = C['accounts'][W]['rolesMods'];
76
+ type NodeType = 'SAFE' | 'ROLES' | 'DELAY';
77
+ /** A reference to a node used in `owners`, `modules`, `target`, etc. */
78
+ type NodeRef = Readonly<{
79
+ type: NodeType;
80
+ label: string;
81
+ chain: ChainId;
82
+ }>;
83
+ /** A blockchain address (checksummed or lowercase) or a reference to another
84
+ * node in the constellation. Values are normalized to lowercase before being
85
+ * sent to the API. */
86
+ type AddressOrRef = Address | NodeRef;
87
+ type NodeBase = Readonly<{
88
+ /** Human-readable identifier, unique within the constellation. */label: string; /** Chain the node is deployed on. */
89
+ chain: ChainId;
90
+ /** Set for existing nodes (from codegen or bound by address), absent for new
91
+ * nodes. Accepts checksummed or lowercase; normalized to lowercase on push. */
92
+ address?: Address; /** Deployment nonce — required for new nodes, optional for existing. */
93
+ nonce?: bigint;
94
+ }>;
95
+ /** A safe node spec — existing vault ref or new safe with required config. */
96
+ type SafeNode = NodeBase & Readonly<{
97
+ /** Discriminator identifying this node as a Safe. */type: 'SAFE'; /** Number of owner signatures required to execute a transaction. */
98
+ threshold: number; /** Safe owner addresses or node references. */
99
+ owners: readonly (string | NodeRef)[]; /** Module addresses or node references enabled on the safe. */
100
+ modules?: readonly (string | NodeRef)[]; /** Whether this safe shall appear as a vault in the workspace. @default false */
101
+ vault?: boolean;
102
+ }>;
103
+ /** A roles modifier node spec — existing vault ref or new roles with modifier config. */
104
+ type RolesNode = NodeBase & Readonly<{
105
+ /** Discriminator identifying this node as a Roles modifier. */type: 'ROLES'; /** The safe that this roles modifier controls. */
106
+ target?: AddressOrRef; /** The account that is allowed to update the configuration of the Roles mod. */
107
+ owner?: AddressOrRef; /** The account that calls will be executed from. */
108
+ avatar?: AddressOrRef; /** MultiSend contract addresses for batched transactions. */
109
+ multisend?: readonly Address[];
110
+ /** Role definitions configured on this modifier. Pass `null` for a key to
111
+ * clear that role; unmentioned roles are left untouched. */
112
+ roles?: Record<string, RoleDef | null>;
113
+ /** Spending allowances configured on this modifier, keyed by name. Pass
114
+ * `null` for a key to clear that allowance; unmentioned allowances are
115
+ * left untouched. */
116
+ allowances?: Record<string, AllowanceSpec | null>;
117
+ }>;
118
+ /** Any complete node that can be passed to `push()`. */
119
+ type ConstellationNode = SafeNode | RolesNode;
120
+ type NewSafeProps = {
121
+ /** Deployment nonce for CREATE2 address derivation. */nonce: bigint; /** Number of owner signatures required to execute a transaction. */
122
+ threshold: number; /** Safe owner addresses or node references. */
123
+ owners: readonly AddressOrRef[]; /** Module addresses or node references to enable on the safe. */
124
+ modules?: readonly AddressOrRef[]; /** Whether this safe is a workspace vault. @default false */
125
+ vault?: boolean;
126
+ };
127
+ /** Configuration shared by both ways of declaring a roles modifier. */
128
+ type RolesConfig = {
129
+ /** The safe that this roles modifier controls. Defaults to the new safe with the same label, when one exists. */target?: AddressOrRef; /** The account that calls will be executed from. Defaults to `target` value */
130
+ avatar?: AddressOrRef; /** The account that is allowed to update the configuration of the Roles Mod. Defaults to `target` value */
131
+ owner?: AddressOrRef; /** MultiSend contract addresses for batched transactions. Defaults to `['0x38869bf66a61cf6bdb996a6ae40d5853fd43b526', '0x9641d764fc13c8b624c04430c7356c1c7c8102e2']` */
132
+ multisend?: readonly Address[];
133
+ /** Role definitions to configure on this modifier. Pass `null` for a key to
134
+ * clear that role; unmentioned roles are left untouched. */
135
+ roles?: Record<string, RoleDef | null>;
136
+ /** Spending allowances to configure on this modifier, keyed by name. Pass
137
+ * `null` for a key to clear that allowance; unmentioned allowances are
138
+ * left untouched. */
139
+ allowances?: Record<string, AllowanceSpec | null>;
140
+ };
141
+ /** Declare a brand-new roles modifier (address derived via CREATE2 from `nonce`). */
142
+ type NewRolesByNonce = RolesConfig & {
143
+ /** Deployment nonce for CREATE2 address derivation. */nonce: bigint;
144
+ };
145
+ /** Bind to a roles modifier already deployed on-chain at a known address, to
146
+ * reconfigure its roles/allowances. Use this for mods not (yet) imported into
147
+ * the workspace — pass the address instead of a deployment `nonce`. */
148
+ type ExistingRolesByAddress = RolesConfig & {
149
+ /** Address of the existing Roles mod to bind to and reconfigure. */address: Address;
150
+ };
151
+ type NewRolesProps = NewRolesByNonce | ExistingRolesByAddress;
152
+ type ExistingNodeAccessor<Type extends string, K extends string, E, Ch extends ChainId, NP extends Record<string, any>> = Readonly<Prettify<E & {
153
+ type: Type;
154
+ label: K;
155
+ chain: Ch;
156
+ }>> & (<O extends { [P in Exclude<keyof E & string, 'id' | 'label'>]?: any } & Partial<NP> = {}>(overrides?: { [P in Exclude<keyof E & string, 'id' | 'label'>]?: any } & Partial<NP> & O) => Readonly<Prettify<Omit<E, keyof O> & O & Partial<NP> & {
157
+ type: Type;
158
+ label: K;
159
+ chain: Ch;
160
+ }>>);
161
+ type NewNodeAccessor<Type extends string, Ch extends ChainId, NP extends Record<string, any>> = Readonly<Prettify<{
162
+ type: Type;
163
+ label: string;
164
+ chain: Ch;
165
+ }>> & (<P extends NP>(props: P) => Readonly<Prettify<P & {
166
+ type: Type;
167
+ label: string;
168
+ chain: Ch;
169
+ }>>);
170
+ type EntityAccessor<Type extends string, Entries extends Record<string, any>, Ch extends ChainId = ChainId, NP extends Record<string, any> = Record<string, any>> = { readonly [K in keyof Entries & string]: ExistingNodeAccessor<Type, K, Entries[K], Ch, NP> } & {
171
+ readonly [key: string]: NewNodeAccessor<Type, Ch, NP>;
172
+ };
173
+ type UserAccessor<C extends CodegenData, Ch extends number> = { readonly [K in keyof C['users'] & string]: C['users'][K]['personalSafes'][Ch]['address'] };
174
+ type ConstellationResult<C extends CodegenData, W extends keyof C['accounts'] = keyof C['accounts'], Ch extends ChainId = ChainId> = {
175
+ /** Access existing safes by label or create new ones with a new label.
176
+ * Only SAFE-typed accounts are suggested in IntelliSense. */
177
+ safe: EntityAccessor<'SAFE', SafeEntries<C, W>, Ch, NewSafeProps>;
178
+ /** Access existing roles modifiers by label or create new ones with a
179
+ * new label. Only ROLES-typed accounts are suggested in IntelliSense. */
180
+ roles: EntityAccessor<'ROLES', RolesEntries<C, W>, Ch, NewRolesProps>; /** Resolve a user's personal safe address on the constellation's chain. */
181
+ user: UserAccessor<C, Ch>;
182
+ };
183
+ /** @internal */
184
+ /**
185
+ * Creates a constellation scoped to a workspace and chain.
186
+ *
187
+ * Use bracket access to reference existing accounts (vaults and other
188
+ * applied constellation nodes) or define new ones:
189
+ * ```ts
190
+ * const eth = constellation({ workspace: 'GG', label: 'my constellation', chain: 1 })
191
+ *
192
+ * const dao = eth.safe['GG DAO'] // existing account ref
193
+ * const roles = eth.roles['GG DAO'] // existing roles ref
194
+ * const newSafe = eth.safe['New Safe']({ nonce: 0n, threshold: 2, owners: [...], modules: [...] })
195
+ * ```
196
+ */
197
+ declare function constellation<const C extends CodegenData = GeneratedCodegen, const W extends keyof C['accounts'] & string = keyof C['accounts'] & string, const Ch extends ChainId = ChainId>(opts: ConstellationOpts<C> & {
198
+ workspace: W;
199
+ chain: Ch;
200
+ }, internal?: ConstellationInternalOpts<C>): ConstellationResult<C, W, Ch>;
201
+ //#endregion
202
+ //#region src/api.d.ts
203
+ type Options$1 = {
204
+ workspace?: string;
205
+ apiKey?: string;
206
+ baseUrl?: string;
207
+ fetch?: typeof globalThis.fetch;
208
+ headers?: Record<string, string>;
209
+ };
210
+ declare class ApiClient {
211
+ private apiKey;
212
+ private baseUrl;
213
+ private _fetch;
214
+ private headers;
215
+ constructor({
216
+ baseUrl,
217
+ fetch: customFetch,
218
+ headers,
219
+ apiKey
220
+ }?: Options$1);
221
+ protected postJson(endpoint: string, payload: unknown): Promise<any>;
222
+ protected get(endpoint: string): Promise<any>;
223
+ listAccounts(): Promise<ListAccountsResult>;
224
+ listUsers(): Promise<ListUsersResult>;
225
+ /**
226
+ * Applies an accounts specification to Zodiac OS.
227
+ */
228
+ applyConstellation(workspaceId: UUID, payload: ApplyConstellationPayload): Promise<ApplyConstellationResult>;
229
+ /**
230
+ * Resolves an accounts specification to Zodiac OS.
231
+ */
232
+ resolveConstellation(workspaceId: UUID, payload: ResolveConstellationPayload): Promise<ResolveConstellationResult>;
233
+ }
234
+ //#endregion
235
+ //#region src/push.d.ts
236
+ type PushOpts = {
237
+ /** API client instance. Defaults to a client configured from environment variables. */api?: ApiClient;
238
+ };
239
+ /**
240
+ * Resolves node references and pushes the constellation specification to the API.
241
+ *
242
+ *
243
+ * ```ts
244
+ * const eth = constellation({ workspace: 'GG', label: 'my constellation', chain: 1 })
245
+ * const dao = eth.safe['GG DAO']
246
+ * const roles = eth.roles['New Roles']({ nonce: 0n, target: dao, owner: dao, avatar: dao })
247
+ *
248
+ * await push([dao, roles])
249
+ * ```
250
+ */
251
+ declare function push(nodes: ConstellationNode[] | {
252
+ [key: string]: ConstellationNode;
253
+ }, opts?: PushOpts): Promise<ApplyConstellationResult[]>;
254
+ //#endregion
255
+ export { type ChainPrefix, type ConditionFunction, EVERYTHING, type FunctionPermission, type Options, type Scoping, type TargetPermission, buildAllowKit, c, constellation, forAll, push };
256
+ //# sourceMappingURL=index.d.mts.map