@itssergio91/sandman 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/dist/cli/commands/connect.d.ts +5 -1
- package/dist/cli/commands/connect.d.ts.map +1 -1
- package/dist/cli/commands/connect.js +22 -20
- package/dist/cli/commands/connect.js.map +1 -1
- package/dist/cli/commands/create.d.ts +3 -2
- package/dist/cli/commands/create.d.ts.map +1 -1
- package/dist/cli/commands/create.js +53 -16
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/destroy.d.ts +1 -0
- package/dist/cli/commands/destroy.d.ts.map +1 -1
- package/dist/cli/commands/destroy.js +15 -6
- package/dist/cli/commands/destroy.js.map +1 -1
- package/dist/cli/commands/enable.d.ts +5 -1
- package/dist/cli/commands/enable.d.ts.map +1 -1
- package/dist/cli/commands/enable.js +29 -14
- package/dist/cli/commands/enable.js.map +1 -1
- package/dist/cli/commands/init.d.ts +6 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +13 -6
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/status.d.ts +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +34 -23
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +14 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/core/state-store.d.ts +3 -3
- package/dist/core/state-store.d.ts.map +1 -1
- package/dist/core/state-store.js +1 -1
- package/dist/core/state-store.js.map +1 -1
- package/dist/providers/aws/adapter.d.ts +3 -0
- package/dist/providers/aws/adapter.d.ts.map +1 -1
- package/dist/providers/aws/adapter.js +331 -9
- package/dist/providers/aws/adapter.js.map +1 -1
- package/dist/providers/aws/adapter.test.js +107 -0
- package/dist/providers/aws/adapter.test.js.map +1 -1
- package/dist/providers/base.d.ts +2 -0
- package/dist/providers/base.d.ts.map +1 -1
- package/dist/providers/base.js +14 -0
- package/dist/providers/base.js.map +1 -1
- package/dist/providers/cloudflare/adapter.d.ts +12 -0
- package/dist/providers/cloudflare/adapter.d.ts.map +1 -0
- package/dist/providers/cloudflare/adapter.js +85 -0
- package/dist/providers/cloudflare/adapter.js.map +1 -0
- package/dist/providers/cloudflare/adapter.test.d.ts +2 -0
- package/dist/providers/cloudflare/adapter.test.d.ts.map +1 -0
- package/dist/providers/cloudflare/adapter.test.js +178 -0
- package/dist/providers/cloudflare/adapter.test.js.map +1 -0
- package/dist/providers/gcp/adapter.d.ts +3 -0
- package/dist/providers/gcp/adapter.d.ts.map +1 -1
- package/dist/providers/gcp/adapter.js +150 -18
- package/dist/providers/gcp/adapter.js.map +1 -1
- package/dist/providers/gcp/adapter.test.js +122 -15
- package/dist/providers/gcp/adapter.test.js.map +1 -1
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +13 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/vercel/adapter.d.ts +12 -0
- package/dist/providers/vercel/adapter.d.ts.map +1 -0
- package/dist/providers/vercel/adapter.js +74 -0
- package/dist/providers/vercel/adapter.js.map +1 -0
- package/dist/providers/vercel/adapter.test.d.ts +2 -0
- package/dist/providers/vercel/adapter.test.d.ts.map +1 -0
- package/dist/providers/vercel/adapter.test.js +166 -0
- package/dist/providers/vercel/adapter.test.js.map +1 -0
- package/dist/types/index.d.ts +21 -21
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +18 -4
- package/dist/types/index.js.map +1 -1
- package/dist/utils/cost-estimator.d.ts +36 -0
- package/dist/utils/cost-estimator.d.ts.map +1 -0
- package/dist/utils/cost-estimator.js +87 -0
- package/dist/utils/cost-estimator.js.map +1 -0
- package/dist/utils/cost-estimator.test.d.ts +2 -0
- package/dist/utils/cost-estimator.test.d.ts.map +1 -0
- package/dist/utils/cost-estimator.test.js +77 -0
- package/dist/utils/cost-estimator.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { CLOUDFLARE_SERVICES } from "../base.js";
|
|
2
|
+
export class CloudflareAdapter {
|
|
3
|
+
accountId = null;
|
|
4
|
+
async init() {
|
|
5
|
+
const apiToken = process.env.CLOUDFLARE_API_TOKEN;
|
|
6
|
+
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
7
|
+
if (!apiToken) {
|
|
8
|
+
throw new Error("CLOUDFLARE_API_TOKEN environment variable is required. " +
|
|
9
|
+
"Create a token at https://dash.cloudflare.com/profile/api-tokens");
|
|
10
|
+
}
|
|
11
|
+
// Verify token by fetching account info
|
|
12
|
+
const response = await fetch("https://api.cloudflare.com/client/v4/user", {
|
|
13
|
+
headers: {
|
|
14
|
+
Authorization: `Bearer ${apiToken}`,
|
|
15
|
+
"Content-Type": "application/json",
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
if (!response.ok) {
|
|
19
|
+
const body = (await response.json());
|
|
20
|
+
const msg = body.errors?.[0]?.message || response.statusText;
|
|
21
|
+
throw new Error(`Cloudflare authentication failed: ${msg}`);
|
|
22
|
+
}
|
|
23
|
+
if (accountId) {
|
|
24
|
+
this.accountId = accountId;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Fetch first account associated with the token
|
|
28
|
+
const accountsRes = await fetch("https://api.cloudflare.com/client/v4/accounts", {
|
|
29
|
+
headers: {
|
|
30
|
+
Authorization: `Bearer ${apiToken}`,
|
|
31
|
+
"Content-Type": "application/json",
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
if (accountsRes.ok) {
|
|
35
|
+
const data = (await accountsRes.json());
|
|
36
|
+
this.accountId = data.result?.[0]?.id || null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async createEnvironment(name) {
|
|
41
|
+
const now = new Date().toISOString();
|
|
42
|
+
const namespaceId = `sandman-${name}-${Date.now()}`;
|
|
43
|
+
return {
|
|
44
|
+
name,
|
|
45
|
+
provider: "cloudflare",
|
|
46
|
+
accountId: process.env.CLOUDFLARE_ACCOUNT_ID || undefined,
|
|
47
|
+
status: "active",
|
|
48
|
+
services: [],
|
|
49
|
+
resources: {
|
|
50
|
+
namespaceId,
|
|
51
|
+
},
|
|
52
|
+
createdAt: now,
|
|
53
|
+
updatedAt: now,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async enableServices(env, services) {
|
|
57
|
+
const enabledServices = services
|
|
58
|
+
.map((s) => CLOUDFLARE_SERVICES[s])
|
|
59
|
+
.filter(Boolean);
|
|
60
|
+
console.log(`Enabling Cloudflare services: ${enabledServices.join(", ")}`);
|
|
61
|
+
}
|
|
62
|
+
async connect(env) {
|
|
63
|
+
const result = {
|
|
64
|
+
provider: "cloudflare",
|
|
65
|
+
};
|
|
66
|
+
if (env.accountId) {
|
|
67
|
+
result.CLOUDFLARE_ACCOUNT_ID = env.accountId;
|
|
68
|
+
}
|
|
69
|
+
if (process.env.CLOUDFLARE_API_TOKEN) {
|
|
70
|
+
result.CLOUDFLARE_API_TOKEN = process.env.CLOUDFLARE_API_TOKEN;
|
|
71
|
+
}
|
|
72
|
+
if (env.resources.namespaceId) {
|
|
73
|
+
result.CLOUDFLARE_NAMESPACE_ID = env.resources.namespaceId;
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
async destroyEnvironment(env) {
|
|
78
|
+
console.log(`Cleaning up Cloudflare resources for environment: ${env.name}`);
|
|
79
|
+
// Future: delete KV namespaces, R2 buckets, D1 databases via API
|
|
80
|
+
}
|
|
81
|
+
async getStatus(env) {
|
|
82
|
+
return env;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/providers/cloudflare/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.test.d.ts","sourceRoot":"","sources":["../../../src/providers/cloudflare/adapter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { CloudflareAdapter } from "./adapter.js";
|
|
3
|
+
global.fetch = vi.fn();
|
|
4
|
+
describe("CloudflareAdapter", () => {
|
|
5
|
+
let adapter;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
vi.clearAllMocks();
|
|
8
|
+
vi.resetAllMocks();
|
|
9
|
+
adapter = new CloudflareAdapter();
|
|
10
|
+
delete process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
11
|
+
});
|
|
12
|
+
describe("init", () => {
|
|
13
|
+
it("should throw if CLOUDFLARE_API_TOKEN is missing", async () => {
|
|
14
|
+
delete process.env.CLOUDFLARE_API_TOKEN;
|
|
15
|
+
await expect(adapter.init()).rejects.toThrow("CLOUDFLARE_API_TOKEN environment variable is required");
|
|
16
|
+
});
|
|
17
|
+
it("should authenticate and fetch account ID", async () => {
|
|
18
|
+
process.env.CLOUDFLARE_API_TOKEN = "test-token";
|
|
19
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = "abc123";
|
|
20
|
+
global.fetch.mockResolvedValueOnce({
|
|
21
|
+
ok: true,
|
|
22
|
+
json: async () => ({ result: { id: "user123" } }),
|
|
23
|
+
});
|
|
24
|
+
await adapter.init();
|
|
25
|
+
// Would throw if auth failed
|
|
26
|
+
expect(global.fetch).toHaveBeenCalledWith("https://api.cloudflare.com/client/v4/user", expect.any(Object));
|
|
27
|
+
});
|
|
28
|
+
it("should throw on authentication failure", async () => {
|
|
29
|
+
process.env.CLOUDFLARE_API_TOKEN = "bad-token";
|
|
30
|
+
global.fetch.mockResolvedValueOnce({
|
|
31
|
+
ok: false,
|
|
32
|
+
json: async () => ({ errors: [{ message: "Invalid token" }] }),
|
|
33
|
+
});
|
|
34
|
+
await expect(adapter.init()).rejects.toThrow("Cloudflare authentication failed: Invalid token");
|
|
35
|
+
});
|
|
36
|
+
it("should fetch first account when ACCOUNT_ID not set", async () => {
|
|
37
|
+
process.env.CLOUDFLARE_API_TOKEN = "test-token";
|
|
38
|
+
delete process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
39
|
+
global.fetch
|
|
40
|
+
.mockResolvedValueOnce({
|
|
41
|
+
ok: true,
|
|
42
|
+
json: async () => ({ result: { id: "user123" } }),
|
|
43
|
+
})
|
|
44
|
+
.mockResolvedValueOnce({
|
|
45
|
+
ok: true,
|
|
46
|
+
json: async () => ({
|
|
47
|
+
result: [{ id: "account123", name: "My Account" }],
|
|
48
|
+
}),
|
|
49
|
+
});
|
|
50
|
+
await adapter.init();
|
|
51
|
+
expect(global.fetch).toHaveBeenCalledWith("https://api.cloudflare.com/client/v4/accounts", expect.any(Object));
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe("createEnvironment", () => {
|
|
55
|
+
it("should create an environment record with namespaceId", async () => {
|
|
56
|
+
const env = await adapter.createEnvironment("test-env");
|
|
57
|
+
expect(env.name).toBe("test-env");
|
|
58
|
+
expect(env.provider).toBe("cloudflare");
|
|
59
|
+
expect(env.status).toBe("active");
|
|
60
|
+
expect(env.resources.namespaceId).toMatch(/^sandman-test-env-/);
|
|
61
|
+
});
|
|
62
|
+
it("should include accountId from env", async () => {
|
|
63
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = "my-account";
|
|
64
|
+
const env = await adapter.createEnvironment("prod");
|
|
65
|
+
expect(env.accountId).toBe("my-account");
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe("enableServices", () => {
|
|
69
|
+
it("should log services to enable", async () => {
|
|
70
|
+
const env = {
|
|
71
|
+
name: "test",
|
|
72
|
+
provider: "cloudflare",
|
|
73
|
+
status: "active",
|
|
74
|
+
services: [],
|
|
75
|
+
resources: {},
|
|
76
|
+
createdAt: new Date().toISOString(),
|
|
77
|
+
updatedAt: new Date().toISOString(),
|
|
78
|
+
};
|
|
79
|
+
const consoleSpy = vi.spyOn(console, "log");
|
|
80
|
+
await adapter.enableServices(env, ["workers", "kv", "d1"]);
|
|
81
|
+
expect(consoleSpy).toHaveBeenCalledWith("Enabling Cloudflare services: workers, kv, d1");
|
|
82
|
+
consoleSpy.mockRestore();
|
|
83
|
+
});
|
|
84
|
+
it("should filter invalid services", async () => {
|
|
85
|
+
const env = {
|
|
86
|
+
name: "test",
|
|
87
|
+
provider: "cloudflare",
|
|
88
|
+
status: "active",
|
|
89
|
+
services: [],
|
|
90
|
+
resources: {},
|
|
91
|
+
createdAt: new Date().toISOString(),
|
|
92
|
+
updatedAt: new Date().toISOString(),
|
|
93
|
+
};
|
|
94
|
+
const consoleSpy = vi.spyOn(console, "log");
|
|
95
|
+
await adapter.enableServices(env, ["invalid-service"]);
|
|
96
|
+
expect(consoleSpy).toHaveBeenCalledWith("Enabling Cloudflare services: ");
|
|
97
|
+
consoleSpy.mockRestore();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
describe("connect", () => {
|
|
101
|
+
it("should return environment variables", async () => {
|
|
102
|
+
process.env.CLOUDFLARE_API_TOKEN = "my-token";
|
|
103
|
+
process.env.CLOUDFLARE_ACCOUNT_ID = "my-account";
|
|
104
|
+
const env = {
|
|
105
|
+
name: "test",
|
|
106
|
+
provider: "cloudflare",
|
|
107
|
+
status: "active",
|
|
108
|
+
services: [],
|
|
109
|
+
resources: { namespaceId: "ns-123" },
|
|
110
|
+
createdAt: new Date().toISOString(),
|
|
111
|
+
updatedAt: new Date().toISOString(),
|
|
112
|
+
accountId: "my-account",
|
|
113
|
+
};
|
|
114
|
+
const creds = await adapter.connect(env);
|
|
115
|
+
expect(creds.provider).toBe("cloudflare");
|
|
116
|
+
expect(creds.CLOUDFLARE_ACCOUNT_ID).toBe("my-account");
|
|
117
|
+
expect(creds.CLOUDFLARE_API_TOKEN).toBe("my-token");
|
|
118
|
+
expect(creds.CLOUDFLARE_NAMESPACE_ID).toBe("ns-123");
|
|
119
|
+
});
|
|
120
|
+
it("should work without optional fields", async () => {
|
|
121
|
+
const env = {
|
|
122
|
+
name: "test",
|
|
123
|
+
provider: "cloudflare",
|
|
124
|
+
status: "active",
|
|
125
|
+
services: [],
|
|
126
|
+
resources: {},
|
|
127
|
+
createdAt: new Date().toISOString(),
|
|
128
|
+
updatedAt: new Date().toISOString(),
|
|
129
|
+
};
|
|
130
|
+
const creds = await adapter.connect(env);
|
|
131
|
+
expect(creds.provider).toBe("cloudflare");
|
|
132
|
+
expect(creds.CLOUDFLARE_ACCOUNT_ID).toBeUndefined();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe("destroyEnvironment", () => {
|
|
136
|
+
it("should log cleanup message", async () => {
|
|
137
|
+
const env = {
|
|
138
|
+
name: "test",
|
|
139
|
+
provider: "cloudflare",
|
|
140
|
+
status: "active",
|
|
141
|
+
services: [],
|
|
142
|
+
resources: { namespaceId: "ns-123" },
|
|
143
|
+
createdAt: new Date().toISOString(),
|
|
144
|
+
updatedAt: new Date().toISOString(),
|
|
145
|
+
};
|
|
146
|
+
const consoleSpy = vi.spyOn(console, "log");
|
|
147
|
+
await adapter.destroyEnvironment(env);
|
|
148
|
+
expect(consoleSpy).toHaveBeenCalledWith("Cleaning up Cloudflare resources for environment: test");
|
|
149
|
+
consoleSpy.mockRestore();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe("getStatus", () => {
|
|
153
|
+
it("should return environment as-is", async () => {
|
|
154
|
+
const env = {
|
|
155
|
+
name: "test",
|
|
156
|
+
provider: "cloudflare",
|
|
157
|
+
status: "active",
|
|
158
|
+
services: ["workers", "kv"],
|
|
159
|
+
resources: { namespaceId: "ns-123" },
|
|
160
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
161
|
+
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
162
|
+
};
|
|
163
|
+
const result = await adapter.getStatus(env);
|
|
164
|
+
expect(result).toEqual(env);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
describe("interface compliance", () => {
|
|
168
|
+
it("should have all required methods", () => {
|
|
169
|
+
expect(typeof adapter.init).toBe("function");
|
|
170
|
+
expect(typeof adapter.createEnvironment).toBe("function");
|
|
171
|
+
expect(typeof adapter.enableServices).toBe("function");
|
|
172
|
+
expect(typeof adapter.connect).toBe("function");
|
|
173
|
+
expect(typeof adapter.destroyEnvironment).toBe("function");
|
|
174
|
+
expect(typeof adapter.getStatus).toBe("function");
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
//# sourceMappingURL=adapter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.test.js","sourceRoot":"","sources":["../../../src/providers/cloudflare/adapter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,14 +2,17 @@ import { ProviderAdapter } from "../base.js";
|
|
|
2
2
|
import { EnvironmentRecord, ServiceName } from "../../types/index.js";
|
|
3
3
|
export declare class GcpAdapter implements ProviderAdapter {
|
|
4
4
|
private projectId;
|
|
5
|
+
private projectNumber;
|
|
5
6
|
private billingAccountId;
|
|
6
7
|
init(): Promise<void>;
|
|
7
8
|
createEnvironment(name: string): Promise<EnvironmentRecord>;
|
|
9
|
+
private linkBillingAccount;
|
|
8
10
|
enableServices(env: EnvironmentRecord, services: ServiceName[]): Promise<void>;
|
|
9
11
|
connect(env: EnvironmentRecord): Promise<Record<string, string>>;
|
|
10
12
|
destroyEnvironment(env: EnvironmentRecord): Promise<void>;
|
|
11
13
|
getStatus(env: EnvironmentRecord): Promise<EnvironmentRecord>;
|
|
12
14
|
setBillingAccount(accountId: string): void;
|
|
13
15
|
getProjectId(): string | null;
|
|
16
|
+
getProjectNumber(): string | null;
|
|
14
17
|
}
|
|
15
18
|
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/providers/gcp/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEtE,qBAAa,UAAW,YAAW,eAAe;IAChD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,gBAAgB,CAAuB;IAEzC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA8CrB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/providers/gcp/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEtE,qBAAa,UAAW,YAAW,eAAe;IAChD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,gBAAgB,CAAuB;IAEzC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA8CrB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;YA0DnD,kBAAkB;IAuB1B,cAAc,CAClB,GAAG,EAAE,iBAAiB,EACtB,QAAQ,EAAE,WAAW,EAAE,GACtB,OAAO,CAAC,IAAI,CAAC;IAiCV,OAAO,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAYhE,kBAAkB,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBzD,SAAS,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAmDnE,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI1C,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B,gBAAgB,IAAI,MAAM,GAAG,IAAI;CAGlC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { GCP_SERVICES } from "../base.js";
|
|
2
2
|
export class GcpAdapter {
|
|
3
3
|
projectId = null;
|
|
4
|
+
projectNumber = null;
|
|
4
5
|
billingAccountId = null;
|
|
5
6
|
async init() {
|
|
6
7
|
try {
|
|
@@ -42,25 +43,93 @@ export class GcpAdapter {
|
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
async createEnvironment(name) {
|
|
46
|
+
if (!this.projectId) {
|
|
47
|
+
throw new Error("No GCP project configured. Set GCP_PROJECT environment variable or run 'gcloud config set project PROJECT_ID'");
|
|
48
|
+
}
|
|
49
|
+
// Generate a unique project ID for the sandman environment
|
|
45
50
|
const timestamp = Date.now();
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
const sandmanProjectId = `sandman-${name}-${timestamp}`;
|
|
52
|
+
try {
|
|
53
|
+
const { ProjectsClient } = await import("@google-cloud/resource-manager");
|
|
54
|
+
const resourceManagerClient = new ProjectsClient();
|
|
55
|
+
// Create the project
|
|
56
|
+
const [operation] = await resourceManagerClient.createProject({
|
|
57
|
+
project: {
|
|
58
|
+
projectId: sandmanProjectId,
|
|
59
|
+
name: `Sandman Environment: ${name}`,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
// Wait for the operation to complete
|
|
63
|
+
const [projectOperation] = await operation.promise();
|
|
64
|
+
// Get the project details to get the project number
|
|
65
|
+
const [project] = await resourceManagerClient.getProject({
|
|
66
|
+
name: `projects/${sandmanProjectId}`,
|
|
67
|
+
});
|
|
68
|
+
// Store the project ID and number
|
|
69
|
+
this.projectId = sandmanProjectId;
|
|
70
|
+
this.projectNumber = project.projectNumber?.toString() || null;
|
|
71
|
+
// Link billing account if provided
|
|
72
|
+
if (this.billingAccountId) {
|
|
73
|
+
await this.linkBillingAccount(sandmanProjectId);
|
|
74
|
+
}
|
|
75
|
+
const now = new Date().toISOString();
|
|
76
|
+
return {
|
|
77
|
+
name,
|
|
78
|
+
provider: "gcp",
|
|
79
|
+
projectId: sandmanProjectId,
|
|
80
|
+
status: "active",
|
|
81
|
+
services: [],
|
|
82
|
+
resources: {},
|
|
83
|
+
createdAt: now,
|
|
84
|
+
updatedAt: now,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
throw new Error(`Failed to create GCP project: ${error.message ?? "Unknown error"}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async linkBillingAccount(projectId) {
|
|
92
|
+
if (!this.billingAccountId) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const { CloudBillingClient } = await import("@google-cloud/billing");
|
|
97
|
+
const billingClient = new CloudBillingClient();
|
|
98
|
+
// Update project billing info to link the billing account
|
|
99
|
+
await billingClient.updateProjectBillingInfo({
|
|
100
|
+
name: `projects/${projectId}`,
|
|
101
|
+
projectBillingInfo: {
|
|
102
|
+
billingAccountName: `billingAccounts/${this.billingAccountId}`,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
throw new Error(`Failed to link billing account: ${error.message ?? "Unknown error"}`);
|
|
108
|
+
}
|
|
58
109
|
}
|
|
59
110
|
async enableServices(env, services) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
111
|
+
if (!env.projectId) {
|
|
112
|
+
throw new Error("Project ID is required to enable services");
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const { ServiceUsageClient } = await import("@google-cloud/service-usage");
|
|
116
|
+
const serviceUsageClient = new ServiceUsageClient();
|
|
117
|
+
const serviceNames = services.map((s) => GCP_SERVICES[s]).filter(Boolean);
|
|
118
|
+
if (serviceNames.length === 0) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
console.log(`Enabling GCP services: ${serviceNames.join(", ")}`);
|
|
122
|
+
// Enable each service
|
|
123
|
+
for (const serviceName of serviceNames) {
|
|
124
|
+
const request = {
|
|
125
|
+
name: `projects/${env.projectId}/services/${serviceName}`,
|
|
126
|
+
};
|
|
127
|
+
await serviceUsageClient.enableService(request);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
throw new Error(`Failed to enable GCP services: ${error.message ?? "Unknown error"}`);
|
|
132
|
+
}
|
|
64
133
|
}
|
|
65
134
|
async connect(env) {
|
|
66
135
|
const result = {
|
|
@@ -72,10 +141,70 @@ export class GcpAdapter {
|
|
|
72
141
|
return result;
|
|
73
142
|
}
|
|
74
143
|
async destroyEnvironment(env) {
|
|
75
|
-
|
|
144
|
+
if (!env.projectId) {
|
|
145
|
+
throw new Error("Project ID is required to destroy environment");
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
const { ProjectsClient } = await import("@google-cloud/resource-manager");
|
|
149
|
+
const resourceManagerClient = new ProjectsClient();
|
|
150
|
+
// Delete the project
|
|
151
|
+
const [operation] = await resourceManagerClient.deleteProject({
|
|
152
|
+
name: `projects/${env.projectId}`,
|
|
153
|
+
});
|
|
154
|
+
// Wait for the operation to complete
|
|
155
|
+
await operation.promise();
|
|
156
|
+
console.log(`Deleted GCP project: ${env.projectId}`);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
throw new Error(`Failed to delete GCP project: ${error.message ?? "Unknown error"}`);
|
|
160
|
+
}
|
|
76
161
|
}
|
|
77
162
|
async getStatus(env) {
|
|
78
|
-
|
|
163
|
+
if (!env.projectId) {
|
|
164
|
+
return {
|
|
165
|
+
...env,
|
|
166
|
+
status: "failed",
|
|
167
|
+
error: "Project ID not available",
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
const { ProjectsClient } = await import("@google-cloud/resource-manager");
|
|
172
|
+
const resourceManagerClient = new ProjectsClient();
|
|
173
|
+
// Get the project to check its status
|
|
174
|
+
const [project] = await resourceManagerClient.getProject({
|
|
175
|
+
name: `projects/${env.projectId}`,
|
|
176
|
+
});
|
|
177
|
+
// Map GCP project lifecycle state to our status
|
|
178
|
+
let status = env.status;
|
|
179
|
+
const lifecycleState = project.lifecycleState;
|
|
180
|
+
switch (lifecycleState) {
|
|
181
|
+
case "ACTIVE":
|
|
182
|
+
status = "active";
|
|
183
|
+
break;
|
|
184
|
+
case "DELETE_REQUESTED":
|
|
185
|
+
case "DELETE_IN_PROGRESS":
|
|
186
|
+
status = "destroyed";
|
|
187
|
+
break;
|
|
188
|
+
case "FAILED":
|
|
189
|
+
status = "failed";
|
|
190
|
+
break;
|
|
191
|
+
default:
|
|
192
|
+
status = "pending";
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
...env,
|
|
196
|
+
status,
|
|
197
|
+
updatedAt: new Date().toISOString(),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
// If we can't get the project, it might have been deleted
|
|
202
|
+
return {
|
|
203
|
+
...env,
|
|
204
|
+
status: "destroyed",
|
|
205
|
+
updatedAt: new Date().toISOString(),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
79
208
|
}
|
|
80
209
|
setBillingAccount(accountId) {
|
|
81
210
|
this.billingAccountId = accountId;
|
|
@@ -83,5 +212,8 @@ export class GcpAdapter {
|
|
|
83
212
|
getProjectId() {
|
|
84
213
|
return this.projectId;
|
|
85
214
|
}
|
|
215
|
+
getProjectNumber() {
|
|
216
|
+
return this.projectNumber;
|
|
217
|
+
}
|
|
86
218
|
}
|
|
87
219
|
//# sourceMappingURL=adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/providers/gcp/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,YAAY,EAAE,MAAM,YAAY,CAAC;AAG3D,MAAM,OAAO,UAAU;IACb,SAAS,GAAkB,IAAI,CAAC;IAChC,gBAAgB,GAAkB,IAAI,CAAC;IAE/C,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,gCAAgC,CAAC,CAAC;YAC1E,MAAM,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;YAEpC,kDAAkD;YAClD,+CAA+C;YAC/C,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;YAEhE,oBAAoB;YACpB,yBAAyB;YACzB,sDAAsD;YACtD,kCAAkC;YAClC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;YAC3C,MAAM,aAAa,GACjB,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;YAExE,IAAI,UAAU,EAAE,CAAC;gBACf,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC;YAC9B,CAAC;iBAAM,IAAI,aAAa,EAAE,CAAC;gBACzB,IAAI,CAAC,SAAS,GAAG,aAAa,CAAC;YACjC,CAAC;iBAAM,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;gBACxD,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACN,2EAA2E;gBAC3E,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACxB,CAAC;QACH,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;gBAC1C,uCAAuC;gBACvC,MAAM,IAAI,KAAK,CACb,0EAA0E,CAC3E,CAAC;YACJ,CAAC;YACD,IACE,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC;gBACzC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,aAAa,CAAC,EACtC,CAAC;gBACD,MAAM,IAAI,KAAK,CACb,0EAA0E,CAC3E,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,IAAY;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/providers/gcp/adapter.ts"],"names":[],"mappings":"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"}
|