Ctrl K
ComunidadGuías…

cli-ext/README.md

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
## Building the binaries

The binaries are built using the [pkg](https://www.npmjs.com/package/pkg) package. Run the following commands:

```bash
npm install
npm run build
OR
make clean-build
```

The binaries will be placed in the `bin` directory at root. Copy the binary to your PATH as `cli-ext`.

Presently, binaries are built for following targets:

- node24.22.1-linux-x64
- node24.22.1-windows-x64
- node24.22.1-macos-x64
- node24.22.1-linux-arm64
- node24.22.1-macos-arm64

More information on `pkg` and `targets` is available on the [pkg page](https://www.npmjs.com/package/pkg).

If you want to build only a specific binary or one for a different target altogether, you can do so by following the commands below:

```bash
npm install -g pkg
pkg ./build/command.js --output <output-path> -t <node-range>-<platform>-<architecture>
```

A supported list and combinations of `node-range`, `platform` and `architecture` is provided [here](https://www.npmjs.com/package/pkg-fetch).

The hasura cli provides a `--cli-ext-path` flag to use a different cli-ext binary.

## Releasing cli-ext

cli-ext publication uses an already-built pull-request commit, separately from
an HGE/CLI release:

1. Open a PR with the cli-ext changes and apply `auto-approve-ci` and
   `ci/build-cli-ext`. Do not apply `auto-update-auto-merge` before the source
   build: that mode reuses cached binaries. CLI/console dev modes and server-test
   mode can omit the job, and normal mono CI skip rules still apply.
2. Wait for a successful, actually executed source build in the mono pipeline's
   `build-cli-ext` job. Record the exact source commit and producer job; a green
   cached or skipped job is not sufficient.
3. Push a new `cli-ext/vX.Y.Z` tag on that exact successfully built commit. The
   tagged commit must include the release workflow and producer-selection logic
   described here. The `release cli-ext` GitHub workflow selects the newest
   **mono** producer status on that SHA; a pending or failed mono build blocks
   publication, even if an older mono build succeeded. Tag-triggered EE-lite
   statuses are not release producers. No new source build is requested by the
   tag itself.
4. Check the workflow's provenance/checksum verification, macOS arm64 ad-hoc
   signing, and publication to
   `gs://graphql-engine-cdn.hasura.io/cli-ext/releases/versioned/vX.Y.Z/`.
   Missing, expired, cached, or mismatched artifacts fail closed; rebuild the
   same source commit in mono and rerun the workflow instead of bypassing checks.
5. In the same PR, update the cached-download version in
   `.buildkite/scripts/cli/build-cli-ext.sh` and the Go CLI fallback version in
   `cli/internal/cliext/cli_ext.go`. Leave the release tag on the earlier built
   commit; then get the pin update reviewed and merged.
6. Include that pin update in the next relevant HGE/CLI release branch and verify
   the helper embedded by the released CLI. Publishing a helper does not upgrade
   existing CLI executables, and `cli-ext/package.json` does not determine the
   published CDN version.

The Buildkite webhook filters can still start a full EE-lite pipeline for a
`cli-ext/` tag. This procedure does not require its source build or its HGE
publication/deployment gates, and does not change those external pipeline filters.

Run the credential-free release-helper regressions with:

```bash
node --test .github/scripts/cli-ext-*.test.js
```

## API

```
scaffolder sdl to '{ "types": { "enums": [], "scalars": [], "input_objects": [ { "name": "UserInput", "fields": [ { "name": "username", "type": "String", "description": "lalz" }, { "name": "password", "type": "String!", "description": "pass" } ] } ], "objects": [ { "name": "UserInfo", "fields": [ { "name": "accessToken", "type": "String", "description": "lolz" } ] } ] } }'

```

```
scaffolder sdl from '{ "sdl": { "action": "type Mutation { actionName (arg1: SampleInput!): SampleOutput }", "types": "type SampleOutput { accessToken: String! } input SampleInput { username: String! password: String! }" }, "types": { "scalars": [], "enums": [], "input_objects": [], "objects": [] } }'
```

```
scaffolder scaffold '{ "action": { "action_name": "validatedUserInsert", "action_defn": { "kind": "synchronous", "webhook": "http://192.168.0.107:5000/actions", "arguments": [{ "name": "user", "type": "_user_insert_input!", "description": null }], "output_type": "UserInfo" } }, "types": { "enums": [{ "name": "_user_constraint", "values": [{ "value": "user_pkey", "description": null, "is_deprecated": null }], "description": null }, { "name": "_user_update_column", "values": [{ "value": "email", "description": null, "is_deprecated": null }, { "value": "id", "description": null, "is_deprecated": null }, { "value": "username", "description": null, "is_deprecated": null }], "description": null }, { "name": "_article_constraint", "values": [{ "value": "article_pkey", "description": null, "is_deprecated": null }], "description": null }, { "name": "_article_update_column", "values": [{ "value": "author_id", "description": null, "is_deprecated": null }, { "value": "content", "description": null, "is_deprecated": null }, { "value": "id", "description": null, "is_deprecated": null }, { "value": "title", "description": null, "is_deprecated": null }], "description": null }], "objects": [{ "name": "UserInfo", "fields": [{ "name": "userId", "type": "Int", "arguments": null, "description": null }, { "name": "accessToken", "type": "String", "arguments": null, "description": null }], "description": null, "relationships": [{ "name": "user", "remote_table": "user", "field_mapping": { "userId": "id" } }, { "name": "anotherrel", "remote_table": "article", "field_mapping": { "userId": "id" } }] }, { "name": "SMSInfo", "fields": [{ "name": "sms_id", "type": "String!", "arguments": null, "description": null }], "description": null, "relationships": null }], "scalars": [], "input_objects": [{ "name": "_user_insert_input", "fields": [{ "name": "articles", "type": "_article_arr_rel_insert_input", "description": null }, { "name": "email", "type": "String", "description": null }, { "name": "id", "type": "Int", "description": null }, { "name": "username", "type": "String", "description": null }], "description": null }, { "name": "_article_arr_rel_insert_input", "fields": [{ "name": "data", "type": "[_article_insert_input!]!", "description": null }, { "name": "on_conflict", "type": "_article_on_conflict", "description": null }], "description": null }, { "name": "_article_insert_input", "fields": [{ "name": "author_id", "type": "Int", "description": null }, { "name": "content", "type": "String", "description": null }, { "name": "id", "type": "Int", "description": null }, { "name": "title", "type": "String", "description": null }, { "name": "user", "type": "_user_obj_rel_insert_input", "description": null }], "description": null }, { "name": "_user_obj_rel_insert_input", "fields": [{ "name": "data", "type": "_user_insert_input!", "description": null }, { "name": "on_conflict", "type": "_user_on_conflict", "description": null }], "description": null }, { "name": "_user_on_conflict", "fields": [{ "name": "constraint", "type": "_user_constraint!", "description": null }, { "name": "update_columns", "type": "[_user_update_column!]!", "description": null }, { "name": "where", "type": "_user_bool_exp", "description": null }], "description": null }, { "name": "_user_bool_exp", "fields": [{ "name": "_and", "type": "[_user_bool_exp]", "description": null }, { "name": "_not", "type": "_user_bool_exp", "description": null }, { "name": "_or", "type": "[_user_bool_exp]", "description": null }, { "name": "articles", "type": "_article_bool_exp", "description": null }, { "name": "email", "type": "_String_comparison_exp", "description": null }, { "name": "id", "type": "_Int_comparison_exp", "description": null }, { "name": "username", "type": "_String_comparison_exp", "description": null }], "description": null }, { "name": "_article_bool_exp", "fields": [{ "name": "_and", "type": "[_article_bool_exp]", "description": null }, { "name": "_not", "type": "_article_bool_exp", "description": null }, { "name": "_or", "type": "[_article_bool_exp]", "description": null }, { "name": "author_id", "type": "_Int_comparison_exp", "description": null }, { "name": "content", "type": "_String_comparison_exp", "description": null }, { "name": "id", "type": "_Int_comparison_exp", "description": null }, { "name": "title", "type": "_String_comparison_exp", "description": null }, { "name": "user", "type": "_user_bool_exp", "description": null }], "description": null }, { "name": "_Int_comparison_exp", "fields": [{ "name": "_eq", "type": "Int", "description": null }, { "name": "_gt", "type": "Int", "description": null }, { "name": "_gte", "type": "Int", "description": null }, { "name": "_in", "type": "[Int!]", "description": null }, { "name": "_is_null", "type": "Boolean", "description": null }, { "name": "_lt", "type": "Int", "description": null }, { "name": "_lte", "type": "Int", "description": null }, { "name": "_neq", "type": "Int", "description": null }, { "name": "_nin", "type": "[Int!]", "description": null }], "description": null }, { "name": "_String_comparison_exp", "fields": [{ "name": "_eq", "type": "String", "description": null }, { "name": "_gt", "type": "String", "description": null }, { "name": "_gte", "type": "String", "description": null }, { "name": "_ilike", "type": "String", "description": null }, { "name": "_in", "type": "[String!]", "description": null }, { "name": "_is_null", "type": "Boolean", "description": null }, { "name": "_like", "type": "String", "description": null }, { "name": "_lt", "type": "String", "description": null }, { "name": "_lte", "type": "String", "description": null }, { "name": "_neq", "type": "String", "description": null }, { "name": "_nilike", "type": "String", "description": null }, { "name": "_nin", "type": "[String!]", "description": null }, { "name": "_nlike", "type": "String", "description": null }, { "name": "_nsimilar", "type": "String", "description": null }, { "name": "_similar", "type": "String", "description": null }], "description": null }, { "name": "_article_on_conflict", "fields": [{ "name": "constraint", "type": "_article_constraint!", "description": null }, { "name": "update_columns", "type": "[_article_update_column!]!", "description": null }, { "name": "where", "type": "_article_bool_exp", "description": null }], "description": null }, { "name": "SMSInput", "fields": [{ "name": "sms", "type": "String", "description": null }, { "name": "is_international", "type": "Boolean", "description": null }, { "name": "price", "type": "[Price]", "description": null }], "description": null }, { "name": "Price", "fields": [{ "name": "value", "type": "String", "description": null }], "description": null }] }, "framework": "typescript-express" }'
```

## Templaters

The templaters are present in the `src/templaters` directory. You can modify the templaters and build.
Each templater function must return an array of file objects. Something like:

```
[
  {
    "name": "filename1.js",
    "content": "filename1 content"
  },
  {
    "name": "filename2.js",
    "content": "filename2 content"
  }
]
```

These files will be generated in the PWD of execution.

## Packaged runtime provenance and release gate

The locked packager is `@yao-pkg/pkg` 6.24.0, which requires `@yao-pkg/pkg-fetch` 3.6.7. The published pkg-fetch 3.6.7 patch manifest maps the pinned Node 24.22.1 targets to its Node 24.22.1 packaging patch. An updated build-host Node does not update the embedded runtime by itself.

Node 24.22.1's official release records the Brotli backport `49dff6f57a` of upstream `0ed4268a4401abcb4472096340477cf4af7d1a2b`. Its embedded Brotli version string remains 1.2.0; that string alone is not a security acceptance check. pkg-fetch's expected SHA-256 for its Linux x64 supplier binary is `c0a4715edd09277f0e66c780dc16eb40be7c14e823e074e0218dd6c27fdac4c3`.

For release validation, use a clean `PKG_CACHE_PATH`, disallow `PKG_NODE_PATH` overrides and locally built/fallback supplier entries, and verify the fetched supplier hash against the locked package. Validate each target independently. Retain the source commit, lockfile, supplier hash and final cli-ext hash, then run benign SDL-to/from and controlled-local-template scaffolding checks on the resulting executable in the final consumer images. A successful roundtrip or exported decoder constant is not a malformed-input regression.

The runtime update does not restrict action-codegen's template execution: its URL and local template paths still execute template JavaScript. Runtime dependency remediation must not be treated as remediation of that separate behavior or as evidence about a reported environment-extraction incident.