@capxul/sdk 0.2.0-alpha.4 → 0.2.0-alpha.5
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 +4 -308
- package/dist/InMemoryAuthCacheAdapter-BK-B_ERB.mjs +113 -0
- package/dist/InMemoryAuthCacheAdapter-BK-B_ERB.mjs.map +1 -0
- package/dist/index.d.mts +1263 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +4740 -0
- package/dist/index.mjs.map +1 -0
- package/dist/node/index.d.mts +55 -0
- package/dist/node/index.d.mts.map +1 -0
- package/dist/node/index.mjs +159 -0
- package/dist/node/index.mjs.map +1 -0
- package/dist/ports/safe-deployment.d.mts +2 -0
- package/dist/ports/safe-deployment.mjs +38 -0
- package/dist/ports/safe-deployment.mjs.map +1 -0
- package/dist/safe-deployment-Vni46k3t.d.mts +137 -0
- package/dist/safe-deployment-Vni46k3t.d.mts.map +1 -0
- package/dist/signer-oaYGfjDe.d.mts +142 -0
- package/dist/signer-oaYGfjDe.d.mts.map +1 -0
- package/package.json +37 -70
- package/CHANGELOG.md +0 -274
- package/LICENSE +0 -44
- package/dist/client-CbUeJoM9.d.ts +0 -1335
- package/dist/client-UEm2oZbZ.d.cts +0 -1335
- package/dist/client.cjs +0 -4042
- package/dist/client.d.cts +0 -6
- package/dist/client.d.ts +0 -6
- package/dist/client.js +0 -4040
- package/dist/errors-CwhCWGxm.d.ts +0 -70
- package/dist/errors-rqxuUhQP.d.cts +0 -70
- package/dist/errors.cjs +0 -35
- package/dist/errors.d.cts +0 -2
- package/dist/errors.d.ts +0 -2
- package/dist/errors.js +0 -31
- package/dist/index.cjs +0 -4273
- package/dist/index.d.cts +0 -461
- package/dist/index.d.ts +0 -461
- package/dist/index.js +0 -4234
- package/dist/next-action-CTGl8wpy.d.cts +0 -177
- package/dist/next-action-CTGl8wpy.d.ts +0 -177
- package/dist/types-BD4VAQb5.d.ts +0 -1205
- package/dist/types-HlwCIjgQ.d.cts +0 -1205
- package/dist/webhooks.cjs +0 -118
- package/dist/webhooks.d.cts +0 -33
- package/dist/webhooks.d.ts +0 -33
- package/dist/webhooks.js +0 -116
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { _ as AuthCachePortTag, g as AuthCachePort, h as AuthCacheError, t as CapxulSigner, v as CachedJwt } from "../signer-oaYGfjDe.mjs";
|
|
2
|
+
import { Effect, Layer } from "effect";
|
|
3
|
+
import { AuthSession } from "@capxul/types";
|
|
4
|
+
import { Hex } from "viem";
|
|
5
|
+
import * as PlatformFileSystem from "@effect/platform/FileSystem";
|
|
6
|
+
import * as PlatformPath from "@effect/platform/Path";
|
|
7
|
+
|
|
8
|
+
//#region src/adapters/auth-cache/FileSystemAuthCacheAdapter.d.ts
|
|
9
|
+
type FileSystemRuntime = PlatformFileSystem.FileSystem | PlatformPath.Path;
|
|
10
|
+
declare class FileSystemAuthCacheAdapter implements AuthCachePort {
|
|
11
|
+
private readonly path;
|
|
12
|
+
private readonly runtime;
|
|
13
|
+
readonly getSession: Effect.Effect<AuthSession | null, AuthCacheError>;
|
|
14
|
+
readonly setSession: (session: AuthSession) => Effect.Effect<void, AuthCacheError>;
|
|
15
|
+
readonly clearSession: Effect.Effect<void, AuthCacheError>;
|
|
16
|
+
readonly getJwt: Effect.Effect<CachedJwt | null, AuthCacheError>;
|
|
17
|
+
readonly setJwt: (jwt: CachedJwt) => Effect.Effect<void, AuthCacheError>;
|
|
18
|
+
readonly clearJwt: Effect.Effect<void, AuthCacheError>;
|
|
19
|
+
constructor(path: string, runtime?: Layer.Layer<FileSystemRuntime>);
|
|
20
|
+
private read;
|
|
21
|
+
private write;
|
|
22
|
+
private run;
|
|
23
|
+
}
|
|
24
|
+
declare function FileSystemAuthCacheLayer(input: {
|
|
25
|
+
readonly path: string;
|
|
26
|
+
readonly runtime?: Layer.Layer<FileSystemRuntime>;
|
|
27
|
+
}): Layer.Layer<AuthCachePortTag, AuthCacheError>;
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/node/index.d.ts
|
|
30
|
+
interface DetectNodeAuthCacheAdapterOptions {
|
|
31
|
+
readonly authCachePath?: string;
|
|
32
|
+
readonly resolveHomeDirectory?: () => string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Node `CapxulSigner` backed by a raw private key. Signs the EIP-712 `SafeOp`
|
|
36
|
+
* digest the backend returns for a prepared deployment UserOperation. The
|
|
37
|
+
* reference CLI builds this from `DEPLOYER_PRIVATE_KEY` for the live capstone.
|
|
38
|
+
*/
|
|
39
|
+
declare function localPrivateKeySigner(input: {
|
|
40
|
+
readonly privateKey: Hex;
|
|
41
|
+
}): CapxulSigner;
|
|
42
|
+
/**
|
|
43
|
+
* Node-aware auth-cache detection. Mirrors the historic default order:
|
|
44
|
+
* 1. Browser localStorage → BrowserAuthCacheAdapter
|
|
45
|
+
* 2. Node.js process → FileSystemAuthCacheAdapter
|
|
46
|
+
* (`~/.config/capxul/auth-cache.json`)
|
|
47
|
+
* 3. Neither detected → InMemoryAuthCacheAdapter
|
|
48
|
+
*
|
|
49
|
+
* Use this from a Node entrypoint and pass the result to
|
|
50
|
+
* `createCapxulClient({ authCache })` for on-disk session persistence.
|
|
51
|
+
*/
|
|
52
|
+
declare function detectNodeAuthCacheAdapter(options?: DetectNodeAuthCacheAdapterOptions): AuthCachePort;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { DetectNodeAuthCacheAdapterOptions, FileSystemAuthCacheAdapter, FileSystemAuthCacheLayer, detectNodeAuthCacheAdapter, localPrivateKeySigner };
|
|
55
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/adapters/auth-cache/FileSystemAuthCacheAdapter.ts","../../src/node/index.ts"],"mappings":";;;;;;;;KAqBK,iBAAA,GAAoB,kBAAA,CAAmB,UAAA,GAAa,YAAA,CAAa,IAAI;AAAA,cAQ7D,0BAAA,YAAsC,aAAA;EAAA,iBAChC,IAAA;EAAA,iBACA,OAAA;EAAA,SACR,UAAA,EAAY,MAAA,CAAO,MAAA,CAAO,WAAA,SAAoB,cAAA;EAAA,SAC9C,UAAA,GAAa,OAAA,EAAS,WAAA,KAAgB,MAAA,CAAO,MAAA,OAAa,cAAA;EAAA,SAC1D,YAAA,EAAc,MAAA,CAAO,MAAA,OAAa,cAAA;EAAA,SAClC,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,SAAA,SAAkB,cAAA;EAAA,SACxC,MAAA,GAAS,GAAA,EAAK,SAAA,KAAc,MAAA,CAAO,MAAA,OAAa,cAAA;EAAA,SAChD,QAAA,EAAU,MAAA,CAAO,MAAA,OAAa,cAAA;cAE3B,IAAA,UAAc,OAAA,GAAS,KAAA,CAAM,KAAA,CAAM,iBAAA;EAAA,QAyCvC,IAAA;EAAA,QAyBA,KAAA;EAAA,QAgBA,GAAA;AAAA;AAAA,iBAWM,wBAAA,CAAyB,KAAA;EAAA,SAC9B,IAAA;EAAA,SACA,OAAA,GAAU,KAAA,CAAM,KAAA,CAAM,iBAAA;AAAA,IAC7B,KAAA,CAAM,KAAA,CAAM,gBAAA,EAAkB,cAAA;;;UC9GjB,iCAAA;EAAA,SACN,aAAA;EAAA,SACA,oBAAoB;AAAA;ADdC;;;;;AAAA,iBCsBhB,qBAAA,CAAsB,KAAA;EAAA,SAAkB,UAAA,EAAY,GAAA;AAAA,IAAQ,YAAY;;ADdd;AAQ1E;;;;;;;;iBC+BgB,0BAAA,CACd,OAAA,GAAS,iCAAA,GACR,aAAa"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { a as AuthCacheError, i as parseCachedJwt, n as BrowserAuthCacheAdapter, o as AuthCachePortTag, r as parseAuthSession, t as InMemoryAuthCacheAdapter } from "../InMemoryAuthCacheAdapter-BK-B_ERB.mjs";
|
|
2
|
+
import { Effect, Layer } from "effect";
|
|
3
|
+
import { toAddress } from "@capxul/types";
|
|
4
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
5
|
+
import * as os from "node:os";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import * as PlatformFileSystem from "@effect/platform/FileSystem";
|
|
8
|
+
import * as PlatformPath from "@effect/platform/Path";
|
|
9
|
+
import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem";
|
|
10
|
+
import * as NodePath from "@effect/platform-node/NodePath";
|
|
11
|
+
//#region src/adapters/auth-cache/FileSystemAuthCacheAdapter.ts
|
|
12
|
+
function emptyPayload() {
|
|
13
|
+
return {
|
|
14
|
+
session: null,
|
|
15
|
+
jwt: null
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const nodeFileSystemRuntime = Layer.merge(NodeFileSystem.layer, NodePath.layer);
|
|
19
|
+
var FileSystemAuthCacheAdapter = class {
|
|
20
|
+
path;
|
|
21
|
+
runtime;
|
|
22
|
+
getSession;
|
|
23
|
+
setSession;
|
|
24
|
+
clearSession;
|
|
25
|
+
getJwt;
|
|
26
|
+
setJwt;
|
|
27
|
+
clearJwt;
|
|
28
|
+
constructor(path, runtime = nodeFileSystemRuntime) {
|
|
29
|
+
this.path = path;
|
|
30
|
+
this.runtime = runtime;
|
|
31
|
+
this.getSession = this.run("getSession", this.read().pipe(Effect.map((payload) => payload.session)));
|
|
32
|
+
this.setSession = (session) => this.run("setSession", Effect.gen(this, function* () {
|
|
33
|
+
const cur = yield* this.read();
|
|
34
|
+
yield* this.write({
|
|
35
|
+
session,
|
|
36
|
+
jwt: cur.jwt
|
|
37
|
+
});
|
|
38
|
+
}));
|
|
39
|
+
this.clearSession = this.run("clearSession", Effect.gen(this, function* () {
|
|
40
|
+
const cur = yield* this.read();
|
|
41
|
+
yield* this.write({
|
|
42
|
+
session: null,
|
|
43
|
+
jwt: cur.jwt
|
|
44
|
+
});
|
|
45
|
+
}));
|
|
46
|
+
this.getJwt = this.run("getJwt", this.read().pipe(Effect.map((payload) => payload.jwt)));
|
|
47
|
+
this.setJwt = (jwt) => this.run("setJwt", Effect.gen(this, function* () {
|
|
48
|
+
const cur = yield* this.read();
|
|
49
|
+
yield* this.write({
|
|
50
|
+
session: cur.session,
|
|
51
|
+
jwt
|
|
52
|
+
});
|
|
53
|
+
}));
|
|
54
|
+
this.clearJwt = this.run("clearJwt", Effect.gen(this, function* () {
|
|
55
|
+
const cur = yield* this.read();
|
|
56
|
+
yield* this.write({
|
|
57
|
+
session: cur.session,
|
|
58
|
+
jwt: null
|
|
59
|
+
});
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
read() {
|
|
63
|
+
return Effect.gen(this, function* () {
|
|
64
|
+
const fs = yield* PlatformFileSystem.FileSystem;
|
|
65
|
+
if (!(yield* fs.exists(this.path))) return emptyPayload();
|
|
66
|
+
const raw = yield* fs.readFileString(this.path, "utf-8");
|
|
67
|
+
let parsed;
|
|
68
|
+
try {
|
|
69
|
+
parsed = JSON.parse(raw);
|
|
70
|
+
} catch {
|
|
71
|
+
return emptyPayload();
|
|
72
|
+
}
|
|
73
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return emptyPayload();
|
|
74
|
+
const payload = parsed;
|
|
75
|
+
return {
|
|
76
|
+
session: parseAuthSession(payload.session),
|
|
77
|
+
jwt: parseCachedJwt(payload.jwt)
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
write(payload) {
|
|
82
|
+
return Effect.gen(this, function* () {
|
|
83
|
+
const fs = yield* PlatformFileSystem.FileSystem;
|
|
84
|
+
const dir = (yield* PlatformPath.Path).dirname(this.path);
|
|
85
|
+
if (!(yield* fs.exists(dir))) yield* fs.makeDirectory(dir, {
|
|
86
|
+
recursive: true,
|
|
87
|
+
mode: 448
|
|
88
|
+
});
|
|
89
|
+
yield* fs.writeFileString(this.path, JSON.stringify(payload), { mode: 384 });
|
|
90
|
+
yield* fs.chmod(this.path, 384);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
run(operation, effect) {
|
|
94
|
+
return effect.pipe(Effect.mapError((cause) => toAuthCacheError(operation, cause)), Effect.provide(this.runtime));
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
function FileSystemAuthCacheLayer(input) {
|
|
98
|
+
return Layer.effect(AuthCachePortTag, Effect.sync(() => new FileSystemAuthCacheAdapter(input.path, input.runtime)).pipe(Effect.mapError((cause) => toAuthCacheError("initialize", cause))));
|
|
99
|
+
}
|
|
100
|
+
function toAuthCacheError(operation, cause) {
|
|
101
|
+
return new AuthCacheError({
|
|
102
|
+
operation,
|
|
103
|
+
cause
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/node/index.ts
|
|
108
|
+
/**
|
|
109
|
+
* Node `CapxulSigner` backed by a raw private key. Signs the EIP-712 `SafeOp`
|
|
110
|
+
* digest the backend returns for a prepared deployment UserOperation. The
|
|
111
|
+
* reference CLI builds this from `DEPLOYER_PRIVATE_KEY` for the live capstone.
|
|
112
|
+
*/
|
|
113
|
+
function localPrivateKeySigner(input) {
|
|
114
|
+
const account = privateKeyToAccount(input.privateKey);
|
|
115
|
+
return {
|
|
116
|
+
source: "local-private-key",
|
|
117
|
+
async getAddress() {
|
|
118
|
+
return toAddress(account.address);
|
|
119
|
+
},
|
|
120
|
+
async signUserOpHash(hash) {
|
|
121
|
+
return account.sign({ hash });
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Node-aware auth-cache detection. Mirrors the historic default order:
|
|
127
|
+
* 1. Browser localStorage → BrowserAuthCacheAdapter
|
|
128
|
+
* 2. Node.js process → FileSystemAuthCacheAdapter
|
|
129
|
+
* (`~/.config/capxul/auth-cache.json`)
|
|
130
|
+
* 3. Neither detected → InMemoryAuthCacheAdapter
|
|
131
|
+
*
|
|
132
|
+
* Use this from a Node entrypoint and pass the result to
|
|
133
|
+
* `createCapxulClient({ authCache })` for on-disk session persistence.
|
|
134
|
+
*/
|
|
135
|
+
function detectNodeAuthCacheAdapter(options = {}) {
|
|
136
|
+
const globalAny = globalThis;
|
|
137
|
+
if (globalAny.window?.localStorage !== void 0) return new BrowserAuthCacheAdapter(globalAny.window.localStorage);
|
|
138
|
+
if (globalAny.process?.versions?.node !== void 0) {
|
|
139
|
+
const authCachePath = normalizeConfiguredAuthCachePath(options.authCachePath) ?? resolveDefaultAuthCachePath(options.resolveHomeDirectory ?? os.homedir);
|
|
140
|
+
if (authCachePath !== null) return new FileSystemAuthCacheAdapter(authCachePath);
|
|
141
|
+
}
|
|
142
|
+
return new InMemoryAuthCacheAdapter();
|
|
143
|
+
}
|
|
144
|
+
function normalizeConfiguredAuthCachePath(path) {
|
|
145
|
+
if (path === void 0) return null;
|
|
146
|
+
const trimmed = path.trim();
|
|
147
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
148
|
+
}
|
|
149
|
+
function resolveDefaultAuthCachePath(resolveHomeDirectory) {
|
|
150
|
+
try {
|
|
151
|
+
return join(resolveHomeDirectory(), ".config", "capxul", "auth-cache.json");
|
|
152
|
+
} catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
export { FileSystemAuthCacheAdapter, FileSystemAuthCacheLayer, detectNodeAuthCacheAdapter, localPrivateKeySigner };
|
|
158
|
+
|
|
159
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/adapters/auth-cache/FileSystemAuthCacheAdapter.ts","../../src/node/index.ts"],"sourcesContent":["import type * as PlatformError from \"@effect/platform/Error\";\nimport * as PlatformFileSystem from \"@effect/platform/FileSystem\";\nimport * as PlatformPath from \"@effect/platform/Path\";\nimport * as NodeFileSystem from \"@effect/platform-node/NodeFileSystem\";\nimport * as NodePath from \"@effect/platform-node/NodePath\";\nimport { Effect, Layer } from \"effect\";\nimport type { AuthSession } from \"@capxul/types\";\n\nimport {\n AuthCacheError,\n AuthCachePortTag,\n type AuthCachePort,\n type CachedJwt,\n} from \"../../ports/auth-cache\";\nimport { parseAuthSession, parseCachedJwt } from \"./serialization\";\n\ninterface FilePayload {\n readonly session: AuthSession | null;\n readonly jwt: CachedJwt | null;\n}\n\ntype FileSystemRuntime = PlatformFileSystem.FileSystem | PlatformPath.Path;\n\nfunction emptyPayload(): FilePayload {\n return { session: null, jwt: null };\n}\n\nconst nodeFileSystemRuntime = Layer.merge(NodeFileSystem.layer, NodePath.layer);\n\nexport class FileSystemAuthCacheAdapter implements AuthCachePort {\n private readonly path: string;\n private readonly runtime: Layer.Layer<FileSystemRuntime>;\n readonly getSession: Effect.Effect<AuthSession | null, AuthCacheError>;\n readonly setSession: (session: AuthSession) => Effect.Effect<void, AuthCacheError>;\n readonly clearSession: Effect.Effect<void, AuthCacheError>;\n readonly getJwt: Effect.Effect<CachedJwt | null, AuthCacheError>;\n readonly setJwt: (jwt: CachedJwt) => Effect.Effect<void, AuthCacheError>;\n readonly clearJwt: Effect.Effect<void, AuthCacheError>;\n\n constructor(path: string, runtime: Layer.Layer<FileSystemRuntime> = nodeFileSystemRuntime) {\n this.path = path;\n this.runtime = runtime;\n\n this.getSession = this.run(\n \"getSession\",\n this.read().pipe(Effect.map((payload) => payload.session)),\n );\n this.setSession = (session: AuthSession) =>\n this.run(\n \"setSession\",\n Effect.gen(this, function* () {\n const cur = yield* this.read();\n yield* this.write({ session, jwt: cur.jwt });\n }),\n );\n this.clearSession = this.run(\n \"clearSession\",\n Effect.gen(this, function* () {\n const cur = yield* this.read();\n yield* this.write({ session: null, jwt: cur.jwt });\n }),\n );\n this.getJwt = this.run(\"getJwt\", this.read().pipe(Effect.map((payload) => payload.jwt)));\n this.setJwt = (jwt: CachedJwt) =>\n this.run(\n \"setJwt\",\n Effect.gen(this, function* () {\n const cur = yield* this.read();\n yield* this.write({ session: cur.session, jwt });\n }),\n );\n this.clearJwt = this.run(\n \"clearJwt\",\n Effect.gen(this, function* () {\n const cur = yield* this.read();\n yield* this.write({ session: cur.session, jwt: null });\n }),\n );\n }\n\n private read(): Effect.Effect<FilePayload, PlatformError.PlatformError, FileSystemRuntime> {\n return Effect.gen(this, function* () {\n const fs = yield* PlatformFileSystem.FileSystem;\n const exists = yield* fs.exists(this.path);\n if (!exists) return emptyPayload();\n const raw = yield* fs.readFileString(this.path, \"utf-8\");\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return emptyPayload();\n }\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return emptyPayload();\n }\n const payload = parsed as { readonly session?: unknown; readonly jwt?: unknown };\n\n return {\n session: parseAuthSession(payload.session),\n jwt: parseCachedJwt(payload.jwt),\n };\n });\n }\n\n private write(\n payload: FilePayload,\n ): Effect.Effect<void, PlatformError.PlatformError, FileSystemRuntime> {\n return Effect.gen(this, function* () {\n const fs = yield* PlatformFileSystem.FileSystem;\n const path = yield* PlatformPath.Path;\n const dir = path.dirname(this.path);\n const dirExists = yield* fs.exists(dir);\n if (!dirExists) {\n yield* fs.makeDirectory(dir, { recursive: true, mode: 0o700 });\n }\n yield* fs.writeFileString(this.path, JSON.stringify(payload), { mode: 0o600 });\n yield* fs.chmod(this.path, 0o600);\n });\n }\n\n private run<T>(\n operation: string,\n effect: Effect.Effect<T, PlatformError.PlatformError, FileSystemRuntime>,\n ): Effect.Effect<T, AuthCacheError> {\n return effect.pipe(\n Effect.mapError((cause) => toAuthCacheError(operation, cause)),\n Effect.provide(this.runtime),\n );\n }\n}\n\nexport function FileSystemAuthCacheLayer(input: {\n readonly path: string;\n readonly runtime?: Layer.Layer<FileSystemRuntime>;\n}): Layer.Layer<AuthCachePortTag, AuthCacheError> {\n return Layer.effect(\n AuthCachePortTag,\n Effect.sync(() => new FileSystemAuthCacheAdapter(input.path, input.runtime)).pipe(\n Effect.mapError((cause) => toAuthCacheError(\"initialize\", cause)),\n ),\n );\n}\n\nfunction toAuthCacheError(operation: string, cause: unknown): AuthCacheError {\n return new AuthCacheError({ operation, cause });\n}\n","// `@capxul/sdk/node` — node-only entry (published-package-boundaries.md).\n//\n// The default `@capxul/sdk` entry is browser-clean: it never statically reaches\n// `@effect/platform-node`. Node consumers import the on-disk auth cache and the\n// node key `CapxulSigner` from here.\n\nimport * as os from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { toAddress } from \"@capxul/types\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport type { Hex } from \"viem\";\n\nimport { BrowserAuthCacheAdapter } from \"../adapters/auth-cache/BrowserAuthCacheAdapter\";\nimport { FileSystemAuthCacheAdapter } from \"../adapters/auth-cache/FileSystemAuthCacheAdapter\";\nimport { InMemoryAuthCacheAdapter } from \"../adapters/auth-cache/InMemoryAuthCacheAdapter\";\nimport type { WindowLike } from \"../client/window-like\";\nimport type { AuthCachePort } from \"../ports/auth-cache\";\nimport type { CapxulSigner } from \"../signer\";\n\nexport {\n FileSystemAuthCacheAdapter,\n FileSystemAuthCacheLayer,\n} from \"../adapters/auth-cache/FileSystemAuthCacheAdapter\";\n\nexport interface DetectNodeAuthCacheAdapterOptions {\n readonly authCachePath?: string;\n readonly resolveHomeDirectory?: () => string;\n}\n\n/**\n * Node `CapxulSigner` backed by a raw private key. Signs the EIP-712 `SafeOp`\n * digest the backend returns for a prepared deployment UserOperation. The\n * reference CLI builds this from `DEPLOYER_PRIVATE_KEY` for the live capstone.\n */\nexport function localPrivateKeySigner(input: { readonly privateKey: Hex }): CapxulSigner {\n const account = privateKeyToAccount(input.privateKey);\n return {\n source: \"local-private-key\",\n async getAddress() {\n return toAddress(account.address);\n },\n async signUserOpHash(hash: Hex): Promise<Hex> {\n // `sign({ hash })` signs the already-computed SafeOp digest directly.\n // `signMessage({ message: { raw: hash } })` would add an EIP-191 prefix.\n return account.sign({ hash });\n },\n };\n}\n\n/**\n * Node-aware auth-cache detection. Mirrors the historic default order:\n * 1. Browser localStorage → BrowserAuthCacheAdapter\n * 2. Node.js process → FileSystemAuthCacheAdapter\n * (`~/.config/capxul/auth-cache.json`)\n * 3. Neither detected → InMemoryAuthCacheAdapter\n *\n * Use this from a Node entrypoint and pass the result to\n * `createCapxulClient({ authCache })` for on-disk session persistence.\n */\nexport function detectNodeAuthCacheAdapter(\n options: DetectNodeAuthCacheAdapterOptions = {},\n): AuthCachePort {\n const globalAny = globalThis as unknown as {\n readonly window?: WindowLike;\n readonly process?: { readonly versions?: { readonly node?: string } };\n };\n if (globalAny.window?.localStorage !== undefined) {\n return new BrowserAuthCacheAdapter(globalAny.window.localStorage);\n }\n if (globalAny.process?.versions?.node !== undefined) {\n const authCachePath =\n normalizeConfiguredAuthCachePath(options.authCachePath) ??\n resolveDefaultAuthCachePath(options.resolveHomeDirectory ?? os.homedir);\n if (authCachePath !== null) return new FileSystemAuthCacheAdapter(authCachePath);\n }\n return new InMemoryAuthCacheAdapter();\n}\n\nfunction normalizeConfiguredAuthCachePath(path: string | undefined): string | null {\n if (path === undefined) return null;\n const trimmed = path.trim();\n return trimmed.length > 0 ? trimmed : null;\n}\n\nfunction resolveDefaultAuthCachePath(resolveHomeDirectory: () => string): string | null {\n try {\n return join(resolveHomeDirectory(), \".config\", \"capxul\", \"auth-cache.json\");\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as SafeDeploymentEvidence, c as SafeDeploymentPortTag, i as SafeDeploymentError, l as safeDeploymentErrorFromCapxul, n as SafeDeploymentConfig, o as SafeDeploymentInput, r as SafeDeploymentDeployedQuery, s as SafeDeploymentPort, t as PreparedSafeAccount } from "../safe-deployment-Vni46k3t.mjs";
|
|
2
|
+
export { PreparedSafeAccount, SafeDeploymentConfig, SafeDeploymentDeployedQuery, SafeDeploymentError, SafeDeploymentEvidence, SafeDeploymentInput, SafeDeploymentPort, SafeDeploymentPortTag, safeDeploymentErrorFromCapxul };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Context, Data } from "effect";
|
|
2
|
+
//#region src/ports/safe-deployment.ts
|
|
3
|
+
/**
|
|
4
|
+
* Typed error for SafeDeploymentPort operations. Mirrors the shape used
|
|
5
|
+
* by `SmartAccountError` (see `ports/smart-account.ts`) so the two
|
|
6
|
+
* domain ports compose uniformly into the deploy slice (#161).
|
|
7
|
+
*/
|
|
8
|
+
var SafeDeploymentError = class extends Data.TaggedError("SafeDeploymentError") {};
|
|
9
|
+
/**
|
|
10
|
+
* Wrap a `CapxulError` as a `SafeDeploymentError`. Adapter helper —
|
|
11
|
+
* used at every failure boundary inside a `SafeDeploymentPort` method
|
|
12
|
+
* to preserve the operation that failed alongside the typed public
|
|
13
|
+
* error.
|
|
14
|
+
*
|
|
15
|
+
* Mirrors the `smartAccountErrorFromCapxul` helper on `SmartAccountPort`
|
|
16
|
+
* — both ports follow the same Effect-native pattern: tagged port-error
|
|
17
|
+
* carries `operation` + `publicCode` + `publicError`, and the helper
|
|
18
|
+
* keeps `details` optional so the call site doesn't have to.
|
|
19
|
+
*
|
|
20
|
+
* @param operation - The port method that failed (e.g. `"deploy"`)
|
|
21
|
+
* @param error - The originating `CapxulError`
|
|
22
|
+
* @param cause - Underlying cause; defaults to `error` itself
|
|
23
|
+
* @returns A `SafeDeploymentError` ready to throw via `Effect.fail`
|
|
24
|
+
*/
|
|
25
|
+
function safeDeploymentErrorFromCapxul(operation, error, cause = error) {
|
|
26
|
+
return new SafeDeploymentError({
|
|
27
|
+
operation,
|
|
28
|
+
publicCode: error.code,
|
|
29
|
+
publicError: error,
|
|
30
|
+
cause,
|
|
31
|
+
...error.details === void 0 ? {} : { details: error.details }
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
var SafeDeploymentPortTag = class extends Context.Tag("@capxul/sdk/ports/SafeDeploymentPort")() {};
|
|
35
|
+
//#endregion
|
|
36
|
+
export { SafeDeploymentError, SafeDeploymentPortTag, safeDeploymentErrorFromCapxul };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=safe-deployment.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-deployment.mjs","names":[],"sources":["../../src/ports/safe-deployment.ts"],"sourcesContent":["import { Context, Data, Effect } from \"effect\";\nimport type { Account } from \"viem\";\n\nimport type { CapxulError, CapxulErrorCode, CapxulErrorDetails } from \"@capxul/config\";\nimport type { Address, BlockNumber, ChainId, DurationMs, Email, TxHash } from \"@capxul/types\";\n\n/**\n * Configuration for a Safe deployment: the chain + RPC endpoint +\n * gas-sponsorship policy the adapter should use.\n *\n * `receiptTimeoutMs` is optional; the production adapter applies a\n * default when omitted. The in-memory adapter ignores it.\n */\nexport type SafeDeploymentConfig = {\n readonly chainId: ChainId;\n readonly rpcUrl: string;\n readonly gasPolicyId: string;\n readonly receiptTimeoutMs?: DurationMs;\n};\n\n/**\n * Result of `prepare`: the counterfactual Safe address derived from\n * `(signerAddress, email)` without any on-chain side effect.\n */\nexport type PreparedSafeAccount = {\n readonly chainId: ChainId;\n readonly signerAddress: Address;\n readonly safeAddress: Address;\n};\n\n/**\n * Evidence of a successful Safe deployment.\n *\n * Every field except `chainId` / `signerAddress` / `safeAddress` is\n * optional because the AC8 precheck short-circuit path (Safe already\n * on-chain at this address; off-chain receipt evidence unavailable)\n * calls the persistence step WITHOUT a `userOpHash`, `txHash`, or\n * `blockNumber` — there is no recoverable transaction. Aaron's rule:\n * \"If there is no TX and it hasn't been deployed then there shouldn't\n * be a hash.\" End-to-end nullable: `v.optional(v.string())` in the\n * backend schema.\n *\n * **`deployedAt` is NOT a field on this type.** The SDK is never the\n * oracle for `deployedAt`. The backend (`confirmDeployment` action —\n * Convex mutations cannot `fetch`, so the chain re-verification lives\n * in an action) derives it from on-chain data — `eth_getUserOperationReceipt`\n * for the real-userOp path or `eth_getLogs` for the precheck path —\n * then resolves the receipt block's timestamp via `eth_getBlockByNumber`.\n * See `docs/canon/ports/smart-account.md` for the γ-B trust-model\n * section.\n */\nexport type SafeDeploymentEvidence = {\n readonly chainId: ChainId;\n readonly signerAddress: Address;\n readonly safeAddress: Address;\n readonly txHash?: TxHash;\n readonly userOpHash?: TxHash;\n readonly blockNumber?: BlockNumber;\n};\n\nexport type SafeDeploymentInput = {\n readonly signer: Account;\n readonly email: Email;\n readonly config: SafeDeploymentConfig;\n};\n\nexport type SafeDeploymentDeployedQuery = {\n readonly safeAddress: Address;\n readonly config: SafeDeploymentConfig;\n};\n\n/**\n * Typed error for SafeDeploymentPort operations. Mirrors the shape used\n * by `SmartAccountError` (see `ports/smart-account.ts`) so the two\n * domain ports compose uniformly into the deploy slice (#161).\n */\nexport class SafeDeploymentError extends Data.TaggedError(\"SafeDeploymentError\")<{\n readonly operation: string;\n readonly publicCode: CapxulErrorCode;\n readonly publicError: CapxulError;\n readonly cause: unknown;\n readonly details?: CapxulErrorDetails;\n}> {}\n\n/**\n * Wrap a `CapxulError` as a `SafeDeploymentError`. Adapter helper —\n * used at every failure boundary inside a `SafeDeploymentPort` method\n * to preserve the operation that failed alongside the typed public\n * error.\n *\n * Mirrors the `smartAccountErrorFromCapxul` helper on `SmartAccountPort`\n * — both ports follow the same Effect-native pattern: tagged port-error\n * carries `operation` + `publicCode` + `publicError`, and the helper\n * keeps `details` optional so the call site doesn't have to.\n *\n * @param operation - The port method that failed (e.g. `\"deploy\"`)\n * @param error - The originating `CapxulError`\n * @param cause - Underlying cause; defaults to `error` itself\n * @returns A `SafeDeploymentError` ready to throw via `Effect.fail`\n */\nexport function safeDeploymentErrorFromCapxul(\n operation: string,\n error: CapxulError,\n cause: unknown = error,\n): SafeDeploymentError {\n return new SafeDeploymentError({\n operation,\n publicCode: error.code,\n publicError: error,\n cause,\n ...(error.details === undefined ? {} : { details: error.details }),\n });\n}\n\n/**\n * Domain port for off-chain + on-chain Safe lifecycle operations.\n *\n * Sibling to `SmartAccountPort` (the Convex-side aggregate). The deploy\n * slice (#161) composes both: `SafeDeploymentPort.deploy` to mint a Safe\n * on-chain, then `SmartAccountPort.confirmDeployment` to persist\n * evidence to Convex. `confirmDeployment` is NOT on this port — that\n * would couple persistence into chain-execution.\n *\n * NOT a member of `PlatformPorts` — domain ports are composed by\n * consumers per the hexagonal Option C decision. See\n * `docs/canon/ports/smart-account.md` for the precedent.\n */\nexport interface SafeDeploymentPort {\n /**\n * Off-chain derivation only: compute the counterfactual Safe address\n * for `(signer, email)`. Pure — no I/O, no state mutation.\n */\n prepare(\n input: SafeDeploymentInput,\n ): Effect.Effect<PreparedSafeAccount, SafeDeploymentError, never>;\n\n /**\n * Deploy the Safe on-chain via the bundler + paymaster (production)\n * or simulate the deployment in memory (testing). Idempotent on\n * `(signer, email)` — repeated calls produce the same `safeAddress`.\n */\n deploy(\n input: SafeDeploymentInput,\n ): Effect.Effect<SafeDeploymentEvidence, SafeDeploymentError, never>;\n\n /**\n * Returns true if `safeAddress` is already deployed on-chain\n * (`extcodesize > 0`). Used by `client._internal.account.deploySafe`\n * to short-circuit the deploy path when a partial-failure retry would\n * otherwise submit a second UserOp against an already-deployed Safe\n * (slice 5B · AC8).\n */\n isDeployed(\n input: SafeDeploymentDeployedQuery,\n ): Effect.Effect<boolean, SafeDeploymentError, never>;\n}\n\nexport class SafeDeploymentPortTag extends Context.Tag(\"@capxul/sdk/ports/SafeDeploymentPort\")<\n SafeDeploymentPortTag,\n SafeDeploymentPort\n>() {}\n"],"mappings":";;;;;;;AA4EA,IAAa,sBAAb,cAAyC,KAAK,YAAY,qBAAqB,EAM5E,CAAC;;;;;;;;;;;;;;;;;AAkBJ,SAAgB,8BACd,WACA,OACA,QAAiB,OACI;CACrB,OAAO,IAAI,oBAAoB;EAC7B;EACA,YAAY,MAAM;EAClB,aAAa;EACb;EACA,GAAI,MAAM,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,MAAM,QAAQ;CAClE,CAAC;AACH;AA6CA,IAAa,wBAAb,cAA2C,QAAQ,IAAI,sCAAsC,EAG3F,EAAE,CAAC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Context, Effect } from "effect";
|
|
2
|
+
import { CapxulError, CapxulErrorCode, CapxulErrorDetails } from "@capxul/config";
|
|
3
|
+
import { Address, BlockNumber, ChainId, DurationMs, Email, TxHash } from "@capxul/types";
|
|
4
|
+
import { Account as Account$1 } from "viem";
|
|
5
|
+
|
|
6
|
+
//#region src/ports/safe-deployment.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for a Safe deployment: the chain + RPC endpoint +
|
|
9
|
+
* gas-sponsorship policy the adapter should use.
|
|
10
|
+
*
|
|
11
|
+
* `receiptTimeoutMs` is optional; the production adapter applies a
|
|
12
|
+
* default when omitted. The in-memory adapter ignores it.
|
|
13
|
+
*/
|
|
14
|
+
type SafeDeploymentConfig = {
|
|
15
|
+
readonly chainId: ChainId;
|
|
16
|
+
readonly rpcUrl: string;
|
|
17
|
+
readonly gasPolicyId: string;
|
|
18
|
+
readonly receiptTimeoutMs?: DurationMs;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Result of `prepare`: the counterfactual Safe address derived from
|
|
22
|
+
* `(signerAddress, email)` without any on-chain side effect.
|
|
23
|
+
*/
|
|
24
|
+
type PreparedSafeAccount = {
|
|
25
|
+
readonly chainId: ChainId;
|
|
26
|
+
readonly signerAddress: Address;
|
|
27
|
+
readonly safeAddress: Address;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Evidence of a successful Safe deployment.
|
|
31
|
+
*
|
|
32
|
+
* Every field except `chainId` / `signerAddress` / `safeAddress` is
|
|
33
|
+
* optional because the AC8 precheck short-circuit path (Safe already
|
|
34
|
+
* on-chain at this address; off-chain receipt evidence unavailable)
|
|
35
|
+
* calls the persistence step WITHOUT a `userOpHash`, `txHash`, or
|
|
36
|
+
* `blockNumber` — there is no recoverable transaction. Aaron's rule:
|
|
37
|
+
* "If there is no TX and it hasn't been deployed then there shouldn't
|
|
38
|
+
* be a hash." End-to-end nullable: `v.optional(v.string())` in the
|
|
39
|
+
* backend schema.
|
|
40
|
+
*
|
|
41
|
+
* **`deployedAt` is NOT a field on this type.** The SDK is never the
|
|
42
|
+
* oracle for `deployedAt`. The backend (`confirmDeployment` action —
|
|
43
|
+
* Convex mutations cannot `fetch`, so the chain re-verification lives
|
|
44
|
+
* in an action) derives it from on-chain data — `eth_getUserOperationReceipt`
|
|
45
|
+
* for the real-userOp path or `eth_getLogs` for the precheck path —
|
|
46
|
+
* then resolves the receipt block's timestamp via `eth_getBlockByNumber`.
|
|
47
|
+
* See `docs/canon/ports/smart-account.md` for the γ-B trust-model
|
|
48
|
+
* section.
|
|
49
|
+
*/
|
|
50
|
+
type SafeDeploymentEvidence = {
|
|
51
|
+
readonly chainId: ChainId;
|
|
52
|
+
readonly signerAddress: Address;
|
|
53
|
+
readonly safeAddress: Address;
|
|
54
|
+
readonly txHash?: TxHash;
|
|
55
|
+
readonly userOpHash?: TxHash;
|
|
56
|
+
readonly blockNumber?: BlockNumber;
|
|
57
|
+
};
|
|
58
|
+
type SafeDeploymentInput = {
|
|
59
|
+
readonly signer: Account$1;
|
|
60
|
+
readonly email: Email;
|
|
61
|
+
readonly config: SafeDeploymentConfig;
|
|
62
|
+
};
|
|
63
|
+
type SafeDeploymentDeployedQuery = {
|
|
64
|
+
readonly safeAddress: Address;
|
|
65
|
+
readonly config: SafeDeploymentConfig;
|
|
66
|
+
};
|
|
67
|
+
declare const SafeDeploymentError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => import("effect/Cause").YieldableError & {
|
|
68
|
+
readonly _tag: "SafeDeploymentError";
|
|
69
|
+
} & Readonly<A>;
|
|
70
|
+
/**
|
|
71
|
+
* Typed error for SafeDeploymentPort operations. Mirrors the shape used
|
|
72
|
+
* by `SmartAccountError` (see `ports/smart-account.ts`) so the two
|
|
73
|
+
* domain ports compose uniformly into the deploy slice (#161).
|
|
74
|
+
*/
|
|
75
|
+
declare class SafeDeploymentError extends SafeDeploymentError_base<{
|
|
76
|
+
readonly operation: string;
|
|
77
|
+
readonly publicCode: CapxulErrorCode;
|
|
78
|
+
readonly publicError: CapxulError;
|
|
79
|
+
readonly cause: unknown;
|
|
80
|
+
readonly details?: CapxulErrorDetails;
|
|
81
|
+
}> {}
|
|
82
|
+
/**
|
|
83
|
+
* Wrap a `CapxulError` as a `SafeDeploymentError`. Adapter helper —
|
|
84
|
+
* used at every failure boundary inside a `SafeDeploymentPort` method
|
|
85
|
+
* to preserve the operation that failed alongside the typed public
|
|
86
|
+
* error.
|
|
87
|
+
*
|
|
88
|
+
* Mirrors the `smartAccountErrorFromCapxul` helper on `SmartAccountPort`
|
|
89
|
+
* — both ports follow the same Effect-native pattern: tagged port-error
|
|
90
|
+
* carries `operation` + `publicCode` + `publicError`, and the helper
|
|
91
|
+
* keeps `details` optional so the call site doesn't have to.
|
|
92
|
+
*
|
|
93
|
+
* @param operation - The port method that failed (e.g. `"deploy"`)
|
|
94
|
+
* @param error - The originating `CapxulError`
|
|
95
|
+
* @param cause - Underlying cause; defaults to `error` itself
|
|
96
|
+
* @returns A `SafeDeploymentError` ready to throw via `Effect.fail`
|
|
97
|
+
*/
|
|
98
|
+
declare function safeDeploymentErrorFromCapxul(operation: string, error: CapxulError, cause?: unknown): SafeDeploymentError;
|
|
99
|
+
/**
|
|
100
|
+
* Domain port for off-chain + on-chain Safe lifecycle operations.
|
|
101
|
+
*
|
|
102
|
+
* Sibling to `SmartAccountPort` (the Convex-side aggregate). The deploy
|
|
103
|
+
* slice (#161) composes both: `SafeDeploymentPort.deploy` to mint a Safe
|
|
104
|
+
* on-chain, then `SmartAccountPort.confirmDeployment` to persist
|
|
105
|
+
* evidence to Convex. `confirmDeployment` is NOT on this port — that
|
|
106
|
+
* would couple persistence into chain-execution.
|
|
107
|
+
*
|
|
108
|
+
* NOT a member of `PlatformPorts` — domain ports are composed by
|
|
109
|
+
* consumers per the hexagonal Option C decision. See
|
|
110
|
+
* `docs/canon/ports/smart-account.md` for the precedent.
|
|
111
|
+
*/
|
|
112
|
+
interface SafeDeploymentPort {
|
|
113
|
+
/**
|
|
114
|
+
* Off-chain derivation only: compute the counterfactual Safe address
|
|
115
|
+
* for `(signer, email)`. Pure — no I/O, no state mutation.
|
|
116
|
+
*/
|
|
117
|
+
prepare(input: SafeDeploymentInput): Effect.Effect<PreparedSafeAccount, SafeDeploymentError, never>;
|
|
118
|
+
/**
|
|
119
|
+
* Deploy the Safe on-chain via the bundler + paymaster (production)
|
|
120
|
+
* or simulate the deployment in memory (testing). Idempotent on
|
|
121
|
+
* `(signer, email)` — repeated calls produce the same `safeAddress`.
|
|
122
|
+
*/
|
|
123
|
+
deploy(input: SafeDeploymentInput): Effect.Effect<SafeDeploymentEvidence, SafeDeploymentError, never>;
|
|
124
|
+
/**
|
|
125
|
+
* Returns true if `safeAddress` is already deployed on-chain
|
|
126
|
+
* (`extcodesize > 0`). Used by `client._internal.account.deploySafe`
|
|
127
|
+
* to short-circuit the deploy path when a partial-failure retry would
|
|
128
|
+
* otherwise submit a second UserOp against an already-deployed Safe
|
|
129
|
+
* (slice 5B · AC8).
|
|
130
|
+
*/
|
|
131
|
+
isDeployed(input: SafeDeploymentDeployedQuery): Effect.Effect<boolean, SafeDeploymentError, never>;
|
|
132
|
+
}
|
|
133
|
+
declare const SafeDeploymentPortTag_base: Context.TagClass<SafeDeploymentPortTag, "@capxul/sdk/ports/SafeDeploymentPort", SafeDeploymentPort>;
|
|
134
|
+
declare class SafeDeploymentPortTag extends SafeDeploymentPortTag_base {}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { SafeDeploymentEvidence as a, SafeDeploymentPortTag as c, SafeDeploymentError as i, safeDeploymentErrorFromCapxul as l, SafeDeploymentConfig as n, SafeDeploymentInput as o, SafeDeploymentDeployedQuery as r, SafeDeploymentPort as s, PreparedSafeAccount as t };
|
|
137
|
+
//# sourceMappingURL=safe-deployment-Vni46k3t.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-deployment-Vni46k3t.d.mts","names":[],"sources":["../src/ports/safe-deployment.ts"],"mappings":";;;;;;;;AAaA;;;;;KAAY,oBAAA;EAAA,SACD,OAAA,EAAS,OAAA;EAAA,SACT,MAAA;EAAA,SACA,WAAA;EAAA,SACA,gBAAA,GAAmB,UAAU;AAAA;AAAA;AAOxC;;;AAPwC,KAO5B,mBAAA;EAAA,SACD,OAAA,EAAS,OAAA;EAAA,SACT,aAAA,EAAe,OAAA;EAAA,SACf,WAAA,EAAa,OAAA;AAAA;;;;;;;;AAAO;AAwB/B;;;;;;;;;;;;;KAAY,sBAAA;EAAA,SACD,OAAA,EAAS,OAAA;EAAA,SACT,aAAA,EAAe,OAAA;EAAA,SACf,WAAA,EAAa,OAAA;EAAA,SACb,MAAA,GAAS,MAAA;EAAA,SACT,UAAA,GAAa,MAAA;EAAA,SACb,WAAA,GAAc,WAAA;AAAA;AAAA,KAGb,mBAAA;EAAA,SACD,MAAA,EAAQ,SAAA;EAAA,SACR,KAAA,EAAO,KAAA;EAAA,SACP,MAAA,EAAQ,oBAAA;AAAA;AAAA,KAGP,2BAAA;EAAA,SACD,WAAA,EAAa,OAAA;EAAA,SACb,MAAA,EAAQ,oBAAoB;AAAA;AAAA,cACrC,wBAAA;;;;;;;;cAOW,mBAAA,SAA4B,wBAAA;EAAA,SAC9B,SAAA;EAAA,SACA,UAAA,EAAY,eAAA;EAAA,SACZ,WAAA,EAAa,WAAA;EAAA,SACb,KAAA;EAAA,SACA,OAAA,GAAU,kBAAA;AAAA;;;;;AAbkB;AACrC;;;;;;;;;;;iBA+Bc,6BAAA,CACd,SAAA,UACA,KAAA,EAAO,WAAA,EACP,KAAA,aACC,mBAAmB;;;;;;;;;;;;;;UAuBL,kBAAA;;;;AAnDjB;EAwDE,OAAA,CACE,KAAA,EAAO,mBAAA,GACN,MAAA,CAAO,MAAA,CAAO,mBAAA,EAAqB,mBAAA;;;;;;EAOtC,MAAA,CACE,KAAA,EAAO,mBAAA,GACN,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,mBAAA;EAnEF;;;;;;;EA4EvC,UAAA,CACE,KAAA,EAAO,2BAAA,GACN,MAAA,CAAO,MAAA,UAAgB,mBAAA;AAAA;AAAA,cAC3B,0BAAA;cAEY,qBAAA,SAA8B,0BAGxC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Context, Effect } from "effect";
|
|
2
|
+
import { Address, AuthSession, EpochSeconds, JwtToken, Profile, SmartAccount } from "@capxul/types";
|
|
3
|
+
import { Account as Account$1, Hex } from "viem";
|
|
4
|
+
|
|
5
|
+
//#region src/ports/auth-cache.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* AuthCachePort (TA4) — replaces `SessionStoragePort` in the rebuild slice's
|
|
8
|
+
* consumer-facing wiring. Stores the user-snapshot Session AND the cached
|
|
9
|
+
* Convex JWT (W7 bridge endpoint). The two slots are independent so a session
|
|
10
|
+
* refresh doesn't invalidate the JWT and vice versa.
|
|
11
|
+
*
|
|
12
|
+
* Three adapters (TA7):
|
|
13
|
+
* - `BrowserAuthCacheAdapter` — backed by `localStorage`
|
|
14
|
+
* - `FileSystemAuthCacheAdapter` — mode-0600 JSON file in `~/.config/capxul/`
|
|
15
|
+
* - `InMemoryAuthCacheAdapter` — for tests
|
|
16
|
+
*
|
|
17
|
+
* `SessionStoragePort` was retired by the Stage 4 rebuild; session and JWT
|
|
18
|
+
* persistence now share this cache boundary.
|
|
19
|
+
*/
|
|
20
|
+
interface AuthCachePort {
|
|
21
|
+
readonly getSession: Effect.Effect<AuthSession | null, AuthCacheError>;
|
|
22
|
+
readonly setSession: (session: AuthSession) => Effect.Effect<void, AuthCacheError>;
|
|
23
|
+
readonly clearSession: Effect.Effect<void, AuthCacheError>;
|
|
24
|
+
/**
|
|
25
|
+
* JWT cache for the `/api/auth/convex/token` bridge endpoint (W7).
|
|
26
|
+
* Stored separately from the session so a session refresh doesn't
|
|
27
|
+
* invalidate cached JWT.
|
|
28
|
+
*/
|
|
29
|
+
readonly getJwt: Effect.Effect<CachedJwt | null, AuthCacheError>;
|
|
30
|
+
readonly setJwt: (jwt: CachedJwt) => Effect.Effect<void, AuthCacheError>;
|
|
31
|
+
readonly clearJwt: Effect.Effect<void, AuthCacheError>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Cached Convex JWT shape (TA4). `expEpochSeconds` is decoded from the JWT's
|
|
35
|
+
* `exp` claim at fetch time so the `tokenProvider` cache eviction logic can
|
|
36
|
+
* proactively refresh at `exp - 30s` per TA3.
|
|
37
|
+
*/
|
|
38
|
+
interface CachedJwt {
|
|
39
|
+
readonly token: JwtToken;
|
|
40
|
+
readonly expEpochSeconds: EpochSeconds;
|
|
41
|
+
}
|
|
42
|
+
declare const AuthCacheError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }>) => import("effect/Cause").YieldableError & {
|
|
43
|
+
readonly _tag: "AuthCacheError";
|
|
44
|
+
} & Readonly<A>;
|
|
45
|
+
declare class AuthCacheError extends AuthCacheError_base<{
|
|
46
|
+
readonly operation: string;
|
|
47
|
+
readonly cause: unknown;
|
|
48
|
+
}> {}
|
|
49
|
+
declare const AuthCachePortTag_base: Context.TagClass<AuthCachePortTag, "@capxul/sdk/ports/AuthCachePort", AuthCachePort>;
|
|
50
|
+
declare class AuthCachePortTag extends AuthCachePortTag_base {}
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/client/types.d.ts
|
|
53
|
+
type Session = AuthSession;
|
|
54
|
+
type Profile$1 = Profile;
|
|
55
|
+
type SmartAccount$1 = SmartAccount;
|
|
56
|
+
/**
|
|
57
|
+
* Result-shape returned by every method on `CapxulClient`. Mirrors the
|
|
58
|
+
* existing per-port `Result` aliases; centralized here so consumers have
|
|
59
|
+
* a single import for the consumer-facing surface.
|
|
60
|
+
*/
|
|
61
|
+
type CapxulResult<T> = {
|
|
62
|
+
readonly ok: true;
|
|
63
|
+
readonly value: T;
|
|
64
|
+
} | {
|
|
65
|
+
readonly ok: false;
|
|
66
|
+
readonly error: import("@capxul/config").CapxulError;
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/client/account-providers.d.ts
|
|
70
|
+
type AccountProviderSource = "local-private-key" | "openfort-embedded" | "injected-eip1193";
|
|
71
|
+
type AccountRequirement = "none" | "counterfactual" | "deployed";
|
|
72
|
+
interface AccountProvider {
|
|
73
|
+
readonly source: AccountProviderSource;
|
|
74
|
+
/**
|
|
75
|
+
* Resolve the signer's EVM address.
|
|
76
|
+
*
|
|
77
|
+
* @determinism MUST return the same `Address` across calls for the
|
|
78
|
+
* lifetime of a single provider instance — the SDK-level deploy mutex
|
|
79
|
+
* keys on `(authUserId, safeAddress)` where `safeAddress` is computed
|
|
80
|
+
* from `getAddress()`'s result before the port's `prepare()` round-trip.
|
|
81
|
+
* If two successive calls returned different addresses, concurrent
|
|
82
|
+
* `deploySafe` invocations would compute different mutex keys and
|
|
83
|
+
* bypass dedup, defeating the mutex.
|
|
84
|
+
*
|
|
85
|
+
* The three sanctioned providers all satisfy this invariant:
|
|
86
|
+
* - `localPrivateKeyAccountProvider` — derives once from the key
|
|
87
|
+
* - `eip1193AccountProvider` — reads `eth_accounts` (idempotent once
|
|
88
|
+
* the wallet is connected; consumer is responsible for connection)
|
|
89
|
+
* - `openfortEmbeddedAccountProvider` — fetches once, caches
|
|
90
|
+
*
|
|
91
|
+
* Custom providers MUST honor this contract.
|
|
92
|
+
*/
|
|
93
|
+
getAddress(): Promise<CapxulResult<Address>>;
|
|
94
|
+
getDeployAccount(): Promise<CapxulResult<Account$1>>;
|
|
95
|
+
}
|
|
96
|
+
interface Eip1193Provider {
|
|
97
|
+
request(args: {
|
|
98
|
+
readonly method: string;
|
|
99
|
+
readonly params?: readonly unknown[];
|
|
100
|
+
}): Promise<unknown>;
|
|
101
|
+
}
|
|
102
|
+
declare function localPrivateKeyAccountProvider(input: {
|
|
103
|
+
readonly privateKey: Hex;
|
|
104
|
+
}): AccountProvider;
|
|
105
|
+
declare function eip1193AccountProvider(input: {
|
|
106
|
+
readonly provider: Eip1193Provider;
|
|
107
|
+
}): AccountProvider;
|
|
108
|
+
declare function openfortEmbeddedAccountProvider(): AccountProvider;
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/signer.d.ts
|
|
111
|
+
interface CapxulSigner {
|
|
112
|
+
/**
|
|
113
|
+
* Signer kind — surfaced on the `accountProviderReady` status so the
|
|
114
|
+
* readiness ladder reports which signer the consumer wired.
|
|
115
|
+
*/
|
|
116
|
+
readonly source: AccountProviderSource;
|
|
117
|
+
/** Owner EOA address — the Safe's single owner. */
|
|
118
|
+
getAddress(): Promise<Address>;
|
|
119
|
+
/**
|
|
120
|
+
* Sign the EIP-712 `SafeOp` digest the backend returns for the prepared
|
|
121
|
+
* deployment UserOperation. Returns the raw 65-byte ECDSA signature; the
|
|
122
|
+
* backend packs `validAfter|validUntil|signature`.
|
|
123
|
+
*/
|
|
124
|
+
signUserOpHash(hash: Hex): Promise<Hex>;
|
|
125
|
+
}
|
|
126
|
+
/** Minimal EIP-1193 surface an injected browser wallet exposes. */
|
|
127
|
+
interface Eip1193RequestProvider {
|
|
128
|
+
request(args: {
|
|
129
|
+
readonly method: string;
|
|
130
|
+
readonly params?: readonly unknown[];
|
|
131
|
+
}): Promise<unknown>;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Browser `CapxulSigner` backed by an injected EIP-1193 wallet (MetaMask, etc.).
|
|
135
|
+
* Signs the SafeOp digest via `eth_sign` (raw-hash signing). The node key signer
|
|
136
|
+
* lives in `@capxul/sdk/node` (`localPrivateKeySigner`). Wallets that disable
|
|
137
|
+
* `eth_sign` must enable raw-hash signing before deployed-account flows run.
|
|
138
|
+
*/
|
|
139
|
+
declare function injectedWalletSigner(provider: Eip1193RequestProvider): CapxulSigner;
|
|
140
|
+
//#endregion
|
|
141
|
+
export { AuthCachePortTag as _, AccountProviderSource as a, eip1193AccountProvider as c, CapxulResult as d, Profile$1 as f, AuthCachePort as g, AuthCacheError as h, AccountProvider as i, localPrivateKeyAccountProvider as l, SmartAccount$1 as m, Eip1193RequestProvider as n, AccountRequirement as o, Session as p, injectedWalletSigner as r, Eip1193Provider as s, CapxulSigner as t, openfortEmbeddedAccountProvider as u, CachedJwt as v };
|
|
142
|
+
//# sourceMappingURL=signer-oaYGfjDe.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signer-oaYGfjDe.d.mts","names":[],"sources":["../src/ports/auth-cache.ts","../src/client/types.ts","../src/client/account-providers.ts","../src/signer.ts"],"mappings":";;;;;;;;AAiBA;;;;;;;;;;;UAAiB,aAAA;EAAA,SACN,UAAA,EAAY,MAAA,CAAO,MAAA,CAAO,WAAA,SAAoB,cAAA;EAAA,SAC9C,UAAA,GAAa,OAAA,EAAS,WAAA,KAAgB,MAAA,CAAO,MAAA,OAAa,cAAA;EAAA,SAC1D,YAAA,EAAc,MAAA,CAAO,MAAA,OAAa,cAAA;EAQc;;;;;EAAA,SADhD,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,SAAA,SAAkB,cAAA;EAAA,SACxC,MAAA,GAAS,GAAA,EAAK,SAAA,KAAc,MAAA,CAAO,MAAA,OAAa,cAAA;EAAA,SAChD,QAAA,EAAU,MAAA,CAAO,MAAA,OAAa,cAAA;AAAA;;;;;;UAQxB,SAAA;EAAA,SACN,KAAA,EAAO,QAAA;EAAA,SACP,eAAA,EAAiB,YAAY;AAAA;AAAA,cACvC,mBAAA;;;cAEY,cAAA,SAAuB,mBAAA;EAAA,SACzB,SAAA;EAAA,SACA,KAAA;AAAA;AAAA,cACN,qBAAA;cAEQ,gBAAA,SAAyB,qBAGnC;;;KClCS,OAAA,GAAU,WAAW;AAAA,KACrB,SAAA,GAAU,OAAY;AAAA,KACtB,cAAA,GAAe,YAAiB;;ADD5C;;;;KCQY,YAAA;EAAA,SACG,EAAA;EAAA,SAAmB,KAAA,EAAO,CAAC;AAAA;EAAA,SAC3B,EAAA;EAAA,SAAoB,KAAA,2BAAgC,WAAA;AAAA;;;KCpBvD,qBAAA;AAAA,KAEA,kBAAA;AAAA,UAEK,eAAA;EAAA,SACN,MAAA,EAAQ,qBAAA;;;;;;;;;;;;;;;;;;;;EAoBjB,UAAA,IAAc,OAAA,CAAQ,YAAA,CAAa,OAAA;EACnC,gBAAA,IAAoB,OAAA,CAAQ,YAAA,CAAa,SAAA;AAAA;AAAA,UAG1B,eAAA;EACf,OAAA,CAAQ,IAAA;IAAA,SACG,MAAA;IAAA,SACA,MAAA;EAAA,IACP,OAAO;AAAA;AAAA,iBAGG,8BAAA,CAA+B,KAAA;EAAA,SACpC,UAAA,EAAY,GAAA;AAAA,IACnB,eAAe;AAAA,iBAcH,sBAAA,CAAuB,KAAA;EAAA,SAC5B,QAAA,EAAU,eAAA;AAAA,IACjB,eAAe;AAAA,iBA0DH,+BAAA,CAAA,GAAmC,eAAe;;;UCrGjD,YAAA;;AHDjB;;;WGMW,MAAA,EAAQ,qBAAA;EHLsC;EGOvD,UAAA,IAAc,OAAA,CAAQ,OAAA;EHNS;;;;;EGY/B,cAAA,CAAe,IAAA,EAAM,GAAA,GAAM,OAAA,CAAQ,GAAA;AAAA;;UAIpB,sBAAA;EACf,OAAA,CAAQ,IAAA;IAAA,SACG,MAAA;IAAA,SACA,MAAA;EAAA,IACP,OAAO;AAAA;;;;;;;iBASG,oBAAA,CAAqB,QAAA,EAAU,sBAAA,GAAyB,YAAY"}
|