@intentius/chant-lexicon-fly 0.44.13 → 0.45.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.
@@ -12,12 +12,6 @@
12
12
  * Machines, Storage, Networking, Secrets).
13
13
  */
14
14
  export declare function serviceFromType(resourceType: string): string;
15
- /**
16
- * The reference doc URL for a fly resource type. The Machines API (flaps) is
17
- * documented at docs.machines.dev, tagged by resource; resources flaps does not
18
- * own (public IPs, certificates) link to the matching fly.io docs page.
19
- */
20
- export declare function resourceTypeUrl(resourceType: string): string;
21
15
  /**
22
16
  * Generate documentation for the fly Machines lexicon.
23
17
  */
@@ -1 +1 @@
1
- {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/codegen/docs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsBH;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAiB5D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAkB5D;AAsED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DjF"}
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/codegen/docs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAiB5D;AA2DD;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBjF"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "201089313736647baccb5b76e3e3397a05c9bf08d219660a4aecd56a400b680c",
4
+ "manifest.json": "aed323ed6c59f96ab9470a796a81e75ddac9d72d7b1a5f7522cc7a544d88df42",
5
5
  "meta.json": "e46e65ba7544fafc6dbb3fd48b841904b5ae6f7cb4d517a940ed68b01626c097",
6
6
  "types/index.d.ts": "a76090adb6eda33a2c07a074183299a59e953b48dd3f2020d7ef11278d59341e",
7
7
  "rules/guest-sizing.ts": "bc749d218df8f3cc3d8fbe388205ae96e6b204ae0d6d77e8bf82cb936cc53ff6",
@@ -15,5 +15,5 @@
15
15
  "skills/chant-fly-ops.md": "b8eef6504e203133e6a35c83aabb08404eec95060705395515a0046d42269cf1",
16
16
  "skills/chant-fly-sprites.md": "89ba52db63a71a17eab483d99233a4ae67f5d34920445010e750f81c95200b4e"
17
17
  },
18
- "composite": "2f3f19f6e8745ffe65aab23db63411aae8c014dc5f1a4c153dd256ce1d010ec4"
18
+ "composite": "2831247df3815a0f1f18a99d8a7dc4baeb905952268fec353746037d2d8a86c2"
19
19
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fly",
3
- "version": "0.44.13",
3
+ "version": "0.45.0",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "Fly"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-fly",
3
- "version": "0.44.13",
3
+ "version": "0.45.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src/",
@@ -57,7 +57,7 @@
57
57
  "typescript": "^5.9.3"
58
58
  },
59
59
  "peerDependencies": {
60
- "@intentius/chant": "^0.44.13",
60
+ "@intentius/chant": "^0.45.0",
61
61
  "typescript": "^5.9.3"
62
62
  },
63
63
  "description": "Fly.io Machines lexicon for chant — declarative IaC in TypeScript",
@@ -12,20 +12,6 @@ import { docsPipeline, writeDocsSite, type DocsConfig } from "@intentius/chant/c
12
12
 
13
13
  const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
14
14
 
15
- /**
16
- * The curated top-level fly resources (#741), in the order they read best in a
17
- * reference table. Property types (MachineConfig, MachineGuest, ...) are grouped
18
- * separately by the pipeline and are not repeated here.
19
- */
20
- const RESOURCES: Array<{ className: string; resourceType: string }> = [
21
- { className: "App", resourceType: "Fly::Machines::App" },
22
- { className: "Machine", resourceType: "Fly::Machines::Machine" },
23
- { className: "Volume", resourceType: "Fly::Machines::Volume" },
24
- { className: "IPAddress", resourceType: "Fly::Machines::IPAddress" },
25
- { className: "Certificate", resourceType: "Fly::Machines::Certificate" },
26
- { className: "Secret", resourceType: "Fly::Machines::Secret" },
27
- ];
28
-
29
15
  /**
30
16
  * Group a fly resource type into a service bucket for the reference sidebar.
31
17
  * fly type names are `Fly::Machines::<Kind>`, so the middle segment is always
@@ -51,31 +37,6 @@ export function serviceFromType(resourceType: string): string {
51
37
  }
52
38
  }
53
39
 
54
- /**
55
- * The reference doc URL for a fly resource type. The Machines API (flaps) is
56
- * documented at docs.machines.dev, tagged by resource; resources flaps does not
57
- * own (public IPs, certificates) link to the matching fly.io docs page.
58
- */
59
- export function resourceTypeUrl(resourceType: string): string {
60
- const kind = resourceType.split("::")[2] ?? resourceType;
61
- switch (kind) {
62
- case "App":
63
- return "https://docs.machines.dev/#tag/apps";
64
- case "Machine":
65
- return "https://docs.machines.dev/#tag/machines";
66
- case "Volume":
67
- return "https://docs.machines.dev/#tag/volumes";
68
- case "Secret":
69
- return "https://docs.machines.dev/#tag/secrets";
70
- case "IPAddress":
71
- return "https://fly.io/docs/networking/services/";
72
- case "Certificate":
73
- return "https://fly.io/docs/networking/custom-domains-with-fly/";
74
- default:
75
- return "https://docs.machines.dev/";
76
- }
77
- }
78
-
79
40
  const overview = `The **Fly Machines** lexicon defines Fly.io apps and machines using chant's declarative TypeScript syntax. Resources are serialized to the JSON create bodies the Machines API ("flaps") accepts, so the applier can POST them straight through and the mudflaps emulator can round-trip them offline.
80
41
 
81
42
  This lexicon is generated from Fly's published [Machines API OpenAPI spec](https://docs.machines.dev/openapi.json).
@@ -133,17 +94,6 @@ Every serialized machine carries the \`managed-by: chant\` ownership marker in \
133
94
 
134
95
  The output is applied against flaps directly (or the mudflaps emulator offline). Endpoint and auth come from \`FLY_FLAPS_BASE_URL\` and \`FLY_API_TOKEN\`.`;
135
96
 
136
- const resourcesPage = `The fly lexicon ships ${RESOURCES.length} top-level resources. Each maps to a Machines API create body; follow the reference link for the underlying API shape.
137
-
138
- | Resource | Type | Service | Machines API |
139
- |----------|------|---------|--------------|
140
- ${RESOURCES.map(
141
- (r) =>
142
- `| \`${r.className}\` | \`${r.resourceType}\` | ${serviceFromType(r.resourceType)} | [reference](${resourceTypeUrl(r.resourceType)}) |`,
143
- ).join("\n")}
144
-
145
- Property types such as \`MachineConfig\`, \`MachineGuest\`, \`MachineService\`, \`MachinePort\`, and \`MachineMount\` are authored inline on a resource and are documented alongside the resources they belong to.`;
146
-
147
97
  /**
148
98
  * Generate documentation for the fly Machines lexicon.
149
99
  */
@@ -159,42 +109,6 @@ export async function generateDocs(options?: { verbose?: boolean }): Promise<voi
159
109
  overview,
160
110
  outputFormat,
161
111
  serviceFromType,
162
- extraPages: [
163
- {
164
- slug: "resources",
165
- title: "Resource Reference",
166
- description: "The fly resource types and their Machines API documentation links",
167
- content: resourcesPage,
168
- },
169
- {
170
- slug: "pseudo-params",
171
- title: "Pseudo-parameters",
172
- description: "Environment-resolved values: Fly.Region, Fly.OrgSlug, Fly.AppName",
173
- content: `Pseudo-parameters stand in for values that vary by environment. Reference them instead of hard-coding, and the serializer resolves each from an environment variable at build time.
174
-
175
- | Pseudo-parameter | Environment variable | Fallback |
176
- |------------------|----------------------|----------|
177
- | \`Fly.Region\` | \`FLY_REGION\` | \`iad\` |
178
- | \`Fly.OrgSlug\` | \`FLY_ORG\`, then \`FLY_ORG_SLUG\` | \`personal\` |
179
- | \`Fly.AppName\` | \`FLY_APP_NAME\` | \`app\` |
180
-
181
- \`\`\`typescript
182
- import { App, Machine, MachineConfig, MachineGuest, Fly } from "@intentius/chant-lexicon-fly";
183
-
184
- const app = new App({ name: "my-app", org_slug: Fly.OrgSlug });
185
-
186
- const web = new Machine({
187
- region: Fly.Region,
188
- config: new MachineConfig({
189
- image: "flyio/hellofly:latest",
190
- guest: new MachineGuest({ cpu_kind: "shared", cpus: 1, memory_mb: 256 }),
191
- }),
192
- });
193
- \`\`\`
194
-
195
- With \`FLY_REGION=lhr\` set, \`region\` serializes to \`"lhr"\`; unset, it falls back to \`"iad"\`.`,
196
- },
197
- ],
198
112
  };
199
113
 
200
114
  const result = docsPipeline(config);
@@ -49,7 +49,7 @@ describe("roundtrip: declared entities → serialize → parse → generate →
49
49
  ["app", app],
50
50
  ["web", web],
51
51
  ]);
52
- const planA = JSON.parse(flySerializer.serialize(entities));
52
+ const planA = JSON.parse(flySerializer.serialize(entities) as string);
53
53
 
54
54
  // 2. Parse the plan and generate TypeScript.
55
55
  const ir = parser.parse(JSON.stringify(planA));
@@ -67,7 +67,7 @@ describe("roundtrip: declared entities → serialize → parse → generate →
67
67
 
68
68
  // 4. Re-serialize the regenerated entities.
69
69
  const regenerated = new Map<string, any>(Object.entries(mod));
70
- const planB = JSON.parse(flySerializer.serialize(regenerated));
70
+ const planB = JSON.parse(flySerializer.serialize(regenerated) as string);
71
71
 
72
72
  // The bodies survive the round-trip. Entity keys differ (variable names are
73
73
  // camelCased from the resource name), so compare the create bodies by kind.
@@ -11,7 +11,7 @@ function stack(...entries: Array<[string, unknown]>): Map<string, Declarable> {
11
11
 
12
12
  describe("fly serializer", () => {
13
13
  it("serializes an empty map to valid JSON", () => {
14
- const result = flySerializer.serialize(new Map());
14
+ const result = flySerializer.serialize(new Map()) as string;
15
15
  expect(typeof result).toBe("string");
16
16
  expect(JSON.parse(result)).toEqual({});
17
17
  });
@@ -27,7 +27,7 @@ describe("fly serializer", () => {
27
27
  new App({ name: "my-app", org_slug: "acme" }),
28
28
  ]);
29
29
 
30
- const out = JSON.parse(flySerializer.serialize(entities));
30
+ const out = JSON.parse(flySerializer.serialize(entities) as string);
31
31
  expect(out.web).toEqual({
32
32
  endpoint: "/v1/apps",
33
33
  method: "POST",
@@ -36,7 +36,7 @@ describe("fly serializer", () => {
36
36
  });
37
37
 
38
38
  it("falls back to the entity name for app_name when no explicit name", () => {
39
- const out = JSON.parse(flySerializer.serialize(stack(["billing", new App({ org_slug: "acme" })])));
39
+ const out = JSON.parse(flySerializer.serialize(stack(["billing", new App({ org_slug: "acme" })])) as string);
40
40
  expect(out.billing.body.app_name).toBe("billing");
41
41
  });
42
42
 
@@ -57,7 +57,7 @@ describe("fly serializer", () => {
57
57
  ],
58
58
  );
59
59
 
60
- const out = JSON.parse(flySerializer.serialize(entities));
60
+ const out = JSON.parse(flySerializer.serialize(entities) as string);
61
61
  expect(out.api.endpoint).toBe("/v1/apps/my-app/machines");
62
62
  expect(out.api.method).toBe("POST");
63
63
  expect(out.api.body.name).toBe("api-1");
@@ -79,7 +79,7 @@ describe("fly serializer", () => {
79
79
  ],
80
80
  );
81
81
 
82
- const out = JSON.parse(flySerializer.serialize(entities));
82
+ const out = JSON.parse(flySerializer.serialize(entities) as string);
83
83
  // No user metadata → marker still present.
84
84
  expect(out.bare.body.config.metadata["managed-by"]).toBe("chant");
85
85
  // User metadata is preserved and the marker is merged in.
@@ -94,7 +94,7 @@ describe("fly serializer", () => {
94
94
  );
95
95
 
96
96
  const out = JSON.parse(
97
- flySerializer.serialize(entities, undefined, { ownership: { stack: "billing", env: "prod" } }),
97
+ flySerializer.serialize(entities, undefined, { ownership: { stack: "billing", env: "prod" } }) as string,
98
98
  );
99
99
  const meta = out.api.body.config.metadata;
100
100
  expect(meta["managed-by"]).toBe("chant");
@@ -110,7 +110,7 @@ describe("fly serializer", () => {
110
110
  new Machine({ name: "api-1", region: "iad", config: new MachineConfig({ image: "nginx" }) }),
111
111
  ],
112
112
  );
113
- const body = JSON.parse(flySerializer.serialize(entities)).api.body;
113
+ const body = JSON.parse(flySerializer.serialize(entities) as string).api.body;
114
114
  // Only fields present on flaps CreateMachineRequest / MachineConfig.
115
115
  expect(Object.keys(body).sort()).toEqual(["config", "name", "region"]);
116
116
  expect(Object.keys(body.config.guest ?? {})).toEqual([]);
@@ -123,7 +123,7 @@ describe("fly serializer", () => {
123
123
  ["app", new App({ name: "my-app" })],
124
124
  ["data", new Volume({ name: "data", region: "iad", size_gb: 10, encrypted: true })],
125
125
  );
126
- const out = JSON.parse(flySerializer.serialize(entities));
126
+ const out = JSON.parse(flySerializer.serialize(entities) as string);
127
127
  expect(out.data).toEqual({
128
128
  endpoint: "/v1/apps/my-app/volumes",
129
129
  method: "POST",
@@ -138,7 +138,7 @@ describe("fly serializer", () => {
138
138
  ["app", new App({ name: "my-app" })],
139
139
  ["ip", new IPAddress({ type: "shared_v4", region: "iad", org_slug: "acme", service_name: "web", network: "default" })],
140
140
  );
141
- const out = JSON.parse(flySerializer.serialize(entities));
141
+ const out = JSON.parse(flySerializer.serialize(entities) as string);
142
142
  expect(out.ip).toEqual({
143
143
  endpoint: "/v1/apps/my-app/ip_assignments",
144
144
  method: "POST",
@@ -151,7 +151,7 @@ describe("fly serializer", () => {
151
151
  ["app", new App({ name: "my-app" })],
152
152
  ["cert", new Certificate({ hostname: "example.com" })],
153
153
  );
154
- const out = JSON.parse(flySerializer.serialize(entities));
154
+ const out = JSON.parse(flySerializer.serialize(entities) as string);
155
155
  expect(out.cert).toEqual({
156
156
  endpoint: "/v1/apps/my-app/certificates",
157
157
  method: "POST",
@@ -164,7 +164,7 @@ describe("fly serializer", () => {
164
164
  ["app", new App({ name: "my-app" })],
165
165
  ["db-password", new Secret({ value: "s3cret" })],
166
166
  );
167
- const out = JSON.parse(flySerializer.serialize(entities));
167
+ const out = JSON.parse(flySerializer.serialize(entities) as string);
168
168
  expect(out["db-password"]).toEqual({
169
169
  endpoint: "/v1/apps/my-app/secrets/db-password",
170
170
  method: "POST",
@@ -195,7 +195,7 @@ describe("fly serializer pseudo-parameters", () => {
195
195
  ["app", new App({ name: "my-app" })],
196
196
  ["web", new Machine({ region: Fly.Region, config: new MachineConfig({ image: "nginx" }) })],
197
197
  );
198
- const body = JSON.parse(flySerializer.serialize(entities)).web.body;
198
+ const body = JSON.parse(flySerializer.serialize(entities) as string).web.body;
199
199
  expect(body.region).toBe("lhr");
200
200
  });
201
201
 
@@ -205,28 +205,28 @@ describe("fly serializer pseudo-parameters", () => {
205
205
  ["app", new App({ name: "my-app" })],
206
206
  ["web", new Machine({ region: Fly.Region, config: new MachineConfig({ image: "nginx" }) })],
207
207
  );
208
- const body = JSON.parse(flySerializer.serialize(entities)).web.body;
208
+ const body = JSON.parse(flySerializer.serialize(entities) as string).web.body;
209
209
  expect(body.region).toBe("iad");
210
210
  });
211
211
 
212
212
  it("resolves Fly.OrgSlug from FLY_ORG (preferred over FLY_ORG_SLUG)", () => {
213
213
  process.env.FLY_ORG = "acme";
214
214
  process.env.FLY_ORG_SLUG = "ignored";
215
- const out = JSON.parse(flySerializer.serialize(stack(["app", new App({ name: "my-app", org_slug: Fly.OrgSlug })])));
215
+ const out = JSON.parse(flySerializer.serialize(stack(["app", new App({ name: "my-app", org_slug: Fly.OrgSlug })])) as string);
216
216
  expect(out.app.body.org_slug).toBe("acme");
217
217
  });
218
218
 
219
219
  it("resolves Fly.OrgSlug from FLY_ORG_SLUG when FLY_ORG is unset", () => {
220
220
  delete process.env.FLY_ORG;
221
221
  process.env.FLY_ORG_SLUG = "beta-org";
222
- const out = JSON.parse(flySerializer.serialize(stack(["app", new App({ name: "my-app", org_slug: Fly.OrgSlug })])));
222
+ const out = JSON.parse(flySerializer.serialize(stack(["app", new App({ name: "my-app", org_slug: Fly.OrgSlug })])) as string);
223
223
  expect(out.app.body.org_slug).toBe("beta-org");
224
224
  });
225
225
 
226
226
  it("falls back to personal for Fly.OrgSlug when no org env var is set", () => {
227
227
  delete process.env.FLY_ORG;
228
228
  delete process.env.FLY_ORG_SLUG;
229
- const out = JSON.parse(flySerializer.serialize(stack(["app", new App({ name: "my-app", org_slug: Fly.OrgSlug })])));
229
+ const out = JSON.parse(flySerializer.serialize(stack(["app", new App({ name: "my-app", org_slug: Fly.OrgSlug })])) as string);
230
230
  expect(out.app.body.org_slug).toBe("personal");
231
231
  });
232
232
  });