puls-dev 0.1.7 → 0.1.8

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 (45) hide show
  1. package/README.md +10 -8
  2. package/dist/core/checker.d.ts +1 -1
  3. package/dist/core/checker.js +88 -56
  4. package/dist/core/decorators.js +8 -2
  5. package/dist/core/resource.js +2 -2
  6. package/dist/core/stack.d.ts +1 -1
  7. package/dist/core/stack.js +2 -2
  8. package/dist/providers/aws/acm.d.ts +1 -1
  9. package/dist/providers/aws/acm.js +27 -23
  10. package/dist/providers/aws/api.d.ts +14 -14
  11. package/dist/providers/aws/api.js +21 -21
  12. package/dist/providers/aws/apigateway.d.ts +2 -2
  13. package/dist/providers/aws/apigateway.js +33 -29
  14. package/dist/providers/aws/cloudfront.d.ts +3 -3
  15. package/dist/providers/aws/cloudfront.js +49 -34
  16. package/dist/providers/aws/fargate.d.ts +2 -2
  17. package/dist/providers/aws/fargate.js +99 -52
  18. package/dist/providers/aws/lambda.d.ts +2 -2
  19. package/dist/providers/aws/lambda.js +63 -32
  20. package/dist/providers/aws/rds.d.ts +1 -1
  21. package/dist/providers/aws/rds.js +77 -39
  22. package/dist/providers/aws/route53.d.ts +5 -5
  23. package/dist/providers/aws/route53.js +42 -35
  24. package/dist/providers/aws/s3.d.ts +2 -2
  25. package/dist/providers/aws/s3.js +40 -33
  26. package/dist/providers/aws/secrets.js +15 -7
  27. package/dist/providers/aws/sqs.d.ts +1 -1
  28. package/dist/providers/aws/sqs.js +47 -23
  29. package/dist/providers/do/domain.d.ts +4 -4
  30. package/dist/providers/do/domain.js +15 -11
  31. package/dist/providers/firebase/auth.d.ts +1 -1
  32. package/dist/providers/firebase/auth.js +65 -33
  33. package/dist/providers/firebase/firestore.d.ts +2 -2
  34. package/dist/providers/firebase/firestore.js +45 -28
  35. package/dist/providers/firebase/functions.d.ts +1 -1
  36. package/dist/providers/firebase/functions.js +75 -42
  37. package/dist/providers/firebase/hosting.d.ts +1 -1
  38. package/dist/providers/firebase/hosting.js +92 -52
  39. package/dist/providers/firebase/remoteconfig.d.ts +1 -1
  40. package/dist/providers/firebase/remoteconfig.js +42 -33
  41. package/dist/providers/firebase/storage.d.ts +1 -1
  42. package/dist/providers/firebase/storage.js +38 -24
  43. package/dist/providers/proxmox/vm.js +34 -22
  44. package/dist/types/aws.js +1 -1
  45. package/package.json +2 -1
@@ -1,8 +1,8 @@
1
- import { readFileSync } from 'node:fs';
2
- import { BaseBuilder } from '../../core/resource.js';
3
- import { cloudFetch, getProjectId } from './api.js';
4
- const RULES_BASE = 'https://firebaserules.googleapis.com/v1';
5
- const GCS_BASE = 'https://storage.googleapis.com/storage/v1';
1
+ import { readFileSync } from "node:fs";
2
+ import { BaseBuilder } from "../../core/resource.js";
3
+ import { cloudFetch, getProjectId } from "./api.js";
4
+ const RULES_BASE = "https://firebaserules.googleapis.com/v1";
5
+ const GCS_BASE = "https://storage.googleapis.com/storage/v1";
6
6
  export class FirebaseStorageBuilder extends BaseBuilder {
7
7
  _rulesPath;
8
8
  _cors = [];
@@ -10,13 +10,22 @@ export class FirebaseStorageBuilder extends BaseBuilder {
10
10
  _resolvedBucket;
11
11
  constructor(bucket) {
12
12
  // Bucket name resolved lazily in deploy() if not provided (needs projectId)
13
- super(bucket ?? '__default__');
13
+ super(bucket ?? "__default__");
14
14
  this._resolvedBucket = bucket;
15
15
  this.discoveryPromise = Promise.resolve(null);
16
16
  }
17
- rules(filePath) { this._rulesPath = filePath; return this; }
18
- cors(rules) { this._cors = rules; return this; }
19
- lifecycle(rule) { this._lifecycle = rule; return this; }
17
+ rules(filePath) {
18
+ this._rulesPath = filePath;
19
+ return this;
20
+ }
21
+ cors(rules) {
22
+ this._cors = rules;
23
+ return this;
24
+ }
25
+ lifecycle(rule) {
26
+ this._lifecycle = rule;
27
+ return this;
28
+ }
20
29
  bucket() {
21
30
  return this._resolvedBucket ?? `${getProjectId()}.appspot.com`;
22
31
  }
@@ -27,26 +36,31 @@ export class FirebaseStorageBuilder extends BaseBuilder {
27
36
  async deployRules(dryRun) {
28
37
  if (!this._rulesPath)
29
38
  return;
30
- const source = readFileSync(this._rulesPath, 'utf8');
39
+ const source = readFileSync(this._rulesPath, "utf8");
31
40
  if (dryRun) {
32
41
  console.log(` šŸ“ [PLAN] Deploy Storage rules from "${this._rulesPath}" → ${this.bucket()}`);
33
42
  return;
34
43
  }
35
44
  const ruleset = await cloudFetch(RULES_BASE, `/projects/${getProjectId()}/rulesets`, {
36
- method: 'POST',
37
- body: JSON.stringify({ source: { files: [{ name: 'storage.rules', content: source }] } }),
45
+ method: "POST",
46
+ body: JSON.stringify({
47
+ source: { files: [{ name: "storage.rules", content: source }] },
48
+ }),
38
49
  });
39
50
  await cloudFetch(RULES_BASE, `/${this.releaseName()}`, {
40
- method: 'PUT',
41
- body: JSON.stringify({ name: this.releaseName(), rulesetName: ruleset.name }),
51
+ method: "PUT",
52
+ body: JSON.stringify({
53
+ name: this.releaseName(),
54
+ rulesetName: ruleset.name,
55
+ }),
42
56
  });
43
- console.log(` āœ… Storage rules deployed (ruleset: ${ruleset.name.split('/').pop()})`);
57
+ console.log(` āœ… Storage rules deployed (ruleset: ${ruleset.name.split("/").pop()})`);
44
58
  }
45
59
  // ── CORS ──────────────────────────────────────────────────────────────────
46
60
  async deployCors(dryRun) {
47
61
  if (this._cors.length === 0)
48
62
  return;
49
- const corsBody = this._cors.map(r => ({
63
+ const corsBody = this._cors.map((r) => ({
50
64
  origin: r.origin,
51
65
  method: r.method,
52
66
  responseHeader: r.responseHeader ?? [],
@@ -55,12 +69,12 @@ export class FirebaseStorageBuilder extends BaseBuilder {
55
69
  if (dryRun) {
56
70
  console.log(` šŸ“ [PLAN] Set CORS on bucket "${this.bucket()}" (${this._cors.length} rule(s))`);
57
71
  for (const r of this._cors) {
58
- console.log(` └─ origins: [${r.origin.join(', ')}], methods: [${r.method.join(', ')}]`);
72
+ console.log(` └─ origins: [${r.origin.join(", ")}], methods: [${r.method.join(", ")}]`);
59
73
  }
60
74
  return;
61
75
  }
62
76
  await cloudFetch(GCS_BASE, `/b/${this.bucket()}`, {
63
- method: 'PATCH',
77
+ method: "PATCH",
64
78
  body: JSON.stringify({ cors: corsBody }),
65
79
  });
66
80
  console.log(` āœ… CORS configured on "${this.bucket()}"`);
@@ -70,7 +84,7 @@ export class FirebaseStorageBuilder extends BaseBuilder {
70
84
  if (!this._lifecycle)
71
85
  return;
72
86
  const rule = {
73
- action: { type: 'Delete' },
87
+ action: { type: "Delete" },
74
88
  condition: {},
75
89
  };
76
90
  if (this._lifecycle.deleteAfterDays !== undefined)
@@ -82,12 +96,12 @@ export class FirebaseStorageBuilder extends BaseBuilder {
82
96
  if (this._lifecycle.deleteAfterDays)
83
97
  parts.push(`delete after ${this._lifecycle.deleteAfterDays} days`);
84
98
  if (this._lifecycle.matchesPrefix)
85
- parts.push(`prefix: [${this._lifecycle.matchesPrefix.join(', ')}]`);
86
- console.log(` šŸ“ [PLAN] Set lifecycle on "${this.bucket()}": ${parts.join(', ')}`);
99
+ parts.push(`prefix: [${this._lifecycle.matchesPrefix.join(", ")}]`);
100
+ console.log(` šŸ“ [PLAN] Set lifecycle on "${this.bucket()}": ${parts.join(", ")}`);
87
101
  return;
88
102
  }
89
103
  await cloudFetch(GCS_BASE, `/b/${this.bucket()}`, {
90
- method: 'PATCH',
104
+ method: "PATCH",
91
105
  body: JSON.stringify({ lifecycle: { rule: [rule] } }),
92
106
  });
93
107
  console.log(` āœ… Lifecycle configured on "${this.bucket()}"`);
@@ -107,10 +121,10 @@ export class FirebaseStorageBuilder extends BaseBuilder {
107
121
  const dryRun = this.isDryRunActive();
108
122
  console.log(`\nšŸ—‘ļø Destroying Firebase Storage config "${this.bucket()}"...`);
109
123
  if (dryRun) {
110
- console.log(` ā„¹ļø Storage buckets cannot be deleted via API — remove manually in the GCP console`);
124
+ console.log(` ā„¹ļø Storage buckets cannot be deleted via API - remove manually in the GCP console`);
111
125
  }
112
126
  else {
113
- console.log(` ā„¹ļø Storage buckets cannot be deleted via API — remove manually in the GCP console`);
127
+ console.log(` ā„¹ļø Storage buckets cannot be deleted via API - remove manually in the GCP console`);
114
128
  }
115
129
  return { destroyed: this.bucket() };
116
130
  }
@@ -118,7 +118,7 @@ export class VMBuilder extends BaseBuilder {
118
118
  this.out.ip.resolve(this._ip?.split("/")[0] ?? "0.0.0.0");
119
119
  return { name: this.name, vmid: "PENDING" };
120
120
  }
121
- // Find the template — match by VMID (numeric string) or name substring
121
+ // Find the template - match by VMID (numeric string) or name substring
122
122
  const resources = await pm.get("/cluster/resources?type=vm");
123
123
  const isVmid = this._image && /^\d+$/.test(this._image);
124
124
  const template = this._image
@@ -156,7 +156,7 @@ export class VMBuilder extends BaseBuilder {
156
156
  storage,
157
157
  format: "raw",
158
158
  });
159
- // Clone is async — wait for the Proxmox task to finish before configuring
159
+ // Clone is async - wait for the Proxmox task to finish before configuring
160
160
  await this.waitForTask(node, taskId, pm);
161
161
  }
162
162
  else {
@@ -184,11 +184,11 @@ export class VMBuilder extends BaseBuilder {
184
184
  console.log(` šŸ” DNS: ${this.name}.${domain} → ${addr}`);
185
185
  }
186
186
  catch {
187
- // Not in DNS — will fall through to DHCP
187
+ // Not in DNS - will fall through to DHCP
188
188
  }
189
189
  }
190
190
  }
191
- // Build net0 string — VirtIO on vmbr1, optional VLAN tag
191
+ // Build net0 string - VirtIO on vmbr1, optional VLAN tag
192
192
  const net0 = `virtio,bridge=vmbr1${this._vlan ? `,tag=${this._vlan}` : ""}`;
193
193
  const configPatch = {
194
194
  onboot: 1,
@@ -244,7 +244,9 @@ export class VMBuilder extends BaseBuilder {
244
244
  if (this._provision) {
245
245
  await this.waitFor(`SSH on ${this.resolvedIp} to be ready`, () => this.checkPort(this.resolvedIp, 22), { intervalMs: 10_000, timeoutMs: 300_000 });
246
246
  await this.waitFor(`cloud-init to finish on ${this.resolvedIp}`, () => this.checkCloudInit(this.resolvedIp), { intervalMs: 15_000, timeoutMs: 300_000 });
247
- const scripts = Array.isArray(this._provision) ? this._provision : [this._provision];
247
+ const scripts = Array.isArray(this._provision)
248
+ ? this._provision
249
+ : [this._provision];
248
250
  for (const script of scripts) {
249
251
  await this.runProvisioner(this.resolvedIp, script);
250
252
  }
@@ -287,7 +289,7 @@ export class VMBuilder extends BaseBuilder {
287
289
  const resources = await pm.get("/cluster/resources?type=vm");
288
290
  const vm = (resources ?? []).find((r) => r.name === name && !r.template);
289
291
  if (!vm) {
290
- console.log(` ā„¹ļø VM "${name}" not found — already gone`);
292
+ console.log(` ā„¹ļø VM "${name}" not found - already gone`);
291
293
  return;
292
294
  }
293
295
  if (vm.status === "running") {
@@ -332,27 +334,37 @@ export class VMBuilder extends BaseBuilder {
332
334
  }
333
335
  checkCloudInit(ip) {
334
336
  const keyPath = this.sshKeyPath();
335
- return new Promise(resolve => {
336
- const proc = spawn('ssh', [
337
- '-i', keyPath,
338
- '-o', 'StrictHostKeyChecking=no',
339
- '-o', 'ConnectTimeout=10',
340
- '-o', 'BatchMode=yes',
337
+ return new Promise((resolve) => {
338
+ const proc = spawn("ssh", [
339
+ "-i",
340
+ keyPath,
341
+ "-o",
342
+ "StrictHostKeyChecking=no",
343
+ "-o",
344
+ "ConnectTimeout=10",
345
+ "-o",
346
+ "BatchMode=yes",
341
347
  `root@${ip}`,
342
- 'cloud-init status',
343
- ], { stdio: ['ignore', 'pipe', 'ignore'] });
344
- let out = '';
345
- proc.stdout.on('data', (d) => out += d.toString());
346
- proc.on('close', () => resolve(out.includes('done') || out.includes('error')));
347
- proc.on('error', () => resolve(false));
348
+ "cloud-init status",
349
+ ], { stdio: ["ignore", "pipe", "ignore"] });
350
+ let out = "";
351
+ proc.stdout.on("data", (d) => (out += d.toString()));
352
+ proc.on("close", () => resolve(out.includes("done") || out.includes("error")));
353
+ proc.on("error", () => resolve(false));
348
354
  });
349
355
  }
350
356
  checkPort(ip, port) {
351
- return new Promise(resolve => {
357
+ return new Promise((resolve) => {
352
358
  const socket = createConnection({ host: ip, port, timeout: 3_000 });
353
- socket.on('connect', () => { socket.destroy(); resolve(true); });
354
- socket.on('timeout', () => { socket.destroy(); resolve(false); });
355
- socket.on('error', () => resolve(false));
359
+ socket.on("connect", () => {
360
+ socket.destroy();
361
+ resolve(true);
362
+ });
363
+ socket.on("timeout", () => {
364
+ socket.destroy();
365
+ resolve(false);
366
+ });
367
+ socket.on("error", () => resolve(false));
356
368
  });
357
369
  }
358
370
  sshKeyPath() {
package/dist/types/aws.js CHANGED
@@ -1,4 +1,4 @@
1
- // Define your secret IDs here — reference them everywhere instead of raw strings.
1
+ // Define your secret IDs here - reference them everywhere instead of raw strings.
2
2
  // Example:
3
3
  // export const SECRETS = {
4
4
  // API_KEY: "myapp/api-key",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "puls-dev",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Intent-driven infrastructure-as-code with eager discovery and no state files.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -50,6 +50,7 @@
50
50
  "@aws-sdk/client-sqs": "^3.1045.0",
51
51
  "dotenv": "^17.4.2",
52
52
  "google-auth-library": "^10.6.2",
53
+ "mkdocs": "^0.0.1",
53
54
  "reflect-metadata": "^0.2.2",
54
55
  "undici": "^8.2.0"
55
56
  }