@zodiac-os/sdk 1.1.1 → 1.3.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.
@@ -0,0 +1,212 @@
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-DTBaxN7b.mjs";
3
+ import { c, forAll } from "zodiac-roles-sdk";
4
+ import { Address, ApplyConstellationPayload, ApplyConstellationResult, ChainId, ListUsersResult, ListVaultsResult, ResolveConstellationPayload, ResolveConstellationResult } from "@zodiac-os/api-types";
5
+ import * as ZodiacOsCodegen from ".zodiac-os";
6
+ import { UUID } from "crypto";
7
+
8
+ //#region src/types.d.ts
9
+ type ApiNewRolesSpec = Extract<ApplyConstellationPayload['specification'][number], {
10
+ type: 'ROLES';
11
+ nonce: string;
12
+ }>;
13
+ /** A role definition in the API's serialized format (bigints as template literal strings). */
14
+ type ApiRoleSpec = Extract<NonNullable<ApiNewRolesSpec['roles']>, readonly any[]>[number];
15
+ /** An allowance definition in the API's serialized format (bigints as template literal strings). */
16
+ type ApiAllowanceSpec = Extract<NonNullable<ApiNewRolesSpec['allowances']>, readonly any[]>[number];
17
+ /** Recursively converts `${bigint}` template literal strings to `bigint`. */
18
+ 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;
19
+ /** A role definition with bigint fields as actual bigints. */
20
+ type RoleSpec = RealBigints<ApiRoleSpec>;
21
+ /** An allowance definition with bigint fields as actual bigints. */
22
+ type AllowanceSpec = RealBigints<ApiAllowanceSpec>;
23
+ //#endregion
24
+ //#region src/constellation.d.ts
25
+ type User = {
26
+ id: UUID;
27
+ fullName: string;
28
+ personalSafes: Record<number, {
29
+ address: Lowercase<Address>;
30
+ active: boolean;
31
+ }>;
32
+ };
33
+ type Vault = {
34
+ id: UUID;
35
+ label: string;
36
+ address: Lowercase<Address>;
37
+ chain: ChainId;
38
+ threshold: number;
39
+ owners: readonly string[];
40
+ modules: readonly string[];
41
+ };
42
+ type WorkspaceVaults = {
43
+ workspaceId: UUID;
44
+ workspaceName: string;
45
+ vaults: Readonly<Record<string, Vault>>;
46
+ };
47
+ /** Shape of the codegen data produced by `zodiac-os pull-org`. */
48
+ type CodegenData = {
49
+ users: Readonly<Record<string, User>>;
50
+ vaults: Readonly<Record<string, WorkspaceVaults>>;
51
+ };
52
+ type GeneratedCodegen = {
53
+ users: typeof ZodiacOsCodegen.users;
54
+ vaults: typeof ZodiacOsCodegen.vaults;
55
+ };
56
+ type ConstellationOpts<C extends CodegenData> = {
57
+ /** Workspace to scope vaults and roles to. */workspace: keyof C['vaults'] & string; /** Human-readable label for this constellation. */
58
+ label: string; /** Target chain for all nodes in this constellation. */
59
+ chain: ChainId;
60
+ };
61
+ type ConstellationInternalOpts<C extends CodegenData> = {
62
+ /** Injected codegen data (used for testing). */codegen?: C;
63
+ };
64
+ type Prettify<T> = { readonly [K in keyof T]: T[K] } & {};
65
+ type WorkspaceVaultEntries<C extends CodegenData, W extends keyof C['vaults']> = C['vaults'][W]['vaults'];
66
+ type NodeType = 'SAFE' | 'ROLES' | 'DELAY';
67
+ /** A reference to a node used in `owners`, `modules`, `target`, etc. */
68
+ type NodeRef = Readonly<{
69
+ type: NodeType;
70
+ label: string;
71
+ chain: ChainId;
72
+ }>;
73
+ /** A blockchain address or a reference to another node in the constellation. */
74
+ type AddressOrRef = Lowercase<Address> | NodeRef;
75
+ type NodeBase = Readonly<{
76
+ /** Human-readable identifier, unique within the constellation. */label: string; /** Chain the node is deployed on. */
77
+ chain: ChainId; /** Set for existing nodes from codegen, absent for new nodes. */
78
+ address?: Lowercase<Address>; /** Deployment nonce — required for new nodes, optional for existing. */
79
+ nonce?: bigint;
80
+ }>;
81
+ /** A safe node spec — existing vault ref or new safe with required config. */
82
+ type SafeNode = NodeBase & Readonly<{
83
+ /** Discriminator identifying this node as a Safe. */type: 'SAFE'; /** Number of owner signatures required to execute a transaction. */
84
+ threshold: number; /** Safe owner addresses or node references. */
85
+ owners: readonly (string | NodeRef)[]; /** Module addresses or node references enabled on the safe. */
86
+ modules?: readonly (string | NodeRef)[]; /** Whether this safe shall appear as a vault in the workspace. @default false */
87
+ vault?: boolean;
88
+ }>;
89
+ /** A roles modifier node spec — existing vault ref or new roles with modifier config. */
90
+ type RolesNode = NodeBase & Readonly<{
91
+ /** Discriminator identifying this node as a Roles modifier. */type: 'ROLES'; /** The safe that this roles modifier controls. */
92
+ target?: AddressOrRef; /** The account that is allowed to update the configuration of the Roles mod. */
93
+ owner?: AddressOrRef; /** The account that calls will be executed from. */
94
+ avatar?: AddressOrRef; /** MultiSend contract addresses for batched transactions. */
95
+ multisend?: readonly Lowercase<Address>[]; /** Role definitions configured on this modifier. */
96
+ roles?: readonly RoleSpec[]; /** Spending allowances configured on this modifier. */
97
+ allowances?: readonly AllowanceSpec[];
98
+ }>;
99
+ /** Any complete node that can be passed to `apply()`. */
100
+ type ConstellationNode = SafeNode | RolesNode;
101
+ type NewSafeProps = {
102
+ /** Deployment nonce for CREATE2 address derivation. */nonce: bigint; /** Number of owner signatures required to execute a transaction. */
103
+ threshold: number; /** Safe owner addresses or node references. */
104
+ owners: readonly AddressOrRef[]; /** Module addresses or node references to enable on the safe. */
105
+ modules?: readonly AddressOrRef[]; /** Whether this safe is a workspace vault. @default false */
106
+ vault?: boolean;
107
+ };
108
+ type NewRolesProps = {
109
+ /** Deployment nonce for CREATE2 address derivation. Defaults to `0n` when omitted. */nonce?: bigint; /** The safe that this roles modifier controls. Defaults to the new safe with the same label, when one exists. */
110
+ target?: AddressOrRef; /** The account that calls will be executed from. Defaults to `target` value */
111
+ avatar?: AddressOrRef; /** The account that is allowed to update the configuration of the Roles Mod. Defaults to `target` value */
112
+ owner?: AddressOrRef; /** MultiSend contract addresses for batched transactions. Defaults to `['0x38869bf66a61cf6bdb996a6ae40d5853fd43b526', '0x9641d764fc13c8b624c04430c7356c1c7c8102e2']` */
113
+ multisend?: readonly Lowercase<Address>[]; /** Role definitions to configure on this modifier. */
114
+ roles?: readonly RoleSpec[]; /** Spending allowances to configure on this modifier. */
115
+ allowances?: readonly AllowanceSpec[];
116
+ };
117
+ 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) | (string & {})]: K extends keyof Entries & string ? Readonly<Prettify<Entries[K] & {
118
+ type: Type;
119
+ label: K;
120
+ chain: Ch;
121
+ }>> & (<O extends { [P in Exclude<keyof Entries[K] & string, 'id' | 'label'>]?: any } & Partial<NP> = {}>(overrides?: { [P in Exclude<keyof Entries[K] & string, 'id' | 'label'>]?: any } & Partial<NP> & O) => Readonly<Prettify<Omit<Entries[K], keyof O> & O & Partial<NP> & {
122
+ type: Type;
123
+ label: K;
124
+ chain: Ch;
125
+ }>>) : Readonly<Prettify<{
126
+ type: Type;
127
+ label: string;
128
+ chain: Ch;
129
+ }>> & ((props: NP) => Readonly<Prettify<NP & {
130
+ type: Type;
131
+ label: string;
132
+ chain: Ch;
133
+ }>>) };
134
+ type UserAccessor<C extends CodegenData, Ch extends number> = { readonly [K in keyof C['users'] & string]: C['users'][K]['personalSafes'][Ch]['address'] };
135
+ type ConstellationResult<C extends CodegenData, W extends keyof C['vaults'] = keyof C['vaults'], Ch extends ChainId = ChainId> = {
136
+ /** Access existing safes by label or create new ones with a new label. */safe: EntityAccessor<'SAFE', WorkspaceVaultEntries<C, W>, Ch, NewSafeProps>; /** Access existing roles modifiers by label or create new ones with a new label. */
137
+ roles: EntityAccessor<'ROLES', WorkspaceVaultEntries<C, W>, Ch, NewRolesProps>; /** Resolve a user's personal safe address on the constellation's chain. */
138
+ user: UserAccessor<C, Ch>;
139
+ };
140
+ /** @internal */
141
+ /**
142
+ * Creates a constellation scoped to a workspace and chain.
143
+ *
144
+ * Use bracket access to reference existing vaults or define new nodes:
145
+ * ```ts
146
+ * const eth = constellation({ workspace: 'GG', label: 'my constellation', chain: 1 })
147
+ *
148
+ * const dao = eth.safe['GG DAO'] // existing vault ref
149
+ * const roles = eth.roles['GG DAO'] // existing roles ref
150
+ * const newSafe = eth.safe['New Safe']({ nonce: 0n, threshold: 2, owners: [...], modules: [...] })
151
+ * ```
152
+ */
153
+ declare function constellation<const C extends CodegenData = GeneratedCodegen, const W extends keyof C['vaults'] & string = keyof C['vaults'] & string, const Ch extends ChainId = ChainId>(opts: ConstellationOpts<C> & {
154
+ workspace: W;
155
+ chain: Ch;
156
+ }, internal?: ConstellationInternalOpts<C>): ConstellationResult<C, W, Ch>;
157
+ //#endregion
158
+ //#region src/api.d.ts
159
+ type Options$1 = {
160
+ workspace?: string;
161
+ apiKey?: string;
162
+ baseUrl?: string;
163
+ fetch?: typeof globalThis.fetch;
164
+ headers?: Record<string, string>;
165
+ };
166
+ declare class ApiClient {
167
+ private apiKey;
168
+ private baseUrl;
169
+ private _fetch;
170
+ private headers;
171
+ constructor({
172
+ baseUrl,
173
+ fetch: customFetch,
174
+ headers,
175
+ apiKey
176
+ }?: Options$1);
177
+ protected postJson(endpoint: string, payload: unknown): Promise<any>;
178
+ protected get(endpoint: string): Promise<any>;
179
+ listVaults(): Promise<ListVaultsResult>;
180
+ listUsers(): Promise<ListUsersResult>;
181
+ /**
182
+ * Applies an accounts specification to Zodiac OS.
183
+ */
184
+ applyConstellation(workspaceId: UUID, payload: ApplyConstellationPayload): Promise<ApplyConstellationResult>;
185
+ /**
186
+ * Resolves an accounts specification to Zodiac OS.
187
+ */
188
+ resolveConstellation(workspaceId: UUID, payload: ResolveConstellationPayload): Promise<ResolveConstellationResult>;
189
+ }
190
+ //#endregion
191
+ //#region src/apply.d.ts
192
+ type ApplyOpts = {
193
+ /** API client instance. Defaults to a client configured from environment variables. */api?: ApiClient;
194
+ };
195
+ /**
196
+ * Resolves node references and applies the constellation specification via the API.
197
+ *
198
+ *
199
+ * ```ts
200
+ * const eth = constellation({ workspace: 'GG', label: 'my constellation', chain: 1 })
201
+ * const dao = eth.safe['GG DAO']
202
+ * const roles = eth.roles['New Roles']({ nonce: 0n, target: dao, owner: dao, avatar: dao })
203
+ *
204
+ * await apply([dao, roles])
205
+ * ```
206
+ */
207
+ declare function apply(nodes: ConstellationNode[] | {
208
+ [key: string]: ConstellationNode;
209
+ }, opts?: ApplyOpts): Promise<ApplyConstellationResult[]>;
210
+ //#endregion
211
+ export { type ChainPrefix, type ConditionFunction, EVERYTHING, type FunctionPermission, type Options, type Scoping, type TargetPermission, apply, buildAllowKit, c, constellation, forAll };
212
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,208 @@
1
+ import { t as ApiClient } from "./api-D6ee2Q2b.mjs";
2
+ import { n as EVERYTHING, t as buildAllowKit } from "./allow-Dzh6t_l8.mjs";
3
+ import { createRequire } from "module";
4
+ import { invariant } from "@epic-web/invariant";
5
+ import { c, forAll } from "zodiac-roles-sdk";
6
+ //#region src/constellation.ts
7
+ function loadCodegen() {
8
+ return createRequire(import.meta.url)(".zodiac-os");
9
+ }
10
+ /**
11
+ * Creates a constellation scoped to a workspace and chain.
12
+ *
13
+ * Use bracket access to reference existing vaults or define new nodes:
14
+ * ```ts
15
+ * const eth = constellation({ workspace: 'GG', label: 'my constellation', chain: 1 })
16
+ *
17
+ * const dao = eth.safe['GG DAO'] // existing vault ref
18
+ * const roles = eth.roles['GG DAO'] // existing roles ref
19
+ * const newSafe = eth.safe['New Safe']({ nonce: 0n, threshold: 2, owners: [...], modules: [...] })
20
+ * ```
21
+ */
22
+ function constellation(opts, internal) {
23
+ const codegen = internal?.codegen ?? loadCodegen();
24
+ const ws = codegen.vaults[opts.workspace];
25
+ const vaultsByLabel = {};
26
+ if (ws) for (const [label, vault] of Object.entries(ws.vaults)) vaultsByLabel[label] = vault;
27
+ const meta = {
28
+ label: opts.label,
29
+ chain: opts.chain,
30
+ workspaceId: ws?.workspaceId ?? ""
31
+ };
32
+ const newSafes = /* @__PURE__ */ new Map();
33
+ function makeNodeRef(data) {
34
+ const ref = Object.freeze({
35
+ ...data,
36
+ chain: opts.chain,
37
+ _constellation: meta
38
+ });
39
+ if (ref.type === "SAFE" && typeof ref.label === "string") newSafes.set(ref.label, ref);
40
+ return ref;
41
+ }
42
+ function entityAccessor(registry, type, resolveCanonicalSafe) {
43
+ const cache = /* @__PURE__ */ new Map();
44
+ return new Proxy({}, { get(_target, name) {
45
+ if (typeof name !== "string") return void 0;
46
+ const cached = cache.get(name);
47
+ if (cached) return cached;
48
+ const existing = registry[name];
49
+ const fn = (overrides) => {
50
+ const canonicalSafe = resolveCanonicalSafe && !overrides?.target ? resolveCanonicalSafe(name) : void 0;
51
+ if (canonicalSafe) return makeNodeRef({
52
+ type,
53
+ nonce: 0n,
54
+ target: canonicalSafe,
55
+ owner: canonicalSafe,
56
+ avatar: canonicalSafe,
57
+ ...overrides,
58
+ label: name
59
+ });
60
+ return makeNodeRef({
61
+ type,
62
+ ...existing || {},
63
+ ...overrides,
64
+ label: name
65
+ });
66
+ };
67
+ Object.assign(fn, {
68
+ type,
69
+ ...existing || {},
70
+ label: name,
71
+ chain: opts.chain,
72
+ _constellation: meta
73
+ });
74
+ cache.set(name, fn);
75
+ return fn;
76
+ } });
77
+ }
78
+ function userAccessor() {
79
+ return new Proxy({}, { get(_target, name) {
80
+ const user = codegen.users[name];
81
+ if (!user) throw new Error(`Unknown user: ${name}`);
82
+ const personalSafe = user.personalSafes[opts.chain];
83
+ if (!personalSafe) throw new Error(`User ${name} has no personal safe on chain ${opts.chain}`);
84
+ return personalSafe.address;
85
+ } });
86
+ }
87
+ const safe = entityAccessor(vaultsByLabel, "SAFE");
88
+ return {
89
+ safe,
90
+ roles: entityAccessor(vaultsByLabel, "ROLES", (name) => {
91
+ const invoked = newSafes.get(name);
92
+ if (invoked) return invoked;
93
+ if (name in vaultsByLabel) return safe[name];
94
+ }),
95
+ user: userAccessor()
96
+ };
97
+ }
98
+ //#endregion
99
+ //#region src/apply.ts
100
+ /**
101
+ * Resolves node references and applies the constellation specification via the API.
102
+ *
103
+ *
104
+ * ```ts
105
+ * const eth = constellation({ workspace: 'GG', label: 'my constellation', chain: 1 })
106
+ * const dao = eth.safe['GG DAO']
107
+ * const roles = eth.roles['New Roles']({ nonce: 0n, target: dao, owner: dao, avatar: dao })
108
+ *
109
+ * await apply([dao, roles])
110
+ * ```
111
+ */
112
+ async function apply(nodes, opts) {
113
+ const api = opts?.api ?? new ApiClient();
114
+ const refs = deriveRefs(nodes);
115
+ const groups = /* @__PURE__ */ new Map();
116
+ for (const node of refs.byIdentity.keys()) {
117
+ const meta = node._constellation;
118
+ invariant(meta, `Node "${node.label}" is not associated with a constellation`);
119
+ const key = `${meta.workspaceId}:${meta.chain}:${meta.label}`;
120
+ let group = groups.get(key);
121
+ if (!group) {
122
+ group = {
123
+ meta,
124
+ nodes: []
125
+ };
126
+ groups.set(key, group);
127
+ }
128
+ group.nodes.push(node);
129
+ }
130
+ const results = [];
131
+ for (const { meta, nodes: groupNodes } of groups.values()) {
132
+ const specification = groupNodes.map((n) => nodeToSpec(n, refs));
133
+ const result = await api.applyConstellation(meta.workspaceId, {
134
+ label: meta.label,
135
+ chain: meta.chain,
136
+ specification
137
+ });
138
+ results.push(result);
139
+ }
140
+ return results;
141
+ }
142
+ function labelKey(node) {
143
+ return `${node._constellation.workspaceId}:${node.type}:${node.label}`;
144
+ }
145
+ function deriveRefs(nodes) {
146
+ const byIdentity = /* @__PURE__ */ new Map();
147
+ const byLabel = /* @__PURE__ */ new Map();
148
+ const register = (node, ref) => {
149
+ byIdentity.set(node, ref);
150
+ byLabel.set(labelKey(node), ref);
151
+ };
152
+ if (Array.isArray(nodes)) for (let i = 0; i < nodes.length; i++) {
153
+ const node = nodes[i];
154
+ invariant(isConstellationNode(node), `unexpected node input at index: ${i}`);
155
+ register(node, `${i}`);
156
+ }
157
+ else for (const [key, node] of Object.entries(nodes)) {
158
+ invariant(isConstellationNode(node), `unexpected node input under key: ${key}`);
159
+ register(node, key);
160
+ }
161
+ return {
162
+ byIdentity,
163
+ byLabel
164
+ };
165
+ }
166
+ function nodeToSpec(node, refs) {
167
+ const { id, _constellation, ...rest } = node;
168
+ const spec = {};
169
+ for (const [key, value] of Object.entries(rest)) spec[key] = resolveRefs(value, refs);
170
+ spec.ref = refs.byIdentity.get(node);
171
+ invariant(spec.ref != null, "ref not found");
172
+ return stringifyBigints(spec);
173
+ }
174
+ function resolveRefs(value, refs) {
175
+ if (isConstellationNode(value)) {
176
+ const ref = refs.byIdentity.get(value) ?? refs.byLabel.get(labelKey(value));
177
+ invariant(ref != null, `Node "${value.label}" is referenced not included in the apply() call`);
178
+ return `$${ref}`;
179
+ }
180
+ if (Array.isArray(value)) return value.map((v) => resolveRefs(v, refs));
181
+ if (typeof value === "object" && value !== null) {
182
+ const resolved = {};
183
+ for (const [k, v] of Object.entries(value)) resolved[k] = resolveRefs(v, refs);
184
+ return resolved;
185
+ }
186
+ return value;
187
+ }
188
+ function stringifyBigints(value) {
189
+ if (typeof value === "bigint") return value.toString();
190
+ if (Array.isArray(value)) return value.map(stringifyBigints);
191
+ if (typeof value === "object" && value !== null) {
192
+ const result = {};
193
+ for (const [k, v] of Object.entries(value)) result[k] = stringifyBigints(v);
194
+ return result;
195
+ }
196
+ return value;
197
+ }
198
+ function isConstellationNode(value) {
199
+ if (typeof value === "function" || typeof value === "object") {
200
+ const obj = value;
201
+ return obj != null && typeof obj.type === "string" && typeof obj.chain === "number" && typeof obj._constellation === "object";
202
+ }
203
+ return false;
204
+ }
205
+ //#endregion
206
+ export { EVERYTHING, apply, buildAllowKit, c, constellation, forAll };
207
+
208
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/constellation.ts","../src/apply.ts"],"sourcesContent":["/// <reference path=\"./zodiac-os-codegen.d.ts\" />\nimport type { Address, ChainId } from '@zodiac-os/api-types'\nimport type { AllowanceSpec, RoleSpec } from './types'\nimport { createRequire } from 'module'\nimport type * as ZodiacOsCodegen from '.zodiac-os'\nimport { UUID } from 'crypto'\n\ntype User = {\n id: UUID\n fullName: string\n personalSafes: Record<\n number,\n { address: Lowercase<Address>; active: boolean }\n >\n}\n\ntype Vault = {\n id: UUID\n label: string\n address: Lowercase<Address>\n chain: ChainId\n threshold: number\n owners: readonly string[]\n modules: readonly string[]\n}\n\ntype WorkspaceVaults = {\n workspaceId: UUID\n workspaceName: string\n vaults: Readonly<Record<string, Vault>>\n}\n\n/** Shape of the codegen data produced by `zodiac-os pull-org`. */\nexport type CodegenData = {\n users: Readonly<Record<string, User>>\n vaults: Readonly<Record<string, WorkspaceVaults>>\n}\n\ntype GeneratedCodegen = {\n users: typeof ZodiacOsCodegen.users\n vaults: typeof ZodiacOsCodegen.vaults\n}\n\ntype ConstellationOpts<C extends CodegenData> = {\n /** Workspace to scope vaults and roles to. */\n workspace: keyof C['vaults'] & string\n /** Human-readable label for this constellation. */\n label: string\n /** Target chain for all nodes in this constellation. */\n chain: ChainId\n}\n\ntype ConstellationInternalOpts<C extends CodegenData> = {\n /** Injected codegen data (used for testing). */\n codegen?: C\n}\n\ntype Prettify<T> = { readonly [K in keyof T]: T[K] } & {}\n\ntype WorkspaceVaultEntries<\n C extends CodegenData,\n W extends keyof C['vaults'],\n> = C['vaults'][W]['vaults']\n\ntype NodeType = 'SAFE' | 'ROLES' | 'DELAY'\n\n/** A reference to a node used in `owners`, `modules`, `target`, etc. */\ntype NodeRef = Readonly<{ type: NodeType; label: string; chain: ChainId }>\n\n/** A blockchain address or a reference to another node in the constellation. */\ntype AddressOrRef = Lowercase<Address> | NodeRef\n\ntype NodeBase = Readonly<{\n /** Human-readable identifier, unique within the constellation. */\n label: string\n /** Chain the node is deployed on. */\n chain: ChainId\n /** Set for existing nodes from codegen, absent for new nodes. */\n address?: Lowercase<Address>\n /** Deployment nonce — required for new nodes, optional for existing. */\n nonce?: bigint\n}>\n\n/** A safe node spec — existing vault ref or new safe with required config. */\nexport type SafeNode = NodeBase &\n Readonly<{\n /** Discriminator identifying this node as a Safe. */\n type: 'SAFE'\n /** Number of owner signatures required to execute a transaction. */\n threshold: number\n /** Safe owner addresses or node references. */\n owners: readonly (string | NodeRef)[]\n /** Module addresses or node references enabled on the safe. */\n modules?: readonly (string | NodeRef)[]\n /** Whether this safe shall appear as a vault in the workspace. @default false */\n vault?: boolean\n }>\n\n/** A roles modifier node spec — existing vault ref or new roles with modifier config. */\nexport type RolesNode = NodeBase &\n Readonly<{\n /** Discriminator identifying this node as a Roles modifier. */\n type: 'ROLES'\n /** The safe that this roles modifier controls. */\n target?: AddressOrRef\n /** The account that is allowed to update the configuration of the Roles mod. */\n owner?: AddressOrRef\n /** The account that calls will be executed from. */\n avatar?: AddressOrRef\n /** MultiSend contract addresses for batched transactions. */\n multisend?: readonly Lowercase<Address>[]\n /** Role definitions configured on this modifier. */\n roles?: readonly RoleSpec[]\n /** Spending allowances configured on this modifier. */\n allowances?: readonly AllowanceSpec[]\n }>\n\n/** Any complete node that can be passed to `apply()`. */\nexport type ConstellationNode = SafeNode | RolesNode\nexport type ConstellationNodeInternal = ConstellationNode & {\n _constellation: ConstellationMeta\n}\n\ntype NewSafeProps = {\n /** Deployment nonce for CREATE2 address derivation. */\n nonce: bigint\n /** Number of owner signatures required to execute a transaction. */\n threshold: number\n /** Safe owner addresses or node references. */\n owners: readonly AddressOrRef[]\n /** Module addresses or node references to enable on the safe. */\n modules?: readonly AddressOrRef[]\n /** Whether this safe is a workspace vault. @default false */\n vault?: boolean\n}\n\ntype NewRolesProps = {\n /** Deployment nonce for CREATE2 address derivation. Defaults to `0n` when omitted. */\n nonce?: bigint\n /** The safe that this roles modifier controls. Defaults to the new safe with the same label, when one exists. */\n target?: AddressOrRef\n /** The account that calls will be executed from. Defaults to `target` value */\n avatar?: AddressOrRef\n /** The account that is allowed to update the configuration of the Roles Mod. Defaults to `target` value */\n owner?: AddressOrRef\n /** MultiSend contract addresses for batched transactions. Defaults to `['0x38869bf66a61cf6bdb996a6ae40d5853fd43b526', '0x9641d764fc13c8b624c04430c7356c1c7c8102e2']` */\n multisend?: readonly Lowercase<Address>[]\n /** Role definitions to configure on this modifier. */\n roles?: readonly RoleSpec[]\n /** Spending allowances to configure on this modifier. */\n allowances?: readonly AllowanceSpec[]\n}\n\ntype EntityAccessor<\n Type extends string,\n Entries extends Record<string, any>,\n Ch extends ChainId = ChainId,\n NP extends Record<string, any> = Record<string, any>,\n> = {\n readonly [K in\n | (keyof Entries & string)\n | (string & {})]: K extends keyof Entries & string\n ? Readonly<Prettify<Entries[K] & { type: Type; label: K; chain: Ch }>> &\n (<\n O extends {\n [P in Exclude<keyof Entries[K] & string, 'id' | 'label'>]?: any\n } & Partial<NP> = {},\n >(\n overrides?: {\n [P in Exclude<keyof Entries[K] & string, 'id' | 'label'>]?: any\n } & Partial<NP> &\n O\n ) => Readonly<\n Prettify<\n Omit<Entries[K], keyof O> &\n O &\n Partial<NP> & { type: Type; label: K; chain: Ch }\n >\n >)\n : Readonly<Prettify<{ type: Type; label: string; chain: Ch }>> &\n ((\n props: NP\n ) => Readonly<Prettify<NP & { type: Type; label: string; chain: Ch }>>)\n}\n\ntype UserAccessor<C extends CodegenData, Ch extends number> = {\n readonly [K in keyof C['users'] &\n string]: C['users'][K]['personalSafes'][Ch]['address']\n}\n\ntype ConstellationResult<\n C extends CodegenData,\n W extends keyof C['vaults'] = keyof C['vaults'],\n Ch extends ChainId = ChainId,\n> = {\n /** Access existing safes by label or create new ones with a new label. */\n safe: EntityAccessor<'SAFE', WorkspaceVaultEntries<C, W>, Ch, NewSafeProps>\n /** Access existing roles modifiers by label or create new ones with a new label. */\n roles: EntityAccessor<'ROLES', WorkspaceVaultEntries<C, W>, Ch, NewRolesProps>\n /** Resolve a user's personal safe address on the constellation's chain. */\n user: UserAccessor<C, Ch>\n}\n\n/** @internal */\nexport type ConstellationMeta = {\n label: string\n chain: ChainId\n workspaceId: UUID\n}\n\nfunction loadCodegen(): CodegenData {\n const require = createRequire(import.meta.url)\n return require('.zodiac-os') as CodegenData\n}\n\n/**\n * Creates a constellation scoped to a workspace and chain.\n *\n * Use bracket access to reference existing vaults or define new nodes:\n * ```ts\n * const eth = constellation({ workspace: 'GG', label: 'my constellation', chain: 1 })\n *\n * const dao = eth.safe['GG DAO'] // existing vault ref\n * const roles = eth.roles['GG DAO'] // existing roles ref\n * const newSafe = eth.safe['New Safe']({ nonce: 0n, threshold: 2, owners: [...], modules: [...] })\n * ```\n */\nexport function constellation<\n const C extends CodegenData = GeneratedCodegen,\n const W extends keyof C['vaults'] & string = keyof C['vaults'] & string,\n const Ch extends ChainId = ChainId,\n>(\n opts: ConstellationOpts<C> & { workspace: W; chain: Ch },\n internal?: ConstellationInternalOpts<C>\n): ConstellationResult<C, W, Ch> {\n const codegen: CodegenData = internal?.codegen ?? loadCodegen()\n\n const ws = codegen.vaults[opts.workspace]\n const vaultsByLabel: Record<string, Vault> = {}\n if (ws) {\n for (const [label, vault] of Object.entries(ws.vaults)) {\n vaultsByLabel[label] = vault\n }\n }\n\n const meta: ConstellationMeta = {\n label: opts.label,\n chain: opts.chain,\n workspaceId: (ws?.workspaceId ?? '') as UUID,\n }\n\n const newSafes = new Map<string, Readonly<Record<string, any>>>()\n\n function makeNodeRef(\n data: Record<string, any>\n ): Readonly<Record<string, any>> {\n const ref: Record<string, any> = Object.freeze({\n ...data,\n chain: opts.chain,\n _constellation: meta,\n })\n if (ref.type === 'SAFE' && typeof ref.label === 'string') {\n newSafes.set(ref.label, ref)\n }\n return ref\n }\n\n function entityAccessor(\n registry: Record<string, Record<string, any>>,\n type: string,\n resolveCanonicalSafe?: (name: string) => Record<string, any> | undefined\n ) {\n const cache = new Map<string, Record<string, any>>()\n return new Proxy({} as Record<string, any>, {\n get(_target: any, name: string) {\n if (typeof name !== 'string') return undefined\n const cached = cache.get(name)\n if (cached) return cached\n const existing = registry[name]\n const fn = (overrides?: Record<string, any>) => {\n const canonicalSafe =\n resolveCanonicalSafe && !overrides?.target\n ? resolveCanonicalSafe(name)\n : undefined\n if (canonicalSafe) {\n return makeNodeRef({\n type,\n nonce: 0n,\n target: canonicalSafe,\n owner: canonicalSafe,\n avatar: canonicalSafe,\n ...overrides,\n label: name,\n })\n }\n return makeNodeRef({\n type,\n ...(existing || {}),\n ...overrides,\n label: name,\n })\n }\n Object.assign(fn, {\n type,\n ...(existing || {}),\n label: name,\n chain: opts.chain,\n _constellation: meta,\n })\n cache.set(name, fn)\n return fn\n },\n })\n }\n\n function userAccessor() {\n return new Proxy(\n {},\n {\n get(_target: any, name: string) {\n const user = codegen.users[name]\n if (!user) throw new Error(`Unknown user: ${name}`)\n const personalSafe = user.personalSafes[opts.chain]\n if (!personalSafe) {\n throw new Error(\n `User ${name} has no personal safe on chain ${opts.chain}`\n )\n }\n return personalSafe.address\n },\n }\n )\n }\n\n const safe = entityAccessor(vaultsByLabel, 'SAFE')\n const roles = entityAccessor(vaultsByLabel, 'ROLES', (name) => {\n const invoked = newSafes.get(name)\n if (invoked) return invoked\n if (name in vaultsByLabel) return safe[name]\n return undefined\n })\n\n return {\n safe,\n roles,\n user: userAccessor(),\n } as ConstellationResult<C, W, Ch>\n}\n","import type {\n ApplyConstellationPayload,\n ApplyConstellationResult,\n} from '@zodiac-os/api-types'\nimport { invariant } from '@epic-web/invariant'\nimport { ApiClient } from './api'\nimport type {\n ConstellationMeta,\n ConstellationNode,\n ConstellationNodeInternal,\n} from './constellation'\n\ntype ApplyOpts = {\n /** API client instance. Defaults to a client configured from environment variables. */\n api?: ApiClient\n}\n\n/**\n * Resolves node references and applies the constellation specification via the API.\n *\n *\n * ```ts\n * const eth = constellation({ workspace: 'GG', label: 'my constellation', chain: 1 })\n * const dao = eth.safe['GG DAO']\n * const roles = eth.roles['New Roles']({ nonce: 0n, target: dao, owner: dao, avatar: dao })\n *\n * await apply([dao, roles])\n * ```\n */\nexport async function apply(\n nodes: ConstellationNode[] | { [key: string]: ConstellationNode },\n opts?: ApplyOpts\n): Promise<ApplyConstellationResult[]> {\n const api = opts?.api ?? new ApiClient()\n const refs = deriveRefs(nodes)\n\n // Group nodes by constellation (multiple constellations can be applied with a single call)\n const groups = new Map<\n string,\n { meta: ConstellationMeta; nodes: ConstellationNodeInternal[] }\n >()\n\n for (const node of refs.byIdentity.keys()) {\n const meta = node._constellation\n invariant(\n meta,\n `Node \"${node.label}\" is not associated with a constellation`\n )\n const key = `${meta.workspaceId}:${meta.chain}:${meta.label}`\n let group = groups.get(key)\n if (!group) {\n group = { meta, nodes: [] }\n groups.set(key, group)\n }\n group.nodes.push(node)\n }\n\n const results: ApplyConstellationResult[] = []\n for (const { meta, nodes: groupNodes } of groups.values()) {\n const specification = groupNodes.map((n) => nodeToSpec(n, refs))\n const result = await api.applyConstellation(meta.workspaceId, {\n label: meta.label,\n chain: meta.chain,\n specification,\n })\n results.push(result)\n }\n\n return results\n}\n\ntype RefsIndex = {\n byIdentity: Map<ConstellationNodeInternal, string>\n byLabel: Map<string, string>\n}\n\nfunction labelKey(node: ConstellationNodeInternal): string {\n return `${node._constellation.workspaceId}:${node.type}:${node.label}`\n}\n\nfunction deriveRefs(\n nodes: ConstellationNode[] | { [key: string]: ConstellationNode }\n): RefsIndex {\n const byIdentity = new Map<ConstellationNodeInternal, string>()\n const byLabel = new Map<string, string>()\n\n const register = (node: ConstellationNodeInternal, ref: string) => {\n byIdentity.set(node, ref)\n byLabel.set(labelKey(node), ref)\n }\n\n if (Array.isArray(nodes)) {\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i]\n invariant(\n isConstellationNode(node),\n `unexpected node input at index: ${i}`\n )\n register(node, `${i}`)\n }\n } else {\n for (const [key, node] of Object.entries(nodes)) {\n invariant(\n isConstellationNode(node),\n `unexpected node input under key: ${key}`\n )\n register(node, key)\n }\n }\n\n return { byIdentity, byLabel }\n}\n\nfunction nodeToSpec(\n node: ConstellationNodeInternal,\n refs: RefsIndex\n): ApplyConstellationPayload['specification'][number] {\n const { id, _constellation, ...rest } = node as Record<string, any>\n const spec: Record<string, any> = {}\n\n for (const [key, value] of Object.entries(rest)) {\n spec[key] = resolveRefs(value, refs)\n }\n\n spec.ref = refs.byIdentity.get(node)\n invariant(spec.ref != null, 'ref not found')\n\n return stringifyBigints(\n spec\n ) as ApplyConstellationPayload['specification'][number]\n}\n\nfunction resolveRefs(value: unknown, refs: RefsIndex): unknown {\n if (isConstellationNode(value)) {\n const ref = refs.byIdentity.get(value) ?? refs.byLabel.get(labelKey(value))\n invariant(\n ref != null,\n `Node \"${value.label}\" is referenced not included in the apply() call`\n )\n return `$${ref}`\n }\n\n if (Array.isArray(value)) {\n return value.map((v) => resolveRefs(v, refs))\n }\n\n if (typeof value === 'object' && value !== null) {\n const resolved: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value)) {\n resolved[k] = resolveRefs(v, refs)\n }\n return resolved\n }\n\n return value\n}\n\nfunction stringifyBigints(value: unknown): unknown {\n if (typeof value === 'bigint') {\n return value.toString()\n }\n\n if (Array.isArray(value)) {\n return value.map(stringifyBigints)\n }\n\n if (typeof value === 'object' && value !== null) {\n const result: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value)) {\n result[k] = stringifyBigints(v)\n }\n return result\n }\n\n return value\n}\n\nfunction isConstellationNode(\n value: unknown\n): value is ConstellationNodeInternal {\n if (typeof value === 'function' || typeof value === 'object') {\n const obj = value as any\n return (\n obj != null &&\n typeof obj.type === 'string' &&\n typeof obj.chain === 'number' &&\n typeof obj._constellation === 'object'\n )\n }\n return false\n}\n"],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ //#region src/allow/abi.ts
4
+ function* walkContracts(config) {
5
+ for (const [chain, contracts] of Object.entries(config)) yield* walkLevel(chain, [], contracts);
6
+ }
7
+ function* walkLevel(chain, segments, node) {
8
+ if (typeof node === "string") {
9
+ if (segments.length === 0) throw new Error(`Contract at ${chain} is missing a name`);
10
+ if (!node.startsWith("0x")) throw new Error(`Invalid address for ${chain}.${segments.join(".")}: ${node}`);
11
+ yield {
12
+ chain,
13
+ segments,
14
+ address: node
15
+ };
16
+ return;
17
+ }
18
+ if (node && typeof node === "object") {
19
+ for (const [key, value] of Object.entries(node)) yield* walkLevel(chain, [...segments, key], value);
20
+ return;
21
+ }
22
+ throw new Error(`Invalid contracts entry at ${chain}.${segments.join(".")}: ${JSON.stringify(node)}`);
23
+ }
24
+ const abiFilePath = (abisDir, node) => path.join(abisDir, node.chain, ...node.segments) + ".json";
25
+ const readAbi = (abisDir, node) => {
26
+ const file = abiFilePath(abisDir, node);
27
+ if (!fs.existsSync(file)) return null;
28
+ const raw = fs.readFileSync(file, "utf8");
29
+ const parsed = JSON.parse(raw);
30
+ if (!Array.isArray(parsed)) throw new Error(`ABI at ${file} is not a JSON array`);
31
+ return parsed;
32
+ };
33
+ const writeAbi = (abisDir, node, abi) => {
34
+ const file = abiFilePath(abisDir, node);
35
+ fs.mkdirSync(path.dirname(file), { recursive: true });
36
+ fs.writeFileSync(file, JSON.stringify(abi, null, 2) + "\n", "utf8");
37
+ };
38
+ //#endregion
39
+ //#region src/allow/networks.ts
40
+ const CHAIN_IDS = {
41
+ eth: 1,
42
+ oeth: 10,
43
+ gno: 100,
44
+ sep: 11155111,
45
+ matic: 137,
46
+ zkevm: 1101,
47
+ arb1: 42161,
48
+ avax: 43114,
49
+ base: 8453,
50
+ basesep: 84532,
51
+ bnb: 56,
52
+ celo: 42220,
53
+ sonic: 146,
54
+ berachain: 80094,
55
+ unichain: 130,
56
+ worldchain: 480,
57
+ bob: 60808,
58
+ mantle: 5e3,
59
+ hemi: 43111,
60
+ katana: 747474,
61
+ linea: 59144,
62
+ ink: 57073,
63
+ hyperevm: 999,
64
+ flare: 14,
65
+ scroll: 534352,
66
+ plasma: 9745,
67
+ megaeth: 4326
68
+ };
69
+ const chainIdFor = (prefix) => {
70
+ const id = CHAIN_IDS[prefix];
71
+ if (id === void 0) throw new Error(`Unknown chain prefix: ${prefix}`);
72
+ return id;
73
+ };
74
+ //#endregion
75
+ export { walkContracts as a, readAbi as i, chainIdFor as n, writeAbi as o, abiFilePath as r, CHAIN_IDS as t };
76
+
77
+ //# sourceMappingURL=networks-BTW1qAAa.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"networks-BTW1qAAa.mjs","names":[],"sources":["../src/allow/abi.ts","../src/allow/networks.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport type { Abi } from './fetch'\n\nexport type ContractAddress = `0x${string}`\n\nexport type ContractNode = {\n chain: string\n segments: string[]\n address: ContractAddress\n}\n\nexport function* walkContracts(\n config: Record<string, any>\n): Generator<ContractNode> {\n for (const [chain, contracts] of Object.entries(config)) {\n yield* walkLevel(chain, [], contracts)\n }\n}\n\nfunction* walkLevel(\n chain: string,\n segments: string[],\n node: unknown\n): Generator<ContractNode> {\n if (typeof node === 'string') {\n if (segments.length === 0) {\n throw new Error(`Contract at ${chain} is missing a name`)\n }\n if (!node.startsWith('0x')) {\n throw new Error(\n `Invalid address for ${chain}.${segments.join('.')}: ${node}`\n )\n }\n yield { chain, segments, address: node as ContractAddress }\n return\n }\n if (node && typeof node === 'object') {\n for (const [key, value] of Object.entries(node as Record<string, any>)) {\n yield* walkLevel(chain, [...segments, key], value)\n }\n return\n }\n throw new Error(\n `Invalid contracts entry at ${chain}.${segments.join('.')}: ${JSON.stringify(node)}`\n )\n}\n\nexport const abiFilePath = (abisDir: string, node: ContractNode): string =>\n path.join(abisDir, node.chain, ...node.segments) + '.json'\n\nexport const readAbi = (abisDir: string, node: ContractNode): Abi | null => {\n const file = abiFilePath(abisDir, node)\n if (!fs.existsSync(file)) return null\n const raw = fs.readFileSync(file, 'utf8')\n const parsed = JSON.parse(raw)\n if (!Array.isArray(parsed)) {\n throw new Error(`ABI at ${file} is not a JSON array`)\n }\n return parsed as Abi\n}\n\nexport const writeAbi = (\n abisDir: string,\n node: ContractNode,\n abi: Abi\n): void => {\n const file = abiFilePath(abisDir, node)\n fs.mkdirSync(path.dirname(file), { recursive: true })\n fs.writeFileSync(file, JSON.stringify(abi, null, 2) + '\\n', 'utf8')\n}\n","export const CHAIN_IDS = {\n eth: 1,\n oeth: 10,\n gno: 100,\n sep: 11155111,\n matic: 137,\n zkevm: 1101,\n arb1: 42161,\n avax: 43114,\n base: 8453,\n basesep: 84532,\n bnb: 56,\n celo: 42220,\n sonic: 146,\n berachain: 80094,\n unichain: 130,\n worldchain: 480,\n bob: 60808,\n mantle: 5000,\n hemi: 43111,\n katana: 747474,\n linea: 59144,\n ink: 57073,\n hyperevm: 999,\n flare: 14,\n scroll: 534352,\n plasma: 9745,\n megaeth: 4326,\n} as const satisfies Record<string, number>\n\nexport type ChainPrefix = keyof typeof CHAIN_IDS\n\nexport const chainIdFor = (prefix: string): number => {\n const id = (CHAIN_IDS as Record<string, number>)[prefix]\n if (id === undefined) {\n throw new Error(`Unknown chain prefix: ${prefix}`)\n }\n return id\n}\n"],"mappings":";;;AAYA,UAAiB,cACf,QACyB;AACzB,MAAK,MAAM,CAAC,OAAO,cAAc,OAAO,QAAQ,OAAO,CACrD,QAAO,UAAU,OAAO,EAAE,EAAE,UAAU;;AAI1C,UAAU,UACR,OACA,UACA,MACyB;AACzB,KAAI,OAAO,SAAS,UAAU;AAC5B,MAAI,SAAS,WAAW,EACtB,OAAM,IAAI,MAAM,eAAe,MAAM,oBAAoB;AAE3D,MAAI,CAAC,KAAK,WAAW,KAAK,CACxB,OAAM,IAAI,MACR,uBAAuB,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,IAAI,OACxD;AAEH,QAAM;GAAE;GAAO;GAAU,SAAS;GAAyB;AAC3D;;AAEF,KAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAA4B,CACpE,QAAO,UAAU,OAAO,CAAC,GAAG,UAAU,IAAI,EAAE,MAAM;AAEpD;;AAEF,OAAM,IAAI,MACR,8BAA8B,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,IAAI,KAAK,UAAU,KAAK,GACnF;;AAGH,MAAa,eAAe,SAAiB,SAC3C,KAAK,KAAK,SAAS,KAAK,OAAO,GAAG,KAAK,SAAS,GAAG;AAErD,MAAa,WAAW,SAAiB,SAAmC;CAC1E,MAAM,OAAO,YAAY,SAAS,KAAK;AACvC,KAAI,CAAC,GAAG,WAAW,KAAK,CAAE,QAAO;CACjC,MAAM,MAAM,GAAG,aAAa,MAAM,OAAO;CACzC,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,KAAI,CAAC,MAAM,QAAQ,OAAO,CACxB,OAAM,IAAI,MAAM,UAAU,KAAK,sBAAsB;AAEvD,QAAO;;AAGT,MAAa,YACX,SACA,MACA,QACS;CACT,MAAM,OAAO,YAAY,SAAS,KAAK;AACvC,IAAG,UAAU,KAAK,QAAQ,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AACrD,IAAG,cAAc,MAAM,KAAK,UAAU,KAAK,MAAM,EAAE,GAAG,MAAM,OAAO;;;;ACrErE,MAAa,YAAY;CACvB,KAAK;CACL,MAAM;CACN,KAAK;CACL,KAAK;CACL,OAAO;CACP,OAAO;CACP,MAAM;CACN,MAAM;CACN,MAAM;CACN,SAAS;CACT,KAAK;CACL,MAAM;CACN,OAAO;CACP,WAAW;CACX,UAAU;CACV,YAAY;CACZ,KAAK;CACL,QAAQ;CACR,MAAM;CACN,QAAQ;CACR,OAAO;CACP,KAAK;CACL,UAAU;CACV,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,SAAS;CACV;AAID,MAAa,cAAc,WAA2B;CACpD,MAAM,KAAM,UAAqC;AACjD,KAAI,OAAO,KAAA,EACT,OAAM,IAAI,MAAM,yBAAyB,SAAS;AAEpD,QAAO"}
@@ -0,0 +1,52 @@
1
+ // Fallback ambient declarations for the .zodiac-os codegen module and for
2
+ // the AllowKit interface. When `pull-org` / `pull-contracts` have been run,
3
+ // the files under node_modules/.zodiac-os/ provide narrow types that take
4
+ // precedence over these empty fallbacks.
5
+
6
+ declare global {
7
+ // Augmented by node_modules/.zodiac-os/allow.d.ts when `pull-contracts` runs.
8
+ interface AllowKit {}
9
+ }
10
+
11
+ declare module '.zodiac-os' {
12
+ import { Address, ChainId } from '@zodiac-os/api-types'
13
+ import { UUID } from 'crypto'
14
+
15
+ export const users: Readonly<
16
+ Record<
17
+ string,
18
+ {
19
+ id: UUID
20
+ fullName: string
21
+ personalSafes: Record<
22
+ number,
23
+ { address: Lowercase<Address>; active: boolean }
24
+ >
25
+ }
26
+ >
27
+ >
28
+
29
+ export const vaults: Readonly<
30
+ Record<
31
+ string,
32
+ {
33
+ workspaceId: UUID
34
+ workspaceName: string
35
+ vaults: Readonly<
36
+ Record<
37
+ string,
38
+ {
39
+ id: UUID
40
+ label: string
41
+ address: Lowercase<Address>
42
+ chain: ChainId
43
+ threshold: number
44
+ owners: readonly string[]
45
+ modules: readonly string[]
46
+ }
47
+ >
48
+ >
49
+ }
50
+ >
51
+ >
52
+ }