puls-dev 0.1.9 → 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.
Files changed (69) hide show
  1. package/README.md +8 -8
  2. package/dist/index.d.ts +0 -7
  3. package/dist/index.js +0 -7
  4. package/dist/providers/aws/api.d.ts +4 -0
  5. package/dist/providers/aws/api.js +4 -0
  6. package/dist/providers/aws/cloudwatch.d.ts +44 -0
  7. package/dist/providers/aws/cloudwatch.js +205 -0
  8. package/dist/providers/aws/cloudwatch.test.d.ts +1 -0
  9. package/dist/providers/aws/cloudwatch.test.js +224 -0
  10. package/dist/providers/aws/fargate.d.ts +2 -0
  11. package/dist/providers/aws/fargate.js +6 -0
  12. package/dist/providers/aws/iam.d.ts +52 -0
  13. package/dist/providers/aws/iam.js +307 -0
  14. package/dist/providers/aws/iam.test.d.ts +1 -0
  15. package/dist/providers/aws/iam.test.js +367 -0
  16. package/dist/providers/aws/index.d.ts +8 -0
  17. package/dist/providers/aws/index.js +8 -0
  18. package/dist/providers/aws/lambda.d.ts +3 -1
  19. package/dist/providers/aws/lambda.js +17 -8
  20. package/dist/providers/aws/lambda.test.d.ts +1 -0
  21. package/dist/providers/aws/lambda.test.js +189 -0
  22. package/dist/providers/aws/rds.d.ts +1 -0
  23. package/dist/providers/aws/rds.js +4 -1
  24. package/dist/providers/aws/route53.d.ts +1 -1
  25. package/dist/providers/aws/route53.js +20 -12
  26. package/dist/providers/aws/route53.test.d.ts +1 -0
  27. package/dist/providers/aws/route53.test.js +229 -0
  28. package/dist/providers/aws/s3.d.ts +3 -0
  29. package/dist/providers/aws/s3.js +65 -3
  30. package/dist/providers/aws/s3.test.d.ts +1 -0
  31. package/dist/providers/aws/s3.test.js +172 -0
  32. package/dist/providers/aws/sns.d.ts +22 -0
  33. package/dist/providers/aws/sns.js +146 -0
  34. package/dist/providers/aws/sns.test.d.ts +1 -0
  35. package/dist/providers/aws/sns.test.js +162 -0
  36. package/dist/providers/do/api.js +5 -1
  37. package/dist/providers/do/certificate.test.d.ts +1 -0
  38. package/dist/providers/do/certificate.test.js +133 -0
  39. package/dist/providers/do/domain.d.ts +12 -1
  40. package/dist/providers/do/domain.js +129 -13
  41. package/dist/providers/do/domain.test.d.ts +1 -0
  42. package/dist/providers/do/domain.test.js +200 -0
  43. package/dist/providers/do/droplet.js +2 -2
  44. package/dist/providers/do/droplet.test.d.ts +1 -0
  45. package/dist/providers/do/droplet.test.js +265 -0
  46. package/dist/providers/do/firewall.test.d.ts +1 -0
  47. package/dist/providers/do/firewall.test.js +176 -0
  48. package/dist/providers/do/index.d.ts +1 -0
  49. package/dist/providers/do/index.js +1 -0
  50. package/dist/providers/do/load_balancer.d.ts +39 -5
  51. package/dist/providers/do/load_balancer.js +272 -30
  52. package/dist/providers/do/load_balancer.test.d.ts +1 -0
  53. package/dist/providers/do/load_balancer.test.js +269 -0
  54. package/dist/providers/firebase/api.js +2 -2
  55. package/dist/providers/firebase/functions.d.ts +1 -0
  56. package/dist/providers/firebase/functions.js +24 -10
  57. package/dist/providers/firebase/functions.test.d.ts +1 -0
  58. package/dist/providers/firebase/functions.test.js +297 -0
  59. package/dist/providers/firebase/hosting.js +5 -5
  60. package/dist/providers/firebase/hosting.test.d.ts +1 -0
  61. package/dist/providers/firebase/hosting.test.js +181 -0
  62. package/dist/providers/proxmox/index.d.ts +1 -0
  63. package/dist/providers/proxmox/index.js +1 -0
  64. package/dist/providers/proxmox/vm.d.ts +2 -1
  65. package/dist/providers/proxmox/vm.js +39 -53
  66. package/dist/providers/proxmox/vm.test.d.ts +1 -0
  67. package/dist/providers/proxmox/vm.test.js +155 -0
  68. package/dist/types/aws.d.ts +11 -0
  69. package/package.json +105 -6
@@ -0,0 +1,265 @@
1
+ import { test, describe, beforeEach, afterEach, mock } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import fs from 'node:fs';
4
+ import { DropletBuilder } from './droplet.js';
5
+ import { Config } from '../../core/config.js';
6
+ describe('DropletBuilder Unit Tests', () => {
7
+ let originalFetch;
8
+ let fetchCalls = [];
9
+ let mockResponses = {};
10
+ beforeEach(() => {
11
+ Config.set({
12
+ dryRun: false,
13
+ providers: {
14
+ do: { token: 'fake-do-token', defaultRegion: 'nyc3' }
15
+ }
16
+ });
17
+ originalFetch = globalThis.fetch;
18
+ fetchCalls = [];
19
+ mockResponses = {};
20
+ globalThis.fetch = async (input, init) => {
21
+ const url = String(input);
22
+ const method = init?.method ?? 'GET';
23
+ const body = init?.body ? JSON.parse(init.body) : undefined;
24
+ const headers = init?.headers;
25
+ fetchCalls.push({ url, method, body, headers });
26
+ const matchKey = Object.keys(mockResponses)
27
+ .filter(key => {
28
+ const [mMethod, mPath] = key.split(' ');
29
+ return method === mMethod && url.includes(mPath);
30
+ })
31
+ .sort((a, b) => b.split(' ')[1].length - a.split(' ')[1].length)[0];
32
+ if (matchKey) {
33
+ const resp = mockResponses[matchKey];
34
+ return {
35
+ ok: resp.status >= 200 && resp.status < 300,
36
+ status: resp.status,
37
+ json: async () => resp.body,
38
+ text: async () => JSON.stringify(resp.body),
39
+ };
40
+ }
41
+ return {
42
+ ok: false,
43
+ status: 404,
44
+ json: async () => ({ message: 'Not found' }),
45
+ text: async () => 'Not found',
46
+ };
47
+ };
48
+ // Mock readFileSync so tests don't hit the real filesystem for SSH keys
49
+ mock.method(fs, 'readFileSync', () => {
50
+ return 'ssh-rsa AAAA_FAKE_PUBLIC_KEY test@example.com';
51
+ });
52
+ });
53
+ afterEach(() => {
54
+ globalThis.fetch = originalFetch;
55
+ mock.restoreAll();
56
+ });
57
+ test('gracefully handles discovery when droplet does not exist', async () => {
58
+ mockResponses['GET /droplets'] = {
59
+ status: 200,
60
+ body: { droplets: [] }
61
+ };
62
+ const builder = new DropletBuilder('my-droplet');
63
+ const discoveryResult = await builder.discoveryPromise;
64
+ assert.strictEqual(discoveryResult, null);
65
+ assert.strictEqual(fetchCalls.length, 1);
66
+ assert.strictEqual(fetchCalls[0].method, 'GET');
67
+ assert.ok(fetchCalls[0].url.includes('/droplets?name=my-droplet'));
68
+ });
69
+ test('discovers droplet successfully when it exists', async () => {
70
+ mockResponses['GET /droplets'] = {
71
+ status: 200,
72
+ body: {
73
+ droplets: [
74
+ {
75
+ id: 123,
76
+ name: 'my-droplet',
77
+ networks: {
78
+ v4: [{ ip_address: '1.2.3.4', type: 'public' }]
79
+ }
80
+ }
81
+ ]
82
+ }
83
+ };
84
+ const builder = new DropletBuilder('my-droplet');
85
+ const discoveryResult = await builder.discoveryPromise;
86
+ assert.ok(discoveryResult);
87
+ assert.strictEqual(discoveryResult.id, 123);
88
+ assert.strictEqual(discoveryResult.name, 'my-droplet');
89
+ const resolvedId = await builder.out.id.get();
90
+ const resolvedIp = await builder.out.ip.get();
91
+ assert.strictEqual(resolvedId, 123);
92
+ assert.strictEqual(resolvedIp, '1.2.3.4');
93
+ });
94
+ test('performs clean dry-run planning without making write requests', async () => {
95
+ Config.set({
96
+ dryRun: true,
97
+ providers: { do: { token: 'fake-token' } }
98
+ });
99
+ mockResponses['GET /droplets'] = {
100
+ status: 200,
101
+ body: { droplets: [] }
102
+ };
103
+ const builder = new DropletBuilder('my-droplet');
104
+ builder
105
+ .region('nyc3')
106
+ .size('s-1vcpu-1gb')
107
+ .sslKey('~/.ssh/id_rsa.pub');
108
+ const result = await builder.deploy();
109
+ assert.ok(result);
110
+ assert.strictEqual(result.region, 'nyc3');
111
+ assert.strictEqual(result.size, 's-1vcpu-1gb');
112
+ const writeCalls = fetchCalls.filter(c => c.method !== 'GET');
113
+ assert.strictEqual(writeCalls.length, 0);
114
+ const resolvedId = await builder.out.id.get();
115
+ const resolvedIp = await builder.out.ip.get();
116
+ assert.strictEqual(resolvedId, -1);
117
+ assert.strictEqual(resolvedIp, '0.0.0.0');
118
+ });
119
+ test('deploys new droplet, registers SSH key, and awaits status: active', async () => {
120
+ mockResponses['GET /droplets'] = {
121
+ status: 200,
122
+ body: { droplets: [] }
123
+ };
124
+ mockResponses['GET /account/keys'] = {
125
+ status: 200,
126
+ body: { ssh_keys: [] } // SSH key does not exist yet
127
+ };
128
+ mockResponses['POST /account/keys'] = {
129
+ status: 201,
130
+ body: { ssh_key: { id: 999, name: 'id_rsa' } }
131
+ };
132
+ mockResponses['POST /droplets'] = {
133
+ status: 202,
134
+ body: { droplet: { id: 12345, name: 'my-droplet' } }
135
+ };
136
+ // First poll returns state: new, second poll returns state: active
137
+ let pollCount = 0;
138
+ mockResponses['GET /droplets/12345'] = {
139
+ status: 200,
140
+ get body() {
141
+ pollCount++;
142
+ if (pollCount === 1) {
143
+ return { droplet: { status: 'new' } };
144
+ }
145
+ return {
146
+ droplet: {
147
+ status: 'active',
148
+ networks: {
149
+ v4: [{ ip_address: '9.9.9.9', type: 'public' }]
150
+ }
151
+ }
152
+ };
153
+ }
154
+ };
155
+ const builder = new DropletBuilder('my-droplet');
156
+ builder
157
+ .region('nyc3')
158
+ .size('s-1vcpu-1gb')
159
+ .sslKey('/path/to/id_rsa.pub');
160
+ // Override the protected waitFor method to poll instantly
161
+ builder.waitFor = async (label, condition) => {
162
+ let done = false;
163
+ while (!done) {
164
+ done = await condition();
165
+ }
166
+ };
167
+ const result = await builder.deploy();
168
+ assert.ok(result);
169
+ const resolvedId = await builder.out.id.get();
170
+ const resolvedIp = await builder.out.ip.get();
171
+ assert.strictEqual(resolvedId, 12345);
172
+ assert.strictEqual(resolvedIp, '9.9.9.9');
173
+ // Assert SSH key registration was posted
174
+ const sshKeyRegisterCall = fetchCalls.find(c => c.method === 'POST' && c.url.includes('/account/keys'));
175
+ assert.ok(sshKeyRegisterCall);
176
+ assert.deepStrictEqual(sshKeyRegisterCall.body, {
177
+ name: 'id_rsa',
178
+ public_key: 'ssh-rsa AAAA_FAKE_PUBLIC_KEY test@example.com'
179
+ });
180
+ // Assert Droplet creation was posted with registered SSH key ID
181
+ const dropletCreateCall = fetchCalls.find(c => c.method === 'POST' && c.url.includes('/droplets'));
182
+ assert.ok(dropletCreateCall);
183
+ assert.deepStrictEqual(dropletCreateCall.body.ssh_keys, [999]);
184
+ });
185
+ test('skips update deployment if droplet configuration is up-to-date', async () => {
186
+ mockResponses['GET /droplets'] = {
187
+ status: 200,
188
+ body: {
189
+ droplets: [
190
+ {
191
+ id: 123,
192
+ name: 'my-droplet',
193
+ size_slug: 's-1vcpu-1gb',
194
+ region: { slug: 'nyc3' },
195
+ networks: {
196
+ v4: [{ ip_address: '1.2.3.4', type: 'public' }]
197
+ }
198
+ }
199
+ ]
200
+ }
201
+ };
202
+ const builder = new DropletBuilder('my-droplet');
203
+ builder
204
+ .region('nyc3')
205
+ .size('s-1vcpu-1gb');
206
+ await builder.deploy();
207
+ // Verify no POST writes or updates
208
+ const writeCalls = fetchCalls.filter(c => c.method === 'POST' || c.method === 'PUT');
209
+ assert.strictEqual(writeCalls.length, 0);
210
+ });
211
+ test('resizes existing droplet when size configuration changes', async () => {
212
+ mockResponses['GET /droplets'] = {
213
+ status: 200,
214
+ body: {
215
+ droplets: [
216
+ {
217
+ id: 123,
218
+ name: 'my-droplet',
219
+ size_slug: 's-1vcpu-1gb', // different from desired s-2vcpu-2gb
220
+ region: { slug: 'nyc3' },
221
+ networks: {
222
+ v4: [{ ip_address: '1.2.3.4', type: 'public' }]
223
+ }
224
+ }
225
+ ]
226
+ }
227
+ };
228
+ mockResponses['POST /droplets/123/actions'] = {
229
+ status: 201,
230
+ body: { action: { id: 888, status: 'in-progress', type: 'resize' } }
231
+ };
232
+ const builder = new DropletBuilder('my-droplet');
233
+ builder
234
+ .region('nyc3')
235
+ .size('s-2vcpu-2gb');
236
+ await builder.deploy();
237
+ const resizeCall = fetchCalls.find(c => c.method === 'POST' && c.url.includes('/droplets/123/actions'));
238
+ assert.ok(resizeCall);
239
+ assert.deepStrictEqual(resizeCall.body, {
240
+ type: 'resize',
241
+ size: 's-2vcpu-2gb'
242
+ });
243
+ });
244
+ test('destroys droplet successfully', async () => {
245
+ mockResponses['GET /droplets'] = {
246
+ status: 200,
247
+ body: {
248
+ droplets: [
249
+ { id: 123, name: 'my-droplet' }
250
+ ]
251
+ }
252
+ };
253
+ mockResponses['DELETE /droplets/123'] = {
254
+ status: 204,
255
+ body: {}
256
+ };
257
+ const builder = new DropletBuilder('my-droplet');
258
+ await builder.discoveryPromise;
259
+ const result = await builder.destroy();
260
+ assert.deepStrictEqual(result, { destroyed: 'my-droplet' });
261
+ const deleteCall = fetchCalls.find(c => c.method === 'DELETE');
262
+ assert.ok(deleteCall);
263
+ assert.ok(deleteCall.url.endsWith('/droplets/123'));
264
+ });
265
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,176 @@
1
+ import { test, describe, beforeEach, afterEach } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { FirewallBuilder } from './firewall.js';
4
+ import { Config } from '../../core/config.js';
5
+ describe('FirewallBuilder Unit Tests', () => {
6
+ let originalFetch;
7
+ let fetchCalls = [];
8
+ let mockResponses = {};
9
+ beforeEach(() => {
10
+ Config.set({
11
+ dryRun: false,
12
+ providers: {
13
+ do: { token: 'fake-do-token' }
14
+ }
15
+ });
16
+ originalFetch = globalThis.fetch;
17
+ fetchCalls = [];
18
+ mockResponses = {};
19
+ globalThis.fetch = async (input, init) => {
20
+ const url = String(input);
21
+ const method = init?.method ?? 'GET';
22
+ const body = init?.body ? JSON.parse(init.body) : undefined;
23
+ const headers = init?.headers;
24
+ fetchCalls.push({ url, method, body, headers });
25
+ const matchKey = Object.keys(mockResponses).find(key => {
26
+ const [mMethod, mPath] = key.split(' ');
27
+ return method === mMethod && url.includes(mPath);
28
+ });
29
+ if (matchKey) {
30
+ const resp = mockResponses[matchKey];
31
+ return {
32
+ ok: resp.status >= 200 && resp.status < 300,
33
+ status: resp.status,
34
+ json: async () => resp.body,
35
+ text: async () => JSON.stringify(resp.body),
36
+ };
37
+ }
38
+ return {
39
+ ok: false,
40
+ status: 404,
41
+ json: async () => ({ message: 'Not found' }),
42
+ text: async () => 'Not found',
43
+ };
44
+ };
45
+ });
46
+ afterEach(() => {
47
+ globalThis.fetch = originalFetch;
48
+ });
49
+ test('gracefully handles discovery when firewall does not exist', async () => {
50
+ mockResponses['GET /firewalls'] = {
51
+ status: 200,
52
+ body: { firewalls: [] }
53
+ };
54
+ const builder = new FirewallBuilder('my-fw');
55
+ const discoveryResult = await builder.discoveryPromise;
56
+ assert.strictEqual(discoveryResult, null);
57
+ assert.strictEqual(fetchCalls.length, 1);
58
+ assert.strictEqual(fetchCalls[0].method, 'GET');
59
+ assert.ok(fetchCalls[0].url.endsWith('/firewalls?per_page=200'));
60
+ });
61
+ test('discovers firewall successfully when it exists', async () => {
62
+ mockResponses['GET /firewalls'] = {
63
+ status: 200,
64
+ body: {
65
+ firewalls: [
66
+ { id: 'fw-123', name: 'my-fw' }
67
+ ]
68
+ }
69
+ };
70
+ const builder = new FirewallBuilder('my-fw');
71
+ const discoveryResult = await builder.discoveryPromise;
72
+ assert.ok(discoveryResult);
73
+ assert.strictEqual(discoveryResult.id, 'fw-123');
74
+ assert.strictEqual(discoveryResult.name, 'my-fw');
75
+ });
76
+ test('performs clean dry-run planning without making write requests', async () => {
77
+ Config.set({
78
+ dryRun: true,
79
+ providers: { do: { token: 'fake-token' } }
80
+ });
81
+ mockResponses['GET /firewalls'] = {
82
+ status: 200,
83
+ body: { firewalls: [] }
84
+ };
85
+ const builder = new FirewallBuilder('my-fw');
86
+ builder
87
+ .ingress('tcp', 80, ['0.0.0.0/0'])
88
+ .egress('tcp', 'all', ['0.0.0.0/0'])
89
+ .attachTo('app-vm');
90
+ const result = await builder.deploy();
91
+ assert.ok(result);
92
+ assert.strictEqual(result.name, 'my-fw');
93
+ const writeCalls = fetchCalls.filter(c => c.method !== 'GET');
94
+ assert.strictEqual(writeCalls.length, 0);
95
+ });
96
+ test('deploys new firewall, resolves droplet names, and posts creation request', async () => {
97
+ mockResponses['GET /firewalls'] = {
98
+ status: 200,
99
+ body: { firewalls: [] }
100
+ };
101
+ mockResponses['GET /droplets?name=app-vm-1'] = {
102
+ status: 200,
103
+ body: { droplets: [{ id: 111, name: 'app-vm-1' }] }
104
+ };
105
+ mockResponses['GET /droplets?name=app-vm-2'] = {
106
+ status: 200,
107
+ body: { droplets: [{ id: 222, name: 'app-vm-2' }] }
108
+ };
109
+ mockResponses['POST /firewalls'] = {
110
+ status: 201,
111
+ body: {
112
+ firewall: { id: 'fw-789', name: 'my-fw' }
113
+ }
114
+ };
115
+ const builder = new FirewallBuilder('my-fw');
116
+ builder
117
+ .ingress('tcp', 80, ['0.0.0.0/0'])
118
+ .egress('tcp', 'all', ['0.0.0.0/0'])
119
+ .attachTo('app-vm-1')
120
+ .attachTo('app-vm-2');
121
+ const result = await builder.deploy();
122
+ assert.ok(result);
123
+ assert.strictEqual(result.name, 'my-fw');
124
+ const postCall = fetchCalls.find(c => c.method === 'POST');
125
+ assert.ok(postCall);
126
+ assert.ok(postCall.url.endsWith('/firewalls'));
127
+ assert.deepStrictEqual(postCall.body, {
128
+ name: 'my-fw',
129
+ inbound_rules: [
130
+ { protocol: 'tcp', ports: '80', sources: { addresses: ['0.0.0.0/0'] } }
131
+ ],
132
+ outbound_rules: [
133
+ { protocol: 'tcp', ports: 'all', destinations: { addresses: ['0.0.0.0/0'] } }
134
+ ],
135
+ droplet_ids: [111, 222]
136
+ });
137
+ });
138
+ test('updates existing firewall using PUT', async () => {
139
+ mockResponses['GET /firewalls'] = {
140
+ status: 200,
141
+ body: {
142
+ firewalls: [
143
+ { id: 'fw-123', name: 'my-fw' }
144
+ ]
145
+ }
146
+ };
147
+ mockResponses['GET /droplets?name=app-vm-1'] = {
148
+ status: 200,
149
+ body: { droplets: [{ id: 111, name: 'app-vm-1' }] }
150
+ };
151
+ mockResponses['PUT /firewalls/fw-123'] = {
152
+ status: 200,
153
+ body: {
154
+ firewall: { id: 'fw-123', name: 'my-fw' }
155
+ }
156
+ };
157
+ const builder = new FirewallBuilder('my-fw');
158
+ builder
159
+ .ingress('tcp', 443, ['0.0.0.0/0'])
160
+ .attachTo('app-vm-1');
161
+ const result = await builder.deploy();
162
+ assert.ok(result);
163
+ assert.strictEqual(result.name, 'my-fw');
164
+ const putCall = fetchCalls.find(c => c.method === 'PUT');
165
+ assert.ok(putCall);
166
+ assert.ok(putCall.url.endsWith('/firewalls/fw-123'));
167
+ assert.deepStrictEqual(putCall.body, {
168
+ name: 'my-fw',
169
+ inbound_rules: [
170
+ { protocol: 'tcp', ports: '443', sources: { addresses: ['0.0.0.0/0'] } }
171
+ ],
172
+ outbound_rules: [],
173
+ droplet_ids: [111]
174
+ });
175
+ });
176
+ });
@@ -13,3 +13,4 @@ export declare const DO: {
13
13
  Certificate: (name: string) => CertificateBuilder;
14
14
  LoadBalancer: (name: string) => LoadBalancerBuilder;
15
15
  };
16
+ export * from "../../types/do.js";
@@ -19,3 +19,4 @@ export const DO = {
19
19
  Certificate: (name) => new CertificateBuilder(name),
20
20
  LoadBalancer: (name) => new LoadBalancerBuilder(name),
21
21
  };
22
+ export * from "../../types/do.js";
@@ -1,12 +1,46 @@
1
+ import { BaseBuilder } from '../../core/resource.js';
1
2
  import { DropletBuilder } from './droplet.js';
2
- export declare class LoadBalancerBuilder {
3
- private name;
4
- private config;
3
+ import { CertificateBuilder } from './certificate.js';
4
+ export interface HealthCheckOpts {
5
+ protocol: 'http' | 'https' | 'tcp';
6
+ port: number;
7
+ path?: string;
8
+ checkIntervalSeconds?: number;
9
+ responseTimeoutSeconds?: number;
10
+ unhealthyThreshold?: number;
11
+ healthyThreshold?: number;
12
+ }
13
+ export interface StickySessionOpts {
14
+ type: 'cookies' | 'none';
15
+ cookieName?: string;
16
+ cookieTtlSeconds?: number;
17
+ }
18
+ export interface ForwardingRule {
19
+ entryProtocol: 'http' | 'https' | 'tcp' | string;
20
+ entryPort: number;
21
+ targetProtocol: 'http' | 'https' | 'tcp' | string;
22
+ targetPort: number;
23
+ certificate?: string | CertificateBuilder;
24
+ tlsPassthrough?: boolean;
25
+ }
26
+ export declare class LoadBalancerBuilder extends BaseBuilder {
27
+ name: string;
28
+ private _region;
5
29
  private targetNames;
6
- private discoveryPromise;
30
+ private forwardingRules;
31
+ private healthCheckConfig?;
32
+ private stickySessionConfig?;
33
+ private lbId?;
7
34
  constructor(name: string);
8
35
  private discoverLb;
9
- private resolveDropletIds;
36
+ region(region: string): this;
10
37
  targets(droplets: (DropletBuilder | string)[]): this;
38
+ target(...droplets: (DropletBuilder | string)[]): this;
39
+ forward(entryProtocol: 'http' | 'https' | 'tcp' | string, entryPort: number, targetProtocol: 'http' | 'https' | 'tcp' | string, targetPort: number, certificate?: string | CertificateBuilder, tlsPassthrough?: boolean): this;
40
+ healthCheck(opts: HealthCheckOpts): this;
41
+ stickySession(type: 'cookies' | 'none', cookieName?: string, cookieTtlSeconds?: number): this;
42
+ private resolveDropletIds;
43
+ private resolveCertificateId;
11
44
  deploy(): Promise<any>;
45
+ destroy(): Promise<any>;
12
46
  }