@zodiac-os/sdk 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/dist/allow/index.d.mts +2 -0
- package/dist/allow/index.mjs +3 -0
- package/dist/allow-Dzh6t_l8.mjs +122 -0
- package/dist/allow-Dzh6t_l8.mjs.map +1 -0
- package/dist/cli/config.d.mts +35 -0
- package/dist/cli/config.mjs +31 -0
- package/dist/cli/config.mjs.map +1 -0
- package/dist/cli.mjs +224 -35
- package/dist/cli.mjs.map +1 -1
- package/dist/index-DTBaxN7b.d.mts +63 -0
- package/dist/index.d.mts +40 -29
- package/dist/index.mjs +70 -19
- package/dist/index.mjs.map +1 -1
- package/dist/networks-BTW1qAAa.mjs +77 -0
- package/dist/networks-BTW1qAAa.mjs.map +1 -0
- package/dist/zodiac-os-codegen.d.ts +10 -3
- package/package.json +25 -12
|
@@ -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-DTBaxN7b.d.mts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference path="./zodiac-os-codegen.d.ts" />
|
|
2
|
-
import { EVERYTHING,
|
|
3
|
-
import { c, forAll } from "zodiac-roles-sdk";
|
|
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 { Annotation, Permission, PermissionSet, c, forAll } from "zodiac-roles-sdk";
|
|
4
4
|
import { Address, ApplyConstellationPayload, ApplyConstellationResult, ChainId, ListUsersResult, ListVaultsResult, ResolveConstellationPayload, ResolveConstellationResult } from "@zodiac-os/api-types";
|
|
5
5
|
import * as ZodiacOsCodegen from ".zodiac-os";
|
|
6
6
|
import { UUID } from "crypto";
|
|
@@ -11,17 +11,24 @@ type ApiNewRolesSpec = Extract<ApplyConstellationPayload['specification'][number
|
|
|
11
11
|
nonce: string;
|
|
12
12
|
}>;
|
|
13
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
14
|
/** An allowance definition in the API's serialized format (bigints as template literal strings). */
|
|
16
15
|
type ApiAllowanceSpec = Extract<NonNullable<ApiNewRolesSpec['allowances']>, readonly any[]>[number];
|
|
17
16
|
/** Recursively converts `${bigint}` template literal strings to `bigint`. */
|
|
18
17
|
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
18
|
/** A role definition with bigint fields as actual bigints. */
|
|
20
|
-
type RoleSpec = RealBigints<ApiRoleSpec>;
|
|
21
19
|
/** An allowance definition with bigint fields as actual bigints. */
|
|
22
20
|
type AllowanceSpec = RealBigints<ApiAllowanceSpec>;
|
|
23
21
|
//#endregion
|
|
24
22
|
//#region src/constellation.d.ts
|
|
23
|
+
/**
|
|
24
|
+
* A role definition keyed by role name. Permissions are expanded into
|
|
25
|
+
* `{ targets, annotations }` via `processPermissions` at `apply()` time.
|
|
26
|
+
*/
|
|
27
|
+
type RoleDef = {
|
|
28
|
+
members: readonly AddressOrRef[];
|
|
29
|
+
permissions: readonly (Permission | PermissionSet | Promise<PermissionSet>)[];
|
|
30
|
+
annotations?: readonly Annotation[];
|
|
31
|
+
};
|
|
25
32
|
type User = {
|
|
26
33
|
id: UUID;
|
|
27
34
|
fullName: string;
|
|
@@ -70,30 +77,32 @@ type NodeRef = Readonly<{
|
|
|
70
77
|
label: string;
|
|
71
78
|
chain: ChainId;
|
|
72
79
|
}>;
|
|
73
|
-
/** A blockchain address or a reference to another
|
|
74
|
-
|
|
80
|
+
/** A blockchain address (checksummed or lowercase) or a reference to another
|
|
81
|
+
* node in the constellation. Values are normalized to lowercase before being
|
|
82
|
+
* sent to the API. */
|
|
83
|
+
type AddressOrRef = Address | NodeRef;
|
|
75
84
|
type NodeBase = Readonly<{
|
|
76
|
-
label: string;
|
|
85
|
+
/** Human-readable identifier, unique within the constellation. */label: string; /** Chain the node is deployed on. */
|
|
77
86
|
chain: ChainId; /** Set for existing nodes from codegen, absent for new nodes. */
|
|
78
87
|
address?: Lowercase<Address>; /** Deployment nonce — required for new nodes, optional for existing. */
|
|
79
88
|
nonce?: bigint;
|
|
80
89
|
}>;
|
|
81
90
|
/** A safe node spec — existing vault ref or new safe with required config. */
|
|
82
91
|
type SafeNode = NodeBase & Readonly<{
|
|
83
|
-
type: 'SAFE';
|
|
84
|
-
threshold: number;
|
|
85
|
-
owners: readonly (string | NodeRef)[];
|
|
86
|
-
modules?: readonly (string | NodeRef)[];
|
|
92
|
+
/** Discriminator identifying this node as a Safe. */type: 'SAFE'; /** Number of owner signatures required to execute a transaction. */
|
|
93
|
+
threshold: number; /** Safe owner addresses or node references. */
|
|
94
|
+
owners: readonly (string | NodeRef)[]; /** Module addresses or node references enabled on the safe. */
|
|
95
|
+
modules?: readonly (string | NodeRef)[]; /** Whether this safe shall appear as a vault in the workspace. @default false */
|
|
87
96
|
vault?: boolean;
|
|
88
97
|
}>;
|
|
89
98
|
/** A roles modifier node spec — existing vault ref or new roles with modifier config. */
|
|
90
99
|
type RolesNode = NodeBase & Readonly<{
|
|
91
|
-
type: 'ROLES';
|
|
92
|
-
target?: AddressOrRef;
|
|
93
|
-
owner?: AddressOrRef;
|
|
94
|
-
avatar?: AddressOrRef;
|
|
95
|
-
multisend?: readonly
|
|
96
|
-
roles?:
|
|
100
|
+
/** Discriminator identifying this node as a Roles modifier. */type: 'ROLES'; /** The safe that this roles modifier controls. */
|
|
101
|
+
target?: AddressOrRef; /** The account that is allowed to update the configuration of the Roles mod. */
|
|
102
|
+
owner?: AddressOrRef; /** The account that calls will be executed from. */
|
|
103
|
+
avatar?: AddressOrRef; /** MultiSend contract addresses for batched transactions. */
|
|
104
|
+
multisend?: readonly Address[]; /** Role definitions configured on this modifier. */
|
|
105
|
+
roles?: Record<string, RoleDef>; /** Spending allowances configured on this modifier. */
|
|
97
106
|
allowances?: readonly AllowanceSpec[];
|
|
98
107
|
}>;
|
|
99
108
|
/** Any complete node that can be passed to `apply()`. */
|
|
@@ -106,29 +115,31 @@ type NewSafeProps = {
|
|
|
106
115
|
vault?: boolean;
|
|
107
116
|
};
|
|
108
117
|
type NewRolesProps = {
|
|
109
|
-
/** Deployment nonce for CREATE2 address derivation. */nonce
|
|
110
|
-
target
|
|
118
|
+
/** 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. */
|
|
119
|
+
target?: AddressOrRef; /** The account that calls will be executed from. Defaults to `target` value */
|
|
111
120
|
avatar?: AddressOrRef; /** The account that is allowed to update the configuration of the Roles Mod. Defaults to `target` value */
|
|
112
121
|
owner?: AddressOrRef; /** MultiSend contract addresses for batched transactions. Defaults to `['0x38869bf66a61cf6bdb996a6ae40d5853fd43b526', '0x9641d764fc13c8b624c04430c7356c1c7c8102e2']` */
|
|
113
|
-
multisend?: readonly
|
|
114
|
-
roles?:
|
|
122
|
+
multisend?: readonly Address[]; /** Role definitions to configure on this modifier. */
|
|
123
|
+
roles?: Record<string, RoleDef>; /** Spending allowances to configure on this modifier. */
|
|
115
124
|
allowances?: readonly AllowanceSpec[];
|
|
116
125
|
};
|
|
117
126
|
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
127
|
type: Type;
|
|
119
128
|
label: K;
|
|
120
129
|
chain: Ch;
|
|
121
|
-
}>> & (<O extends { [P in Exclude<keyof Entries[K] & string, 'id' | 'label'>]?: any } = {}>(overrides?: { [P in Exclude<keyof Entries[K] & string, 'id' | 'label'>]?: any } & O) => Readonly<Prettify<Omit<Entries[K], keyof O> & O & {
|
|
130
|
+
}>> & (<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
131
|
type: Type;
|
|
123
132
|
label: K;
|
|
124
133
|
chain: Ch;
|
|
125
|
-
}>>) : <
|
|
126
|
-
|
|
127
|
-
|
|
134
|
+
}>>) : Readonly<Prettify<{
|
|
135
|
+
type: Type;
|
|
136
|
+
label: string;
|
|
137
|
+
chain: Ch;
|
|
138
|
+
}>> & ((props: NP) => Readonly<Prettify<NP & {
|
|
128
139
|
type: Type;
|
|
129
140
|
label: string;
|
|
130
141
|
chain: Ch;
|
|
131
|
-
}>> };
|
|
142
|
+
}>>) };
|
|
132
143
|
type UserAccessor<C extends CodegenData, Ch extends number> = { readonly [K in keyof C['users'] & string]: C['users'][K]['personalSafes'][Ch]['address'] };
|
|
133
144
|
type ConstellationResult<C extends CodegenData, W extends keyof C['vaults'] = keyof C['vaults'], Ch extends ChainId = ChainId> = {
|
|
134
145
|
/** 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. */
|
|
@@ -154,7 +165,7 @@ declare function constellation<const C extends CodegenData = GeneratedCodegen, c
|
|
|
154
165
|
}, internal?: ConstellationInternalOpts<C>): ConstellationResult<C, W, Ch>;
|
|
155
166
|
//#endregion
|
|
156
167
|
//#region src/api.d.ts
|
|
157
|
-
type Options = {
|
|
168
|
+
type Options$1 = {
|
|
158
169
|
workspace?: string;
|
|
159
170
|
apiKey?: string;
|
|
160
171
|
baseUrl?: string;
|
|
@@ -171,7 +182,7 @@ declare class ApiClient {
|
|
|
171
182
|
fetch: customFetch,
|
|
172
183
|
headers,
|
|
173
184
|
apiKey
|
|
174
|
-
}?: Options);
|
|
185
|
+
}?: Options$1);
|
|
175
186
|
protected postJson(endpoint: string, payload: unknown): Promise<any>;
|
|
176
187
|
protected get(endpoint: string): Promise<any>;
|
|
177
188
|
listVaults(): Promise<ListVaultsResult>;
|
|
@@ -206,5 +217,5 @@ declare function apply(nodes: ConstellationNode[] | {
|
|
|
206
217
|
[key: string]: ConstellationNode;
|
|
207
218
|
}, opts?: ApplyOpts): Promise<ApplyConstellationResult[]>;
|
|
208
219
|
//#endregion
|
|
209
|
-
export { EVERYTHING,
|
|
220
|
+
export { type ChainPrefix, type ConditionFunction, EVERYTHING, type FunctionPermission, type Options, type Scoping, type TargetPermission, apply, buildAllowKit, c, constellation, forAll };
|
|
210
221
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as ApiClient } from "./api-D6ee2Q2b.mjs";
|
|
2
|
+
import { n as EVERYTHING, t as buildAllowKit } from "./allow-Dzh6t_l8.mjs";
|
|
2
3
|
import { createRequire } from "module";
|
|
3
4
|
import { invariant } from "@epic-web/invariant";
|
|
4
|
-
import {
|
|
5
|
-
import { c, forAll } from "zodiac-roles-sdk";
|
|
5
|
+
import { c, forAll, processPermissions } from "zodiac-roles-sdk";
|
|
6
6
|
//#region src/constellation.ts
|
|
7
7
|
function loadCodegen() {
|
|
8
8
|
return createRequire(import.meta.url)(".zodiac-os");
|
|
@@ -29,18 +29,34 @@ function constellation(opts, internal) {
|
|
|
29
29
|
chain: opts.chain,
|
|
30
30
|
workspaceId: ws?.workspaceId ?? ""
|
|
31
31
|
};
|
|
32
|
+
const newSafes = /* @__PURE__ */ new Map();
|
|
32
33
|
function makeNodeRef(data) {
|
|
33
|
-
|
|
34
|
+
const ref = Object.freeze({
|
|
34
35
|
...data,
|
|
35
36
|
chain: opts.chain,
|
|
36
37
|
_constellation: meta
|
|
37
38
|
});
|
|
39
|
+
if (ref.type === "SAFE" && typeof ref.label === "string") newSafes.set(ref.label, ref);
|
|
40
|
+
return ref;
|
|
38
41
|
}
|
|
39
|
-
function entityAccessor(registry, type) {
|
|
42
|
+
function entityAccessor(registry, type, resolveCanonicalSafe) {
|
|
43
|
+
const cache = /* @__PURE__ */ new Map();
|
|
40
44
|
return new Proxy({}, { get(_target, name) {
|
|
41
45
|
if (typeof name !== "string") return void 0;
|
|
46
|
+
const cached = cache.get(name);
|
|
47
|
+
if (cached) return cached;
|
|
42
48
|
const existing = registry[name];
|
|
43
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
|
+
});
|
|
44
60
|
return makeNodeRef({
|
|
45
61
|
type,
|
|
46
62
|
...existing || {},
|
|
@@ -48,13 +64,14 @@ function constellation(opts, internal) {
|
|
|
48
64
|
label: name
|
|
49
65
|
});
|
|
50
66
|
};
|
|
51
|
-
|
|
67
|
+
Object.assign(fn, {
|
|
52
68
|
type,
|
|
53
|
-
...existing,
|
|
69
|
+
...existing || {},
|
|
54
70
|
label: name,
|
|
55
71
|
chain: opts.chain,
|
|
56
72
|
_constellation: meta
|
|
57
73
|
});
|
|
74
|
+
cache.set(name, fn);
|
|
58
75
|
return fn;
|
|
59
76
|
} });
|
|
60
77
|
}
|
|
@@ -67,9 +84,14 @@ function constellation(opts, internal) {
|
|
|
67
84
|
return personalSafe.address;
|
|
68
85
|
} });
|
|
69
86
|
}
|
|
87
|
+
const safe = entityAccessor(vaultsByLabel, "SAFE");
|
|
70
88
|
return {
|
|
71
|
-
safe
|
|
72
|
-
roles: entityAccessor(vaultsByLabel, "ROLES")
|
|
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
|
+
}),
|
|
73
95
|
user: userAccessor()
|
|
74
96
|
};
|
|
75
97
|
}
|
|
@@ -91,7 +113,7 @@ async function apply(nodes, opts) {
|
|
|
91
113
|
const api = opts?.api ?? new ApiClient();
|
|
92
114
|
const refs = deriveRefs(nodes);
|
|
93
115
|
const groups = /* @__PURE__ */ new Map();
|
|
94
|
-
for (const node of refs.keys()) {
|
|
116
|
+
for (const node of refs.byIdentity.keys()) {
|
|
95
117
|
const meta = node._constellation;
|
|
96
118
|
invariant(meta, `Node "${node.label}" is not associated with a constellation`);
|
|
97
119
|
const key = `${meta.workspaceId}:${meta.chain}:${meta.label}`;
|
|
@@ -107,7 +129,7 @@ async function apply(nodes, opts) {
|
|
|
107
129
|
}
|
|
108
130
|
const results = [];
|
|
109
131
|
for (const { meta, nodes: groupNodes } of groups.values()) {
|
|
110
|
-
const specification = groupNodes.map((n) => nodeToSpec(n, refs));
|
|
132
|
+
const specification = await Promise.all(groupNodes.map((n) => nodeToSpec(n, refs)));
|
|
111
133
|
const result = await api.applyConstellation(meta.workspaceId, {
|
|
112
134
|
label: meta.label,
|
|
113
135
|
chain: meta.chain,
|
|
@@ -117,30 +139,58 @@ async function apply(nodes, opts) {
|
|
|
117
139
|
}
|
|
118
140
|
return results;
|
|
119
141
|
}
|
|
142
|
+
function labelKey(node) {
|
|
143
|
+
return `${node._constellation.workspaceId}:${node.type}:${node.label}`;
|
|
144
|
+
}
|
|
120
145
|
function deriveRefs(nodes) {
|
|
121
|
-
const
|
|
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
|
+
};
|
|
122
152
|
if (Array.isArray(nodes)) for (let i = 0; i < nodes.length; i++) {
|
|
123
153
|
const node = nodes[i];
|
|
124
154
|
invariant(isConstellationNode(node), `unexpected node input at index: ${i}`);
|
|
125
|
-
|
|
155
|
+
register(node, `${i}`);
|
|
126
156
|
}
|
|
127
157
|
else for (const [key, node] of Object.entries(nodes)) {
|
|
128
158
|
invariant(isConstellationNode(node), `unexpected node input under key: ${key}`);
|
|
129
|
-
|
|
159
|
+
register(node, key);
|
|
130
160
|
}
|
|
131
|
-
return
|
|
161
|
+
return {
|
|
162
|
+
byIdentity,
|
|
163
|
+
byLabel
|
|
164
|
+
};
|
|
132
165
|
}
|
|
133
|
-
function nodeToSpec(node, refs) {
|
|
166
|
+
async function nodeToSpec(node, refs) {
|
|
134
167
|
const { id, _constellation, ...rest } = node;
|
|
135
168
|
const spec = {};
|
|
136
|
-
for (const [key, value] of Object.entries(rest))
|
|
137
|
-
|
|
169
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
170
|
+
if (node.type === "ROLES" && key === "roles" && value != null) {
|
|
171
|
+
spec.roles = await expandRoles(value, refs);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
spec[key] = resolveRefs(value, refs);
|
|
175
|
+
}
|
|
176
|
+
spec.ref = refs.byIdentity.get(node);
|
|
138
177
|
invariant(spec.ref != null, "ref not found");
|
|
139
178
|
return stringifyBigints(spec);
|
|
140
179
|
}
|
|
180
|
+
async function expandRoles(roles, refs) {
|
|
181
|
+
return Promise.all(Object.entries(roles).map(async ([key, def]) => {
|
|
182
|
+
const { targets, annotations } = processPermissions(await Promise.all(def.permissions.map((p) => Promise.resolve(p))));
|
|
183
|
+
return {
|
|
184
|
+
key,
|
|
185
|
+
members: resolveRefs(def.members, refs),
|
|
186
|
+
targets,
|
|
187
|
+
annotations: [...def.annotations ?? [], ...annotations]
|
|
188
|
+
};
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
141
191
|
function resolveRefs(value, refs) {
|
|
142
192
|
if (isConstellationNode(value)) {
|
|
143
|
-
const ref = refs.get(value);
|
|
193
|
+
const ref = refs.byIdentity.get(value) ?? refs.byLabel.get(labelKey(value));
|
|
144
194
|
invariant(ref != null, `Node "${value.label}" is referenced not included in the apply() call`);
|
|
145
195
|
return `$${ref}`;
|
|
146
196
|
}
|
|
@@ -150,6 +200,7 @@ function resolveRefs(value, refs) {
|
|
|
150
200
|
for (const [k, v] of Object.entries(value)) resolved[k] = resolveRefs(v, refs);
|
|
151
201
|
return resolved;
|
|
152
202
|
}
|
|
203
|
+
if (typeof value === "string" && /^0x[0-9a-fA-F]{40}$/.test(value)) return value.toLowerCase();
|
|
153
204
|
return value;
|
|
154
205
|
}
|
|
155
206
|
function stringifyBigints(value) {
|
|
@@ -170,6 +221,6 @@ function isConstellationNode(value) {
|
|
|
170
221
|
return false;
|
|
171
222
|
}
|
|
172
223
|
//#endregion
|
|
173
|
-
export { EVERYTHING,
|
|
224
|
+
export { EVERYTHING, apply, buildAllowKit, c, constellation, forAll };
|
|
174
225
|
|
|
175
226
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +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 label: string\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 type: 'SAFE'\n threshold: number\n owners: readonly (string | NodeRef)[]\n modules?: readonly (string | NodeRef)[]\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 type: 'ROLES'\n target?: AddressOrRef\n owner?: AddressOrRef\n avatar?: AddressOrRef\n multisend?: readonly Lowercase<Address>[]\n roles?: readonly RoleSpec[]\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. */\n nonce: bigint\n /** The safe that this roles modifier controls. */\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 } = {},\n >(\n overrides?: {\n [P in Exclude<keyof Entries[K] & string, 'id' | 'label'>]?: any\n } & O\n ) => Readonly<\n Prettify<\n Omit<Entries[K], keyof O> & O & { type: Type; label: K; chain: Ch }\n >\n >)\n : <P extends Record<string, any>>(\n props: NP & { [key: string & {}]: any } & P\n ) => Readonly<Prettify<P & { 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 function makeNodeRef(\n data: Record<string, any>\n ): Readonly<Record<string, any>> {\n const ref = Object.freeze({\n ...data,\n chain: opts.chain,\n _constellation: meta,\n })\n return ref\n }\n\n function entityAccessor(\n registry: Record<string, Record<string, any>>,\n type: string\n ) {\n return new Proxy({} as Record<string, any>, {\n get(_target: any, name: string) {\n if (typeof name !== 'string') return undefined\n const existing = registry[name]\n const fn = (overrides?: Record<string, any>) => {\n return makeNodeRef({\n type,\n ...(existing || {}),\n ...overrides,\n label: name,\n })\n }\n if (existing) {\n Object.assign(fn, {\n type,\n ...existing,\n label: name,\n chain: opts.chain,\n _constellation: meta,\n })\n }\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 return {\n safe: entityAccessor(vaultsByLabel, 'SAFE'),\n roles: entityAccessor(vaultsByLabel, '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.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\nfunction deriveRefs(\n nodes: ConstellationNode[] | { [key: string]: ConstellationNode }\n): Map<ConstellationNodeInternal, string> {\n const refs = new Map<ConstellationNodeInternal, string>()\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 refs.set(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 refs.set(node, key)\n }\n }\n\n return refs\n}\n\nfunction nodeToSpec(\n node: ConstellationNodeInternal,\n refs: Map<ConstellationNodeInternal, string>\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.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(\n value: unknown,\n refs: Map<ConstellationNodeInternal, string>\n): unknown {\n if (isConstellationNode(value)) {\n const ref = refs.get(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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"}
|
|
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 } from './types'\nimport type { Annotation, Permission, PermissionSet } from 'zodiac-roles-sdk'\nimport { createRequire } from 'module'\nimport type * as ZodiacOsCodegen from '.zodiac-os'\nimport { UUID } from 'crypto'\n\n/**\n * A role definition keyed by role name. Permissions are expanded into\n * `{ targets, annotations }` via `processPermissions` at `apply()` time.\n */\nexport type RoleDef = {\n members: readonly AddressOrRef[]\n permissions: readonly (Permission | PermissionSet | Promise<PermissionSet>)[]\n annotations?: readonly Annotation[]\n}\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 (checksummed or lowercase) or a reference to another\n * node in the constellation. Values are normalized to lowercase before being\n * sent to the API. */\ntype AddressOrRef = 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 Address[]\n /** Role definitions configured on this modifier. */\n roles?: Record<string, RoleDef>\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 Address[]\n /** Role definitions to configure on this modifier. */\n roles?: Record<string, RoleDef>\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 { processPermissions } from 'zodiac-roles-sdk'\nimport type { PermissionSet } from 'zodiac-roles-sdk'\nimport { ApiClient } from './api'\nimport type {\n ConstellationMeta,\n ConstellationNode,\n ConstellationNodeInternal,\n RoleDef,\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 = await Promise.all(\n groupNodes.map((n) => nodeToSpec(n, refs))\n )\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\nasync function nodeToSpec(\n node: ConstellationNodeInternal,\n refs: RefsIndex\n): Promise<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 if (node.type === 'ROLES' && key === 'roles' && value != null) {\n spec.roles = await expandRoles(value as Record<string, RoleDef>, refs)\n continue\n }\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\nasync function expandRoles(\n roles: Record<string, RoleDef>,\n refs: RefsIndex\n): Promise<unknown[]> {\n return Promise.all(\n Object.entries(roles).map(async ([key, def]) => {\n const resolvedPermissions = (await Promise.all(\n def.permissions.map((p) => Promise.resolve(p))\n )) as Parameters<typeof processPermissions>[0][number][]\n const { targets, annotations } = processPermissions(resolvedPermissions)\n return {\n key,\n members: resolveRefs(def.members, refs),\n targets,\n annotations: [...(def.annotations ?? []), ...annotations],\n }\n })\n )\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 // Normalize checksummed addresses to lowercase — the API stores addresses\n // lowercase, and accepting checksummed input at the type level would\n // otherwise smuggle mixed-case values into the payload.\n if (typeof value === 'string' && /^0x[0-9a-fA-F]{40}$/.test(value)) {\n return value.toLowerCase()\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"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
// Fallback ambient
|
|
2
|
-
// When `pull-org`
|
|
3
|
-
//
|
|
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
|
+
|
|
4
11
|
declare module '.zodiac-os' {
|
|
5
12
|
import { Address, ChainId } from '@zodiac-os/api-types'
|
|
6
13
|
import { UUID } from 'crypto'
|