@itssergio91/sandman 0.1.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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +321 -0
  3. package/dist/cli/commands/connect.d.ts +3 -0
  4. package/dist/cli/commands/connect.d.ts.map +1 -0
  5. package/dist/cli/commands/connect.js +64 -0
  6. package/dist/cli/commands/connect.js.map +1 -0
  7. package/dist/cli/commands/create.d.ts +8 -0
  8. package/dist/cli/commands/create.d.ts.map +1 -0
  9. package/dist/cli/commands/create.js +45 -0
  10. package/dist/cli/commands/create.js.map +1 -0
  11. package/dist/cli/commands/destroy.d.ts +7 -0
  12. package/dist/cli/commands/destroy.d.ts.map +1 -0
  13. package/dist/cli/commands/destroy.js +49 -0
  14. package/dist/cli/commands/destroy.js.map +1 -0
  15. package/dist/cli/commands/enable.d.ts +4 -0
  16. package/dist/cli/commands/enable.d.ts.map +1 -0
  17. package/dist/cli/commands/enable.js +59 -0
  18. package/dist/cli/commands/enable.js.map +1 -0
  19. package/dist/cli/commands/init.d.ts +3 -0
  20. package/dist/cli/commands/init.d.ts.map +1 -0
  21. package/dist/cli/commands/init.js +23 -0
  22. package/dist/cli/commands/init.js.map +1 -0
  23. package/dist/cli/commands/list.d.ts +7 -0
  24. package/dist/cli/commands/list.d.ts.map +1 -0
  25. package/dist/cli/commands/list.js +28 -0
  26. package/dist/cli/commands/list.js.map +1 -0
  27. package/dist/cli/commands/status.d.ts +7 -0
  28. package/dist/cli/commands/status.d.ts.map +1 -0
  29. package/dist/cli/commands/status.js +49 -0
  30. package/dist/cli/commands/status.js.map +1 -0
  31. package/dist/cli/index.d.ts +6 -0
  32. package/dist/cli/index.d.ts.map +1 -0
  33. package/dist/cli/index.js +73 -0
  34. package/dist/cli/index.js.map +1 -0
  35. package/dist/core/state-store.d.ts +18 -0
  36. package/dist/core/state-store.d.ts.map +1 -0
  37. package/dist/core/state-store.js +71 -0
  38. package/dist/core/state-store.js.map +1 -0
  39. package/dist/core/state-store.test.d.ts +2 -0
  40. package/dist/core/state-store.test.d.ts.map +1 -0
  41. package/dist/core/state-store.test.js +183 -0
  42. package/dist/core/state-store.test.js.map +1 -0
  43. package/dist/index.d.ts +3 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +4 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/providers/aws/adapter.d.ts +17 -0
  48. package/dist/providers/aws/adapter.d.ts.map +1 -0
  49. package/dist/providers/aws/adapter.js +106 -0
  50. package/dist/providers/aws/adapter.js.map +1 -0
  51. package/dist/providers/aws/adapter.test.d.ts +2 -0
  52. package/dist/providers/aws/adapter.test.d.ts.map +1 -0
  53. package/dist/providers/aws/adapter.test.js +154 -0
  54. package/dist/providers/aws/adapter.test.js.map +1 -0
  55. package/dist/providers/base.d.ts +12 -0
  56. package/dist/providers/base.d.ts.map +1 -0
  57. package/dist/providers/base.js +13 -0
  58. package/dist/providers/base.js.map +1 -0
  59. package/dist/providers/base.test.d.ts +2 -0
  60. package/dist/providers/base.test.d.ts.map +1 -0
  61. package/dist/providers/base.test.js +50 -0
  62. package/dist/providers/base.test.js.map +1 -0
  63. package/dist/providers/gcp/adapter.d.ts +15 -0
  64. package/dist/providers/gcp/adapter.d.ts.map +1 -0
  65. package/dist/providers/gcp/adapter.js +87 -0
  66. package/dist/providers/gcp/adapter.js.map +1 -0
  67. package/dist/providers/gcp/adapter.test.d.ts +2 -0
  68. package/dist/providers/gcp/adapter.test.d.ts.map +1 -0
  69. package/dist/providers/gcp/adapter.test.js +135 -0
  70. package/dist/providers/gcp/adapter.test.js.map +1 -0
  71. package/dist/types/index.d.ts +139 -0
  72. package/dist/types/index.d.ts.map +1 -0
  73. package/dist/types/index.js +37 -0
  74. package/dist/types/index.js.map +1 -0
  75. package/package.json +72 -0
@@ -0,0 +1,106 @@
1
+ export class AwsAdapter {
2
+ accountId = null;
3
+ region = "us-east-1";
4
+ async init() {
5
+ try {
6
+ const { STSClient, GetCallerIdentityCommand } = await import("@aws-sdk/client-sts");
7
+ const client = new STSClient({});
8
+ const command = new GetCallerIdentityCommand({});
9
+ const response = await client.send(command);
10
+ this.accountId = response.Account || null;
11
+ this.region = process.env.AWS_DEFAULT_REGION || "us-east-1";
12
+ }
13
+ catch (error) {
14
+ if (error.name === "CredentialsProviderError") {
15
+ throw new Error('AWS credentials required. Configure with "aws configure"');
16
+ }
17
+ throw error;
18
+ }
19
+ }
20
+ async createEnvironment(name) {
21
+ const bucketName = `sandman-${name}-${Date.now()}`;
22
+ try {
23
+ const { S3Client, CreateBucketCommand } = await import("@aws-sdk/client-s3");
24
+ const client = new S3Client({ region: this.region });
25
+ await client.send(new CreateBucketCommand({
26
+ Bucket: bucketName,
27
+ }));
28
+ }
29
+ catch (error) {
30
+ if (error.name !== "BucketAlreadyOwnedByYou") {
31
+ console.warn("Could not create bucket:", error.message);
32
+ }
33
+ }
34
+ const now = new Date().toISOString();
35
+ return {
36
+ name,
37
+ provider: "aws",
38
+ accountId: this.accountId || undefined,
39
+ region: this.region,
40
+ status: "active",
41
+ services: [],
42
+ resources: {
43
+ bucketName,
44
+ },
45
+ createdAt: now,
46
+ updatedAt: now,
47
+ };
48
+ }
49
+ async enableServices(env, services) {
50
+ console.log(`Enabling AWS services: ${services.join(", ")}`);
51
+ }
52
+ async connect(env) {
53
+ const result = {
54
+ provider: "aws",
55
+ };
56
+ if (env.accountId) {
57
+ result.AWS_ACCOUNT_ID = env.accountId;
58
+ }
59
+ if (env.region) {
60
+ result.AWS_REGION = env.region;
61
+ }
62
+ if (env.resources.bucketName) {
63
+ result.AWS_S3_BUCKET = env.resources.bucketName;
64
+ }
65
+ return result;
66
+ }
67
+ async destroyEnvironment(env) {
68
+ if (env.resources.bucketName) {
69
+ try {
70
+ const { S3Client, DeleteBucketCommand, ListObjectsV2Command, DeleteObjectsCommand, } = await import("@aws-sdk/client-s3");
71
+ const client = new S3Client({ region: env.region });
72
+ const listResponse = await client.send(new ListObjectsV2Command({
73
+ Bucket: env.resources.bucketName,
74
+ }));
75
+ if (listResponse.Contents?.length) {
76
+ await client.send(new DeleteObjectsCommand({
77
+ Bucket: env.resources.bucketName,
78
+ Delete: {
79
+ Objects: listResponse.Contents.map((obj) => ({
80
+ Key: obj.Key,
81
+ })),
82
+ },
83
+ }));
84
+ }
85
+ await client.send(new DeleteBucketCommand({
86
+ Bucket: env.resources.bucketName,
87
+ }));
88
+ }
89
+ catch (error) {
90
+ if (error.name !== "NoSuchBucket") {
91
+ console.warn("Could not delete bucket:", error.message);
92
+ }
93
+ }
94
+ }
95
+ }
96
+ async getStatus(env) {
97
+ return env;
98
+ }
99
+ getAccountInfo() {
100
+ return {
101
+ accountId: this.accountId,
102
+ region: this.region,
103
+ };
104
+ }
105
+ }
106
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/providers/aws/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=adapter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.test.d.ts","sourceRoot":"","sources":["../../../src/providers/aws/adapter.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,154 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { AwsAdapter } from "./adapter.js";
3
+ vi.mock("@aws-sdk/client-sts", () => ({
4
+ STSClient: vi.fn().mockImplementation(() => ({
5
+ send: vi.fn().mockResolvedValue({
6
+ Account: "123456789012",
7
+ Arn: "arn:aws:sts::123456789012:assumed-role/test",
8
+ }),
9
+ })),
10
+ GetCallerIdentityCommand: vi.fn().mockImplementation(() => ({})),
11
+ }));
12
+ vi.mock("@aws-sdk/client-s3", () => ({
13
+ S3Client: vi.fn().mockImplementation(() => ({
14
+ send: vi.fn().mockResolvedValue({}),
15
+ })),
16
+ CreateBucketCommand: vi.fn().mockImplementation(() => ({})),
17
+ DeleteBucketCommand: vi.fn().mockImplementation(() => ({})),
18
+ ListObjectsV2Command: vi.fn().mockImplementation(() => ({ Contents: [] })),
19
+ DeleteObjectsCommand: vi.fn().mockImplementation(() => ({})),
20
+ }));
21
+ describe("AwsAdapter", () => {
22
+ let adapter;
23
+ beforeEach(() => {
24
+ vi.clearAllMocks();
25
+ adapter = new AwsAdapter();
26
+ });
27
+ afterEach(() => {
28
+ vi.resetModules();
29
+ });
30
+ describe("init", () => {
31
+ it("should verify credentials and detect account ID", async () => {
32
+ await adapter.init();
33
+ const info = adapter.getAccountInfo();
34
+ expect(info.accountId).toBe("123456789012");
35
+ expect(info.region).toBe("us-east-1");
36
+ });
37
+ it("should respect AWS_DEFAULT_REGION env var", async () => {
38
+ process.env.AWS_DEFAULT_REGION = "eu-west-1";
39
+ const newAdapter = new AwsAdapter();
40
+ await newAdapter.init();
41
+ const info = newAdapter.getAccountInfo();
42
+ expect(info.region).toBe("eu-west-1");
43
+ delete process.env.AWS_DEFAULT_REGION;
44
+ });
45
+ });
46
+ describe("createEnvironment", () => {
47
+ it("should create an environment with S3 bucket", async () => {
48
+ const env = await adapter.createEnvironment("test-env");
49
+ expect(env.name).toBe("test-env");
50
+ expect(env.provider).toBe("aws");
51
+ expect(env.status).toBe("active");
52
+ expect(env.resources.bucketName).toMatch(/^sandman-test-env-/);
53
+ });
54
+ it("should use account ID from init", async () => {
55
+ await adapter.init();
56
+ const env = await adapter.createEnvironment("my-env");
57
+ expect(env.accountId).toBe("123456789012");
58
+ });
59
+ });
60
+ describe("connect", () => {
61
+ it("should return environment variables", async () => {
62
+ const env = {
63
+ name: "test",
64
+ provider: "aws",
65
+ status: "active",
66
+ services: [],
67
+ resources: { bucketName: "test-bucket" },
68
+ createdAt: new Date().toISOString(),
69
+ updatedAt: new Date().toISOString(),
70
+ accountId: "123456789012",
71
+ region: "us-east-1",
72
+ };
73
+ const creds = await adapter.connect(env);
74
+ expect(creds.provider).toBe("aws");
75
+ expect(creds.AWS_ACCOUNT_ID).toBe("123456789012");
76
+ expect(creds.AWS_REGION).toBe("us-east-1");
77
+ expect(creds.AWS_S3_BUCKET).toBe("test-bucket");
78
+ });
79
+ it("should work without optional fields", async () => {
80
+ const env = {
81
+ name: "test",
82
+ provider: "aws",
83
+ status: "active",
84
+ services: [],
85
+ resources: {},
86
+ createdAt: new Date().toISOString(),
87
+ updatedAt: new Date().toISOString(),
88
+ };
89
+ const creds = await adapter.connect(env);
90
+ expect(creds.provider).toBe("aws");
91
+ expect(creds.AWS_ACCOUNT_ID).toBeUndefined();
92
+ });
93
+ });
94
+ describe("destroyEnvironment", () => {
95
+ it("should delete bucket and clean up resources", async () => {
96
+ const env = {
97
+ name: "test",
98
+ provider: "aws",
99
+ status: "active",
100
+ services: [],
101
+ resources: { bucketName: "test-bucket" },
102
+ createdAt: new Date().toISOString(),
103
+ updatedAt: new Date().toISOString(),
104
+ region: "us-east-1",
105
+ };
106
+ await expect(adapter.destroyEnvironment(env)).resolves.not.toThrow();
107
+ });
108
+ it("should handle missing bucket gracefully", async () => {
109
+ const env = {
110
+ name: "test",
111
+ provider: "aws",
112
+ status: "active",
113
+ services: [],
114
+ resources: {},
115
+ createdAt: new Date().toISOString(),
116
+ updatedAt: new Date().toISOString(),
117
+ };
118
+ await expect(adapter.destroyEnvironment(env)).resolves.not.toThrow();
119
+ });
120
+ });
121
+ describe("enableServices", () => {
122
+ it("should log services to enable", async () => {
123
+ const env = {
124
+ name: "test",
125
+ provider: "aws",
126
+ status: "active",
127
+ services: [],
128
+ resources: {},
129
+ createdAt: new Date().toISOString(),
130
+ updatedAt: new Date().toISOString(),
131
+ };
132
+ const consoleSpy = vi.spyOn(console, "log");
133
+ await adapter.enableServices(env, ["s3", "lambda"]);
134
+ expect(consoleSpy).toHaveBeenCalledWith("Enabling AWS services: s3, lambda");
135
+ consoleSpy.mockRestore();
136
+ });
137
+ });
138
+ describe("getStatus", () => {
139
+ it("should return environment as-is", async () => {
140
+ const env = {
141
+ name: "test",
142
+ provider: "aws",
143
+ status: "active",
144
+ services: ["s3"],
145
+ resources: { bucketName: "my-bucket" },
146
+ createdAt: "2026-01-01T00:00:00.000Z",
147
+ updatedAt: "2026-01-01T00:00:00.000Z",
148
+ };
149
+ const result = await adapter.getStatus(env);
150
+ expect(result).toEqual(env);
151
+ });
152
+ });
153
+ });
154
+ //# sourceMappingURL=adapter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.test.js","sourceRoot":"","sources":["../../../src/providers/aws/adapter.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { EnvironmentRecord, ServiceName } from '../types/index.js';
2
+ export interface ProviderAdapter {
3
+ init(): Promise<void>;
4
+ createEnvironment(name: string): Promise<EnvironmentRecord>;
5
+ enableServices(env: EnvironmentRecord, services: ServiceName[]): Promise<void>;
6
+ connect(env: EnvironmentRecord): Promise<Record<string, string>>;
7
+ destroyEnvironment(env: EnvironmentRecord): Promise<void>;
8
+ getStatus(env: EnvironmentRecord): Promise<EnvironmentRecord>;
9
+ }
10
+ export declare const GCP_SERVICES: Record<string, string>;
11
+ export declare const AWS_SERVICES: Record<string, string>;
12
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/providers/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC9B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC5D,cAAc,CAAC,GAAG,EAAE,iBAAiB,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjE,kBAAkB,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,SAAS,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC/D;AAED,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK/C,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK/C,CAAC"}
@@ -0,0 +1,13 @@
1
+ export const GCP_SERVICES = {
2
+ compute: 'compute.googleapis.com',
3
+ storage: 'storage.googleapis.com',
4
+ cloudrun: 'run.googleapis.com',
5
+ iam: 'iam.googleapis.com',
6
+ };
7
+ export const AWS_SERVICES = {
8
+ ec2: 'ec2',
9
+ s3: 's3',
10
+ lambda: 'lambda',
11
+ iam: 'iam',
12
+ };
13
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/providers/base.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,YAAY,GAA2B;IAClD,OAAO,EAAE,wBAAwB;IACjC,OAAO,EAAE,wBAAwB;IACjC,QAAQ,EAAE,oBAAoB;IAC9B,GAAG,EAAE,oBAAoB;CAC1B,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAA2B;IAClD,GAAG,EAAE,KAAK;IACV,EAAE,EAAE,IAAI;IACR,MAAM,EAAE,QAAQ;IAChB,GAAG,EAAE,KAAK;CACX,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=base.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.test.d.ts","sourceRoot":"","sources":["../../src/providers/base.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,50 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ describe('ProviderAdapter (interface contract)', () => {
3
+ it('should have all required methods', () => {
4
+ const adapter = {
5
+ init: async () => { },
6
+ createEnvironment: async (name) => ({
7
+ name,
8
+ provider: 'gcp',
9
+ status: 'active',
10
+ services: [],
11
+ resources: {},
12
+ createdAt: new Date().toISOString(),
13
+ updatedAt: new Date().toISOString(),
14
+ }),
15
+ enableServices: async () => { },
16
+ connect: async () => ({}),
17
+ destroyEnvironment: async () => { },
18
+ getStatus: async (env) => env,
19
+ };
20
+ expect(typeof adapter.init).toBe('function');
21
+ expect(typeof adapter.createEnvironment).toBe('function');
22
+ expect(typeof adapter.enableServices).toBe('function');
23
+ expect(typeof adapter.connect).toBe('function');
24
+ expect(typeof adapter.destroyEnvironment).toBe('function');
25
+ expect(typeof adapter.getStatus).toBe('function');
26
+ });
27
+ it('createEnvironment should return EnvironmentRecord', async () => {
28
+ const adapter = {
29
+ init: async () => { },
30
+ createEnvironment: async (name) => ({
31
+ name,
32
+ provider: 'gcp',
33
+ status: 'active',
34
+ services: [],
35
+ resources: {},
36
+ createdAt: new Date().toISOString(),
37
+ updatedAt: new Date().toISOString(),
38
+ }),
39
+ enableServices: async () => { },
40
+ connect: async () => ({}),
41
+ destroyEnvironment: async () => { },
42
+ getStatus: async (env) => env,
43
+ };
44
+ const result = await adapter.createEnvironment('test');
45
+ expect(result.name).toBe('test');
46
+ expect(result.provider).toBe('gcp');
47
+ expect(result.status).toBe('active');
48
+ });
49
+ });
50
+ //# sourceMappingURL=base.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.test.js","sourceRoot":"","sources":["../../src/providers/base.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAI9C,QAAQ,CAAC,sCAAsC,EAAE,GAAG,EAAE;IACpD,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,OAAO,GAAoB;YAC/B,IAAI,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;YACpB,iBAAiB,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE,CAAC,CAAC;gBAC1C,IAAI;gBACJ,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,QAAQ;gBAChB,QAAQ,EAAE,EAAE;gBACZ,SAAS,EAAE,EAAE;gBACb,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;YACF,cAAc,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;YAC9B,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YACzB,kBAAkB,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;YAClC,SAAS,EAAE,KAAK,EAAE,GAAsB,EAAE,EAAE,CAAC,GAAG;SACjD,CAAC;QAEF,MAAM,CAAC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,CAAC,OAAO,OAAO,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1D,MAAM,CAAC,OAAO,OAAO,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,CAAC,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,CAAC,OAAO,OAAO,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3D,MAAM,CAAC,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,OAAO,GAAoB;YAC/B,IAAI,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;YACpB,iBAAiB,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE,CAAC,CAAC;gBAC1C,IAAI;gBACJ,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,QAAQ;gBAChB,QAAQ,EAAE,EAAE;gBACZ,SAAS,EAAE,EAAE;gBACb,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;YACF,cAAc,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;YAC9B,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YACzB,kBAAkB,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;YAClC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG;SAC9B,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { ProviderAdapter } from "../base.js";
2
+ import { EnvironmentRecord, ServiceName } from "../../types/index.js";
3
+ export declare class GcpAdapter implements ProviderAdapter {
4
+ private projectId;
5
+ private billingAccountId;
6
+ init(): Promise<void>;
7
+ createEnvironment(name: string): Promise<EnvironmentRecord>;
8
+ enableServices(env: EnvironmentRecord, services: ServiceName[]): Promise<void>;
9
+ connect(env: EnvironmentRecord): Promise<Record<string, string>>;
10
+ destroyEnvironment(env: EnvironmentRecord): Promise<void>;
11
+ getStatus(env: EnvironmentRecord): Promise<EnvironmentRecord>;
12
+ setBillingAccount(accountId: string): void;
13
+ getProjectId(): string | null;
14
+ }
15
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +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;IAiB3D,cAAc,CAClB,GAAG,EAAE,iBAAiB,EACtB,QAAQ,EAAE,WAAW,EAAE,GACtB,OAAO,CAAC,IAAI,CAAC;IAOV,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;IAIzD,SAAS,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAInE,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI1C,YAAY,IAAI,MAAM,GAAG,IAAI;CAG9B"}
@@ -0,0 +1,87 @@
1
+ import { GCP_SERVICES } from "../base.js";
2
+ export class GcpAdapter {
3
+ projectId = null;
4
+ billingAccountId = null;
5
+ async init() {
6
+ try {
7
+ const { ProjectsClient } = await import("@google-cloud/resource-manager");
8
+ const client = new ProjectsClient();
9
+ // Verify authentication by searching for projects
10
+ // This works even without specifying a project
11
+ const [projects] = await client.searchProjects({ pageSize: 1 });
12
+ // Get project from:
13
+ // 1. GCP_PROJECT env var
14
+ // 2. gcloud config (via GCLOUD_CONFIG env or default)
15
+ // 3. First project found (if any)
16
+ const envProject = process.env.GCP_PROJECT;
17
+ const gcloudProject = process.env.GOOGLE_CLOUD_PROJECT || process.env.CLOUDSDK_CORE_PROJECT;
18
+ if (envProject) {
19
+ this.projectId = envProject;
20
+ }
21
+ else if (gcloudProject) {
22
+ this.projectId = gcloudProject;
23
+ }
24
+ else if (projects.length > 0 && projects[0].projectId) {
25
+ this.projectId = projects[0].projectId;
26
+ }
27
+ else {
28
+ // Auth works but no projects - user needs to create one or set GCP_PROJECT
29
+ this.projectId = null;
30
+ }
31
+ }
32
+ catch (error) {
33
+ if (error.code === 7 || error.code === 16) {
34
+ // PERMISSION_DENIED or UNAUTHENTICATED
35
+ throw new Error('GCP authentication required. Run "gcloud auth application-default login"');
36
+ }
37
+ if (error.message?.includes("Could not load") ||
38
+ error.message?.includes("credentials")) {
39
+ throw new Error('GCP authentication required. Run "gcloud auth application-default login"');
40
+ }
41
+ throw error;
42
+ }
43
+ }
44
+ async createEnvironment(name) {
45
+ const timestamp = Date.now();
46
+ const projectId = `sandman-${name}-${timestamp}`;
47
+ const now = new Date().toISOString();
48
+ return {
49
+ name,
50
+ provider: "gcp",
51
+ projectId,
52
+ status: "active",
53
+ services: [],
54
+ resources: {},
55
+ createdAt: now,
56
+ updatedAt: now,
57
+ };
58
+ }
59
+ async enableServices(env, services) {
60
+ const enabledServices = services
61
+ .map((s) => GCP_SERVICES[s])
62
+ .filter(Boolean);
63
+ console.log(`Enabling GCP services: ${enabledServices.join(", ")}`);
64
+ }
65
+ async connect(env) {
66
+ const result = {
67
+ provider: "gcp",
68
+ };
69
+ if (env.projectId) {
70
+ result.GCP_PROJECT = env.projectId;
71
+ }
72
+ return result;
73
+ }
74
+ async destroyEnvironment(env) {
75
+ console.log(`Would delete GCP project: ${env.projectId}`);
76
+ }
77
+ async getStatus(env) {
78
+ return env;
79
+ }
80
+ setBillingAccount(accountId) {
81
+ this.billingAccountId = accountId;
82
+ }
83
+ getProjectId() {
84
+ return this.projectId;
85
+ }
86
+ }
87
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/providers/gcp/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=adapter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.test.d.ts","sourceRoot":"","sources":["../../../src/providers/gcp/adapter.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,135 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { GcpAdapter } from "./adapter.js";
3
+ vi.mock("@google-cloud/resource-manager", () => ({
4
+ ProjectsClient: vi.fn().mockImplementation(() => ({
5
+ searchProjects: vi
6
+ .fn()
7
+ .mockResolvedValue([
8
+ [{ projectId: "test-project", name: "Test Project" }],
9
+ ]),
10
+ getProject: vi
11
+ .fn()
12
+ .mockResolvedValue([{ projectId: "test-project", name: "Test" }]),
13
+ })),
14
+ }));
15
+ describe("GcpAdapter", () => {
16
+ let adapter;
17
+ beforeEach(() => {
18
+ vi.clearAllMocks();
19
+ adapter = new GcpAdapter();
20
+ });
21
+ describe("init", () => {
22
+ it("should authenticate successfully", async () => {
23
+ await expect(adapter.init()).resolves.not.toThrow();
24
+ });
25
+ it("should set projectId from environment variable", async () => {
26
+ process.env.GCP_PROJECT = "my-project";
27
+ const newAdapter = new GcpAdapter();
28
+ await newAdapter.init();
29
+ expect(newAdapter.getProjectId()).toBe("my-project");
30
+ delete process.env.GCP_PROJECT;
31
+ });
32
+ it("should set projectId from found projects", async () => {
33
+ delete process.env.GCP_PROJECT;
34
+ delete process.env.GOOGLE_CLOUD_PROJECT;
35
+ delete process.env.CLOUDSDK_CORE_PROJECT;
36
+ await adapter.init();
37
+ expect(adapter.getProjectId()).toBe("test-project");
38
+ });
39
+ });
40
+ describe("createEnvironment", () => {
41
+ it("should create an environment record", async () => {
42
+ const env = await adapter.createEnvironment("test-env");
43
+ expect(env.name).toBe("test-env");
44
+ expect(env.provider).toBe("gcp");
45
+ expect(env.status).toBe("active");
46
+ expect(env.projectId).toMatch(/^sandman-test-env-/);
47
+ });
48
+ });
49
+ describe("enableServices", () => {
50
+ it("should log services to enable", async () => {
51
+ const env = {
52
+ name: "test",
53
+ provider: "gcp",
54
+ status: "active",
55
+ services: [],
56
+ resources: {},
57
+ projectId: "test-project",
58
+ createdAt: new Date().toISOString(),
59
+ updatedAt: new Date().toISOString(),
60
+ };
61
+ const consoleSpy = vi.spyOn(console, "log");
62
+ await adapter.enableServices(env, ["compute", "storage"]);
63
+ expect(consoleSpy).toHaveBeenCalledWith("Enabling GCP services: compute.googleapis.com, storage.googleapis.com");
64
+ consoleSpy.mockRestore();
65
+ });
66
+ });
67
+ describe("connect", () => {
68
+ it("should return environment variables", async () => {
69
+ const env = {
70
+ name: "test",
71
+ provider: "gcp",
72
+ status: "active",
73
+ services: [],
74
+ resources: {},
75
+ projectId: "my-gcp-project",
76
+ createdAt: new Date().toISOString(),
77
+ updatedAt: new Date().toISOString(),
78
+ };
79
+ const creds = await adapter.connect(env);
80
+ expect(creds.provider).toBe("gcp");
81
+ expect(creds.GCP_PROJECT).toBe("my-gcp-project");
82
+ });
83
+ });
84
+ describe("destroyEnvironment", () => {
85
+ it("should log project deletion", async () => {
86
+ const env = {
87
+ name: "test",
88
+ provider: "gcp",
89
+ status: "active",
90
+ services: [],
91
+ resources: {},
92
+ projectId: "test-project",
93
+ createdAt: new Date().toISOString(),
94
+ updatedAt: new Date().toISOString(),
95
+ };
96
+ const consoleSpy = vi.spyOn(console, "log");
97
+ await adapter.destroyEnvironment(env);
98
+ expect(consoleSpy).toHaveBeenCalledWith("Would delete GCP project: test-project");
99
+ consoleSpy.mockRestore();
100
+ });
101
+ });
102
+ describe("getStatus", () => {
103
+ it("should return environment as-is", async () => {
104
+ const env = {
105
+ name: "test",
106
+ provider: "gcp",
107
+ status: "active",
108
+ services: ["compute"],
109
+ resources: {},
110
+ projectId: "test-project",
111
+ createdAt: "2026-01-01T00:00:00.000Z",
112
+ updatedAt: "2026-01-01T00:00:00.000Z",
113
+ };
114
+ const result = await adapter.getStatus(env);
115
+ expect(result).toEqual(env);
116
+ });
117
+ });
118
+ describe("setBillingAccount", () => {
119
+ it("should set billing account", () => {
120
+ adapter.setBillingAccount("123456-ABCDEF");
121
+ // Internal state, just verify it doesn't throw
122
+ });
123
+ });
124
+ describe("interface compliance", () => {
125
+ it("should have all required methods", () => {
126
+ expect(typeof adapter.init).toBe("function");
127
+ expect(typeof adapter.createEnvironment).toBe("function");
128
+ expect(typeof adapter.enableServices).toBe("function");
129
+ expect(typeof adapter.connect).toBe("function");
130
+ expect(typeof adapter.destroyEnvironment).toBe("function");
131
+ expect(typeof adapter.getStatus).toBe("function");
132
+ });
133
+ });
134
+ });
135
+ //# sourceMappingURL=adapter.test.js.map