@intentius/chant-lexicon-fly 0.124.31 → 0.124.32
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/dist/codegen/docs-cli.js +6 -0
- package/dist/codegen/docs.js +143 -0
- package/dist/codegen/generate-cli.js +26 -0
- package/dist/codegen/generate-lexicon.js +38 -0
- package/dist/codegen/generate-typescript.js +45 -0
- package/dist/codegen/generate.js +82 -0
- package/dist/codegen/naming.js +33 -0
- package/dist/codegen/package.js +35 -0
- package/dist/components/capability-plugin.js +26 -0
- package/dist/components/fly-release.js +335 -0
- package/dist/components/index.js +10 -0
- package/dist/components/run-agent.js +133 -0
- package/dist/composites/catalog.js +176 -0
- package/dist/composites/fly-deploy.js +91 -0
- package/dist/composites/fly-otel-collector.js +66 -0
- package/dist/composites/fly-site.js +80 -0
- package/dist/coverage.js +29 -0
- package/dist/describe-resources.js +443 -0
- package/dist/detect.js +63 -0
- package/dist/export-resources.js +81 -0
- package/dist/generated/index.js +44 -0
- package/dist/generated/runtime.js +4 -0
- package/dist/import/generator.js +208 -0
- package/dist/import/live-export.js +81 -0
- package/dist/import/parser.js +157 -0
- package/dist/index.js +40 -0
- package/dist/integrity.json +3 -3
- package/dist/lint/audit-catalog.js +28 -0
- package/dist/lint/audit-lineage.js +5 -0
- package/dist/lint/post-synth/fly-helpers.js +24 -0
- package/dist/lint/post-synth/fly010-machine-requires-image.js +33 -0
- package/dist/lint/post-synth/fly011-mount-references-declared-volume.js +58 -0
- package/dist/lint/post-synth/index.js +6 -0
- package/dist/lint/rules/guest-sizing.js +92 -0
- package/dist/lint/rules/index.js +12 -0
- package/dist/lint/rules/no-secret-literals.js +58 -0
- package/dist/lint/rules/valid-region.js +52 -0
- package/dist/lsp/completions.js +12 -0
- package/dist/lsp/hover.js +12 -0
- package/dist/manifest.json +1 -1
- package/dist/mcp/context-tools.js +113 -0
- package/dist/okf/types/Machine.md +1 -1
- package/dist/op/activities/box-services.js +88 -0
- package/dist/op/activities/emulator-images.js +32 -0
- package/dist/op/activities/flaps.js +34 -0
- package/dist/op/activities/fly-apply.js +911 -0
- package/dist/op/activities/fly-release-step.js +21 -0
- package/dist/op/activities/fly-rollback-step.js +22 -0
- package/dist/op/activities/index.js +53 -0
- package/dist/op/activities/machine-release.js +236 -0
- package/dist/op/activities/machines-contract.js +81 -0
- package/dist/op/activities/machines-fake.js +203 -0
- package/dist/op/activities/machines-local-cli.js +85 -0
- package/dist/op/activities/machines-local.js +395 -0
- package/dist/op/activities/progress.js +10 -0
- package/dist/op/activities/sprite-config.js +409 -0
- package/dist/op/activities/sprite-fs.js +131 -0
- package/dist/op/activities/sprite-service-converge.js +224 -0
- package/dist/op/activities/sprite-services.js +174 -0
- package/dist/op/activities/sprite-tasks.js +57 -0
- package/dist/op/activities/sprites-contract.js +87 -0
- package/dist/op/activities/sprites-emulator.js +72 -0
- package/dist/op/activities/sprites-fake.js +547 -0
- package/dist/op/activities/sprites.js +515 -0
- package/dist/op/activity-contracts.js +82 -0
- package/dist/op/builders.js +157 -0
- package/dist/ownership.js +29 -0
- package/dist/package-cli.js +20 -0
- package/dist/plugin.js +298 -0
- package/dist/pseudo.js +26 -0
- package/dist/reference-catalog.js +37 -0
- package/dist/release-metadata.js +59 -0
- package/dist/release-store.js +46 -0
- package/dist/serializer.js +299 -0
- package/dist/spec/fetch.js +32 -0
- package/dist/spec/parse.js +260 -0
- package/dist/teardown.js +194 -0
- package/dist/types/index.d.ts +33 -2
- package/dist/validate-cli.js +4 -0
- package/dist/validate.js +33 -0
- package/package.json +11 -11
- package/src/codegen/package.ts +2 -2
- package/src/generated/index.d.ts +33 -2
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fly (Machines API / "flaps") documentation generator.
|
|
3
|
+
*
|
|
4
|
+
* Calls the core docsPipeline with fly-specific config: service grouping and
|
|
5
|
+
* overview content. writeDocsSite puts the pages in the main docs site under
|
|
6
|
+
* docs/src/content/docs/lexicons/fly/ (chant #3993).
|
|
7
|
+
*/
|
|
8
|
+
import { dirname, join } from "path";
|
|
9
|
+
import { fileURLToPath } from "url";
|
|
10
|
+
import { docsPipeline, writeDocsSite } from "@intentius/chant/codegen/docs";
|
|
11
|
+
const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
12
|
+
/**
|
|
13
|
+
* Group a fly resource type into a service bucket for the reference sidebar.
|
|
14
|
+
* fly type names are `Fly::Machines::<Kind>`, so the middle segment is always
|
|
15
|
+
* "Machines"; grouping by the leaf kind gives a more useful split (Apps,
|
|
16
|
+
* Machines, Storage, Networking, Secrets).
|
|
17
|
+
*/
|
|
18
|
+
export function serviceFromType(resourceType) {
|
|
19
|
+
const kind = resourceType.split("::")[2] ?? resourceType;
|
|
20
|
+
switch (kind) {
|
|
21
|
+
case "App":
|
|
22
|
+
return "Apps";
|
|
23
|
+
case "Machine":
|
|
24
|
+
return "Machines";
|
|
25
|
+
case "Volume":
|
|
26
|
+
return "Storage";
|
|
27
|
+
case "IPAddress":
|
|
28
|
+
case "Certificate":
|
|
29
|
+
return "Networking";
|
|
30
|
+
case "Secret":
|
|
31
|
+
return "Secrets";
|
|
32
|
+
default:
|
|
33
|
+
return "Machines";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
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.
|
|
37
|
+
|
|
38
|
+
This lexicon is generated from Fly's published [Machines API OpenAPI spec](https://docs.machines.dev/openapi.json).
|
|
39
|
+
|
|
40
|
+
Install it with:
|
|
41
|
+
|
|
42
|
+
\`\`\`bash
|
|
43
|
+
npm install --save-dev @intentius/chant-lexicon-fly
|
|
44
|
+
\`\`\`
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
\`\`\`typescript
|
|
49
|
+
import { App, Machine, MachineConfig, MachineGuest, Fly } from "@intentius/chant-lexicon-fly";
|
|
50
|
+
|
|
51
|
+
const app = new App({ name: "my-app", org_slug: Fly.OrgSlug });
|
|
52
|
+
|
|
53
|
+
const web = new Machine({
|
|
54
|
+
name: "web",
|
|
55
|
+
region: Fly.Region,
|
|
56
|
+
config: new MachineConfig({
|
|
57
|
+
image: "flyio/hellofly:latest",
|
|
58
|
+
guest: new MachineGuest({ cpu_kind: "shared", cpus: 1, memory_mb: 256 }),
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export { app, web };
|
|
63
|
+
\`\`\`
|
|
64
|
+
|
|
65
|
+
\`Fly.Region\` and \`Fly.OrgSlug\` are pseudo-parameters resolved from the environment at build time (\`FLY_REGION\`, \`FLY_ORG\` / \`FLY_ORG_SLUG\`).`;
|
|
66
|
+
const outputFormat = `The fly lexicon serializes resources into the JSON create bodies the Machines API ("flaps") accepts.
|
|
67
|
+
|
|
68
|
+
## Building
|
|
69
|
+
|
|
70
|
+
Each declared resource becomes a single flaps request keyed by its logical name:
|
|
71
|
+
|
|
72
|
+
\`\`\`json
|
|
73
|
+
{
|
|
74
|
+
"web": {
|
|
75
|
+
"endpoint": "/v1/apps/my-app/machines",
|
|
76
|
+
"method": "POST",
|
|
77
|
+
"body": { "name": "web", "region": "iad", "config": { ... } }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
\`\`\`
|
|
81
|
+
|
|
82
|
+
- An \`App\` becomes \`POST /v1/apps { app_name, org_slug? }\`.
|
|
83
|
+
- A \`Machine\` becomes \`POST /v1/apps/{app}/machines\` with the full \`MachineConfig\` as \`config\`. The owning app is a URL path segment, not a body field.
|
|
84
|
+
- \`Volume\`, \`IPAddress\`, \`Certificate\`, and \`Secret\` are app-scoped and POST under their app.
|
|
85
|
+
|
|
86
|
+
Every serialized machine carries the \`managed-by: chant\` ownership marker in \`config.metadata\`, which the owned-only prune reads back.
|
|
87
|
+
|
|
88
|
+
## Telemetry attribution
|
|
89
|
+
|
|
90
|
+
Inside a workspace, the fly lexicon adds two variables to each Machine's \`config.env\`, so that its spans name the declaration that produced them ([#3060](https://github.com/INTENTIUS/chant/issues/3060), [ws-060](https://github.com/INTENTIUS/chant/blob/main/docs/design/decisions/ws-060-telemetry-attribution.md)).
|
|
91
|
+
|
|
92
|
+
\`\`\`json
|
|
93
|
+
"env": {
|
|
94
|
+
"PORT": "8080",
|
|
95
|
+
"OTEL_SERVICE_NAME": "notes",
|
|
96
|
+
"OTEL_RESOURCE_ATTRIBUTES": "chant.workspace=acme,chant.member=svc,chant.decl=web"
|
|
97
|
+
}
|
|
98
|
+
\`\`\`
|
|
99
|
+
|
|
100
|
+
\`OTEL_SERVICE_NAME\` is the name of the Machine's app on Fly, or the Machine's export name when the build can't tell which app owns it. \`chant.decl\` is the Machine's export name. \`deployment.environment.name\` is added when the build has an environment (\`--env\` or \`ownership.env\`), and an image pinned by digest adds \`service.version\`. A value the Machine already sets is kept, and only the missing attributes are added. An \`App\` has no env, so only Machines are stamped. A project with no \`chant.workspace.json\` builds the same plan as before unless \`telemetry.attribution: true\` opts it in, and \`telemetry.attribution: false\` turns stamping off inside a workspace.
|
|
101
|
+
|
|
102
|
+
A Machine's env values are literal strings, so the plan carries no reference to \`CHANT_RELEASE_ATTRIBUTES\` ([ws-081](https://github.com/INTENTIUS/chant/blob/main/docs/design/decisions/ws-081-release-attributes-at-deploy.md)). The \`fly-release\` step writes the release into the Machine it serves instead: on a stamped Machine, \`OTEL_RESOURCE_ATTRIBUTES\` gets \`service.version\` (the release's digest) and \`vcs.ref.head.revision\` (its commit), the same release its metadata names. A plain apply of the plan carries no release.
|
|
103
|
+
|
|
104
|
+
## Applying
|
|
105
|
+
|
|
106
|
+
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\`.
|
|
107
|
+
|
|
108
|
+
A \`Secret\` with a \`value\` is set on every apply. A \`Secret\` with no value is one you set outside chant, for example with \`fly secrets set\`. Apply never sends it. It checks that the app has the secret, and fails with the secret's name if the app does not. The \`name\` prop sets the secret's name on the app and defaults to the export name.
|
|
109
|
+
|
|
110
|
+
The applier writes its progress lines to stderr, so an Op step's stdout carries only its output.
|
|
111
|
+
|
|
112
|
+
## Reading live state
|
|
113
|
+
|
|
114
|
+
The helpers the applier reads live state with are exported from \`@intentius/chant-lexicon-fly/op/activities\`. \`listMachines\`, \`listVolumes\`, \`listIps\`, \`listCerts\` and \`listSecrets\` each take an \`ApplyCtx\`, an app name and a \`FlyHttp\`, and return what flaps lists for that app. \`listSecrets\` returns names only, never values. Build the context with \`resolveEndpoint\` and the client with \`defaultFlyHttp\`, as apply does:
|
|
115
|
+
|
|
116
|
+
\`\`\`typescript
|
|
117
|
+
import { defaultFlyHttp, listSecrets, resolveEndpoint } from "@intentius/chant-lexicon-fly/op/activities";
|
|
118
|
+
|
|
119
|
+
const ctx = { base: resolveEndpoint({}) };
|
|
120
|
+
const secrets = await listSecrets(ctx, "my-app", defaultFlyHttp());
|
|
121
|
+
\`\`\``;
|
|
122
|
+
/**
|
|
123
|
+
* Generate documentation for the fly Machines lexicon.
|
|
124
|
+
*/
|
|
125
|
+
export async function generateDocs(options) {
|
|
126
|
+
const config = {
|
|
127
|
+
name: "fly",
|
|
128
|
+
displayName: "Fly Machines",
|
|
129
|
+
description: "Typed constructors for Fly.io apps and machines, serialized to Machines API create bodies",
|
|
130
|
+
distDir: join(pkgDir, "dist"),
|
|
131
|
+
outDir: join(pkgDir, "docs"),
|
|
132
|
+
srcDir: join(pkgDir, "src"),
|
|
133
|
+
basePath: process.env.DOCS_BASE_PATH ?? "/chant/lexicons/fly/",
|
|
134
|
+
overview,
|
|
135
|
+
outputFormat,
|
|
136
|
+
serviceFromType,
|
|
137
|
+
};
|
|
138
|
+
const result = docsPipeline(config);
|
|
139
|
+
writeDocsSite(config, result);
|
|
140
|
+
if (options?.verbose) {
|
|
141
|
+
console.error(`Generated docs: ${result.stats.resources} resources, ${result.stats.properties} properties, ${result.stats.services} services, ${result.stats.rules} rules`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* CLI entry point for fly lexicon generation.
|
|
4
|
+
*/
|
|
5
|
+
import { dirname } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
import { generate, writeGeneratedFiles } from "./generate.js";
|
|
8
|
+
const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
9
|
+
async function main() {
|
|
10
|
+
const verbose = process.argv.includes("--verbose") || process.argv.includes("-v");
|
|
11
|
+
const force = process.argv.includes("--force") || process.argv.includes("-f");
|
|
12
|
+
console.error("Generating fly lexicon...");
|
|
13
|
+
const result = await generate({ verbose, force });
|
|
14
|
+
writeGeneratedFiles(result, pkgDir);
|
|
15
|
+
console.error(`Generated ${result.resources} resources, ${result.properties} property types, ${result.enums} enums`);
|
|
16
|
+
if (result.warnings.length > 0) {
|
|
17
|
+
console.error(`${result.warnings.length} warnings:`);
|
|
18
|
+
for (const w of result.warnings) {
|
|
19
|
+
console.error(` ${w.file}: ${w.error}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
main().catch((err) => {
|
|
24
|
+
console.error("Generation failed:", err);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lexicon JSON generator — produces lexicon-fly.json with metadata for the
|
|
3
|
+
* fly resource and property types.
|
|
4
|
+
*/
|
|
5
|
+
import { flyShortName } from "../spec/parse.js";
|
|
6
|
+
import { buildRegistry, serializeRegistry } from "@intentius/chant/codegen/generate-registry";
|
|
7
|
+
/**
|
|
8
|
+
* Generate the lexicon-fly.json content.
|
|
9
|
+
*/
|
|
10
|
+
export function generateLexiconJSON(results, naming) {
|
|
11
|
+
const registryResources = results.map((r) => ({
|
|
12
|
+
typeName: r.resource.typeName,
|
|
13
|
+
attributes: r.resource.attributes,
|
|
14
|
+
properties: r.resource.properties,
|
|
15
|
+
propertyTypes: [],
|
|
16
|
+
}));
|
|
17
|
+
const entries = buildRegistry(registryResources, naming, {
|
|
18
|
+
shortName: flyShortName,
|
|
19
|
+
buildEntry: (resource, _tsName, _attrs, propConstraints) => {
|
|
20
|
+
const r = results.find((res) => res.resource.typeName === resource.typeName);
|
|
21
|
+
const entry = {
|
|
22
|
+
resourceType: resource.typeName,
|
|
23
|
+
kind: r?.isProperty ? "property" : "resource",
|
|
24
|
+
lexicon: "fly",
|
|
25
|
+
};
|
|
26
|
+
if (propConstraints && Object.keys(propConstraints).length > 0) {
|
|
27
|
+
entry.constraints = propConstraints;
|
|
28
|
+
}
|
|
29
|
+
return entry;
|
|
30
|
+
},
|
|
31
|
+
buildPropertyEntry: (resourceType, propertyType) => ({
|
|
32
|
+
resourceType: `${resourceType}.${propertyType}`,
|
|
33
|
+
kind: "property",
|
|
34
|
+
lexicon: "fly",
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
return serializeRegistry(entries);
|
|
38
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript declaration file generator — produces index.d.ts with the fly
|
|
3
|
+
* resource classes (App, Machine, Volume) and their property-type classes.
|
|
4
|
+
*/
|
|
5
|
+
import { writeResourceClass, writePropertyClass, } from "@intentius/chant/codegen/generate-typescript";
|
|
6
|
+
/**
|
|
7
|
+
* Generate the complete .d.ts file content.
|
|
8
|
+
*/
|
|
9
|
+
export function generateTypeScriptDeclarations(results, naming) {
|
|
10
|
+
const lines = [];
|
|
11
|
+
lines.push("// Code generated by chant fly generate. DO NOT EDIT.");
|
|
12
|
+
const entries = [];
|
|
13
|
+
for (const r of results) {
|
|
14
|
+
const tsName = naming.resolve(r.resource.typeName);
|
|
15
|
+
if (!tsName)
|
|
16
|
+
continue;
|
|
17
|
+
const properties = r.resource.properties.map((p) => ({
|
|
18
|
+
name: p.name,
|
|
19
|
+
type: p.tsType,
|
|
20
|
+
required: p.required,
|
|
21
|
+
description: p.description,
|
|
22
|
+
}));
|
|
23
|
+
const attributes = r.resource.attributes.map((a) => ({ name: a.name, type: a.tsType }));
|
|
24
|
+
entries.push({ tsName, isProperty: !!r.isProperty, properties, attributes });
|
|
25
|
+
}
|
|
26
|
+
entries.sort((a, b) => a.tsName.localeCompare(b.tsName));
|
|
27
|
+
const resources = entries.filter((e) => !e.isProperty);
|
|
28
|
+
const propertyTypes = entries.filter((e) => e.isProperty);
|
|
29
|
+
if (resources.length > 0) {
|
|
30
|
+
lines.push("");
|
|
31
|
+
lines.push("// --- Fly Resource classes ---");
|
|
32
|
+
for (const re of resources) {
|
|
33
|
+
writeResourceClass(lines, re.tsName, re.properties, re.attributes);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (propertyTypes.length > 0) {
|
|
37
|
+
lines.push("");
|
|
38
|
+
lines.push("// --- Property type classes ---");
|
|
39
|
+
for (const pe of propertyTypes) {
|
|
40
|
+
writePropertyClass(lines, pe.tsName, pe.properties);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
lines.push("");
|
|
44
|
+
return lines.join("\n");
|
|
45
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fly generation pipeline — uses core generatePipeline with fly-specific
|
|
3
|
+
* fetch, parse, naming, and generation callbacks.
|
|
4
|
+
*/
|
|
5
|
+
import { generatePipeline, writeGeneratedArtifacts, } from "@intentius/chant/codegen/generate";
|
|
6
|
+
import { fetchSchemas } from "../spec/fetch.js";
|
|
7
|
+
import { parseFlyOpenAPI } from "../spec/parse.js";
|
|
8
|
+
import { NamingStrategy } from "./naming.js";
|
|
9
|
+
import { generateLexiconJSON } from "./generate-lexicon.js";
|
|
10
|
+
import { generateTypeScriptDeclarations } from "./generate-typescript.js";
|
|
11
|
+
import { generateRuntimeIndex as coreGenerateRuntimeIndex, } from "@intentius/chant/codegen/generate-runtime-index";
|
|
12
|
+
/**
|
|
13
|
+
* Run the full fly generation pipeline.
|
|
14
|
+
*/
|
|
15
|
+
export async function generate(opts = {}) {
|
|
16
|
+
// The flaps spec is a single document — parseFlyOpenAPI returns multiple
|
|
17
|
+
// results. The pipeline calls parseSchema once, so we return the first result
|
|
18
|
+
// and inject the rest via augmentResults.
|
|
19
|
+
let pendingResults = [];
|
|
20
|
+
const config = {
|
|
21
|
+
fetchSchemas: (fetchOpts) => fetchSchemas({ force: fetchOpts.force }),
|
|
22
|
+
parseSchema: (_typeName, data) => {
|
|
23
|
+
const results = parseFlyOpenAPI(data);
|
|
24
|
+
if (results.length === 0)
|
|
25
|
+
return null;
|
|
26
|
+
pendingResults = results.slice(1);
|
|
27
|
+
return results[0];
|
|
28
|
+
},
|
|
29
|
+
createNaming: (results) => new NamingStrategy(results),
|
|
30
|
+
augmentResults: (results, _opts, log) => {
|
|
31
|
+
if (pendingResults.length > 0) {
|
|
32
|
+
results.push(...pendingResults);
|
|
33
|
+
log(`Added ${pendingResults.length} additional fly schemas from OpenAPI spec`);
|
|
34
|
+
pendingResults = [];
|
|
35
|
+
}
|
|
36
|
+
log(`Total: ${results.length} fly resource/property schemas`);
|
|
37
|
+
return { results };
|
|
38
|
+
},
|
|
39
|
+
generateRegistry: (results, naming) => generateLexiconJSON(results, naming),
|
|
40
|
+
generateTypes: (results, naming) => generateTypeScriptDeclarations(results, naming),
|
|
41
|
+
generateRuntimeIndex: (results, naming) => generateRuntimeIndex(results, naming),
|
|
42
|
+
};
|
|
43
|
+
return generatePipeline(config, opts);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Write generated artifacts to disk.
|
|
47
|
+
*/
|
|
48
|
+
export function writeGeneratedFiles(result, baseDir) {
|
|
49
|
+
writeGeneratedArtifacts({
|
|
50
|
+
baseDir,
|
|
51
|
+
files: {
|
|
52
|
+
"lexicon-fly.json": result.lexiconJSON,
|
|
53
|
+
"index.d.ts": result.typesDTS,
|
|
54
|
+
"index.ts": result.indexTS,
|
|
55
|
+
"runtime.ts": `/**\n * Runtime factory constructors — re-exported from core.\n */\nexport { createResource, createProperty } from "@intentius/chant/runtime";\n`,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Generate the runtime index.ts with factory constructor exports.
|
|
61
|
+
*/
|
|
62
|
+
function generateRuntimeIndex(results, naming) {
|
|
63
|
+
const resourceEntries = [];
|
|
64
|
+
const propertyEntries = [];
|
|
65
|
+
for (const r of results) {
|
|
66
|
+
const typeName = r.resource.typeName;
|
|
67
|
+
const tsName = naming.resolve(typeName);
|
|
68
|
+
if (!tsName)
|
|
69
|
+
continue;
|
|
70
|
+
if (r.isProperty) {
|
|
71
|
+
propertyEntries.push({ tsName, resourceType: typeName });
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const attrs = {};
|
|
75
|
+
for (const attr of r.resource.attributes) {
|
|
76
|
+
attrs[attr.name] = attr.name;
|
|
77
|
+
}
|
|
78
|
+
resourceEntries.push({ tsName, resourceType: typeName, attrs });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return coreGenerateRuntimeIndex(resourceEntries, propertyEntries, { lexiconName: "fly" });
|
|
82
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fly naming strategy — maps Fly::Machines::{Kind} type names to
|
|
3
|
+
* user-friendly TypeScript class names.
|
|
4
|
+
*/
|
|
5
|
+
import { NamingStrategy as CoreNamingStrategy, } from "@intentius/chant/codegen/naming";
|
|
6
|
+
import { flyShortName, flyServiceName } from "../spec/parse.js";
|
|
7
|
+
export { propertyTypeName, extractDefName } from "@intentius/chant/codegen/naming";
|
|
8
|
+
const flyNamingConfig = {
|
|
9
|
+
priorityNames: {
|
|
10
|
+
"Fly::Machines::App": "App",
|
|
11
|
+
"Fly::Machines::Machine": "Machine",
|
|
12
|
+
"Fly::Machines::Volume": "Volume",
|
|
13
|
+
},
|
|
14
|
+
priorityAliases: {},
|
|
15
|
+
priorityPropertyAliases: {},
|
|
16
|
+
serviceAbbreviations: {
|
|
17
|
+
Machines: "Machines",
|
|
18
|
+
},
|
|
19
|
+
shortName: flyShortName,
|
|
20
|
+
serviceName: flyServiceName,
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Fly-specific naming strategy. Extends the core strategy with the fly config.
|
|
24
|
+
*/
|
|
25
|
+
export class NamingStrategy extends CoreNamingStrategy {
|
|
26
|
+
constructor(results) {
|
|
27
|
+
const inputs = results.map((r) => ({
|
|
28
|
+
typeName: r.resource.typeName,
|
|
29
|
+
propertyTypes: r.propertyTypes,
|
|
30
|
+
}));
|
|
31
|
+
super(inputs, flyNamingConfig);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { packagePipeline, collectSkills } from "@intentius/chant/codegen/package";
|
|
2
|
+
import { generate } from "./generate.js";
|
|
3
|
+
import { flyPlugin } from "../plugin.js";
|
|
4
|
+
import { readFileSync } from "fs";
|
|
5
|
+
import { dirname, join } from "path";
|
|
6
|
+
import { moduleSourceDir } from "@intentius/chant/module-source";
|
|
7
|
+
/**
|
|
8
|
+
* Package the fly lexicon for distribution.
|
|
9
|
+
*/
|
|
10
|
+
export async function packageLexicon(options) {
|
|
11
|
+
// This file is src/codegen/package.ts — rules and skills are collected
|
|
12
|
+
// relative to src/, so srcDir must be the parent of this directory.
|
|
13
|
+
// Pointing it at src/codegen made collectRules glob a directory that does
|
|
14
|
+
// not exist, and the bundle shipped zero rules alongside zero skills.
|
|
15
|
+
const srcDir = dirname(moduleSourceDir(import.meta.url));
|
|
16
|
+
const pkgJson = JSON.parse(readFileSync(join(srcDir, "..", "package.json"), "utf-8"));
|
|
17
|
+
const { spec, stats } = await packagePipeline({
|
|
18
|
+
generate: (opts) => generate({ verbose: opts?.verbose, force: opts?.force }),
|
|
19
|
+
// chant #1067 — chantVersion/namespace/version were never populated here
|
|
20
|
+
// (a hardcoded "0.0.1", never the real package version), so
|
|
21
|
+
// `dist/manifest.json` shipped without a chantVersion at all. Matches
|
|
22
|
+
// the shape every other lexicon's codegen/package.ts already uses.
|
|
23
|
+
buildManifest: (_genResult) => ({
|
|
24
|
+
name: "fly",
|
|
25
|
+
version: pkgJson.version ?? "0.0.0",
|
|
26
|
+
chantVersion: ">=0.1.0",
|
|
27
|
+
namespace: "Fly",
|
|
28
|
+
}),
|
|
29
|
+
srcDir,
|
|
30
|
+
collectSkills: () => collectSkills(flyPlugin.skills?.() ?? []),
|
|
31
|
+
});
|
|
32
|
+
// Both callers (the plugin's package() and package-cli) print their own
|
|
33
|
+
// summary — don't double-report here.
|
|
34
|
+
return { spec, stats };
|
|
35
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ownPackageVersion } from "@intentius/chant/components/capability-plugin";
|
|
2
|
+
import { flyRunAgentCapability } from "./run-agent.js";
|
|
3
|
+
import { flyReleaseCapability, flyRollbackCapability } from "./fly-release.js";
|
|
4
|
+
export const FLY_VERB_FAMILIES = {
|
|
5
|
+
agentExecution: ["run-agent"],
|
|
6
|
+
// A release served by a Fly Machine, and going back to an earlier one (#2736).
|
|
7
|
+
apply: ["fly-release", "fly-rollback"],
|
|
8
|
+
};
|
|
9
|
+
export const flyCapabilityPlugin = {
|
|
10
|
+
name: "fly",
|
|
11
|
+
// The lexicon package's own version (mirrors aws/helm's #1505 fix — a
|
|
12
|
+
// getter so the package.json read happens on first access, not at import time).
|
|
13
|
+
get version() {
|
|
14
|
+
return ownPackageVersion(import.meta.url);
|
|
15
|
+
},
|
|
16
|
+
capabilities() {
|
|
17
|
+
return [
|
|
18
|
+
flyRunAgentCapability,
|
|
19
|
+
flyReleaseCapability,
|
|
20
|
+
flyRollbackCapability,
|
|
21
|
+
];
|
|
22
|
+
},
|
|
23
|
+
families() {
|
|
24
|
+
return FLY_VERB_FAMILIES;
|
|
25
|
+
},
|
|
26
|
+
};
|