@eiva/protoc-gen-fletcher 0.1.1-alpha
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/README.md +86 -0
- package/bin/protoc-gen-fletcher.js +110 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# @eiva/protoc-gen-fletcher
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@eiva/protoc-gen-fletcher)
|
|
4
|
+
|
|
5
|
+
A `protoc` plugin that generates typed `TypedSchema<T>` modules (`.fletcher.ts`) from `.proto` files. Pairs with [`@eiva/fletcher-gateway-client`](https://www.npmjs.com/package/@eiva/fletcher-gateway-client), Fletcher's WebSocket gateway runtime.
|
|
6
|
+
|
|
7
|
+
This package is a thin Node.js shim. On first invocation it downloads the platform-matching native plugin binary from [Fletcher's GitHub Releases](https://github.com/eivacom/Fletcher/releases) and caches it under `~/.cache/protoc-gen-fletcher/<version>/`. Subsequent invocations exec the cached binary directly.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install --save-dev @eiva/protoc-gen-fletcher
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install --save-dev @protobuf-ts/protoc
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install --save-dev fletcher-gateway-client@npm:@eiva/fletcher-gateway-client
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Three pieces:
|
|
24
|
+
|
|
25
|
+
- **`@eiva/protoc-gen-fletcher`** — this plugin shim.
|
|
26
|
+
- **`@protobuf-ts/protoc`** — ships the `protoc` compiler binary itself. Declared as a peer dependency; npm 7+ auto-installs it, older npm versions print a warning. Install explicitly above to be safe.
|
|
27
|
+
- **`fletcher-gateway-client`** under the bare alias `npm:@eiva/fletcher-gateway-client` — the generated `.fletcher.ts` files import `WireTypeId` and the `TypedSchema` type from a **bare** `'fletcher-gateway-client'` specifier. Installing under that alias makes the published `@eiva/fletcher-gateway-client` resolve at runtime via standard Node resolution (no tsconfig path-alias trickery needed).
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
Wire `proto:gen` into your `package.json`. Adding it as a `prebuild` script keeps generated bindings in sync with `.proto` changes automatically — every `npm run build` regenerates first.
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"scripts": {
|
|
36
|
+
"proto:gen": "node -e \"require('fs').mkdirSync('src/generated',{recursive:true})\" && protoc --fletcher_opt=ts --fletcher_out=src/generated -I proto proto/*.proto",
|
|
37
|
+
"prebuild": "npm run proto:gen",
|
|
38
|
+
"build": "tsc"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Two notes:
|
|
44
|
+
|
|
45
|
+
- The leading `node -e mkdirSync(...)` ensures `src/generated/` exists before `protoc` runs — `protoc` does not auto-create its `--fletcher_out` directory, and `mkdir -p` is not portable to Windows.
|
|
46
|
+
- No `--plugin=` flag is needed. `protoc` searches `PATH` (which npm prepends `node_modules/.bin/` to during script execution) for `protoc-gen-<name>` based on the `--<name>_out` flag, with the OS's executable-extension rules — so the `protoc-gen-fletcher.cmd` wrapper that npm writes alongside the bin shim is found correctly on Windows.
|
|
47
|
+
|
|
48
|
+
Then:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm run build
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
…regenerates `src/generated/*.fletcher.ts` and compiles. Consume the generated descriptor:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { FletcherClient } from '@eiva/fletcher-gateway-client';
|
|
58
|
+
import { Telemetry, type ITelemetry } from './generated/telemetry.fletcher.js';
|
|
59
|
+
|
|
60
|
+
const client = new FletcherClient({ url: 'ws://localhost:9090' });
|
|
61
|
+
await client.connect();
|
|
62
|
+
|
|
63
|
+
await client.publish('telemetry', Telemetry, {
|
|
64
|
+
sensor_id: 42,
|
|
65
|
+
temperature: 23.5,
|
|
66
|
+
} satisfies ITelemetry);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Supported platforms
|
|
70
|
+
|
|
71
|
+
| OS / arch | GitHub Release asset |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `linux/x64` | `protoc-gen-fletcher-linux-x64` |
|
|
74
|
+
| `win32/x64` | `protoc-gen-fletcher-windows-x64.exe` |
|
|
75
|
+
|
|
76
|
+
Adding macOS / arm64 is tracked in [Fletcher's issue tracker](https://github.com/eivacom/Fletcher/issues).
|
|
77
|
+
|
|
78
|
+
## Environment variables
|
|
79
|
+
|
|
80
|
+
| Variable | Purpose |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `PROTOC_GEN_FLETCHER_RELEASES_URL` | Override the GitHub Releases base URL (e.g. to test against a fork or a mirror). Default: `https://github.com/eivacom/Fletcher/releases/download`. |
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
LGPL-3.0-or-later © The Fletcher Authors. The shim itself is in this repo at [`protoc/npm/`](https://github.com/eivacom/Fletcher/tree/main/protoc/npm); the native plugin source is in [`protoc/`](https://github.com/eivacom/Fletcher/tree/main/protoc).
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
3
|
+
// Copyright (C) 2026 The Fletcher Authors
|
|
4
|
+
//
|
|
5
|
+
// Node.js shim for the fletcher-protoc plugin. On first invocation it
|
|
6
|
+
// downloads the platform-matching native binary from this package's matching
|
|
7
|
+
// protoc-v<version> GitHub Release, caches it under
|
|
8
|
+
// ~/.cache/protoc-gen-fletcher/<version>/, and exec's it with inherited
|
|
9
|
+
// stdin/stdout/stderr so protoc's CodeGeneratorRequest / CodeGeneratorResponse
|
|
10
|
+
// pipe protocol passes through the shim unchanged.
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const fs = require('node:fs');
|
|
15
|
+
const path = require('node:path');
|
|
16
|
+
const os = require('node:os');
|
|
17
|
+
const https = require('node:https');
|
|
18
|
+
const { spawnSync } = require('node:child_process');
|
|
19
|
+
|
|
20
|
+
const { version: VERSION } = require('../package.json');
|
|
21
|
+
const RELEASE_BASE =
|
|
22
|
+
process.env.PROTOC_GEN_FLETCHER_RELEASES_URL ||
|
|
23
|
+
'https://github.com/eivacom/Fletcher/releases/download';
|
|
24
|
+
|
|
25
|
+
function platformAssetName() {
|
|
26
|
+
const platform = os.platform();
|
|
27
|
+
const arch = os.arch();
|
|
28
|
+
if (platform === 'linux' && arch === 'x64') {
|
|
29
|
+
return 'protoc-gen-fletcher-linux-x64';
|
|
30
|
+
}
|
|
31
|
+
if (platform === 'win32' && arch === 'x64') {
|
|
32
|
+
return 'protoc-gen-fletcher-windows-x64.exe';
|
|
33
|
+
}
|
|
34
|
+
throw new Error(
|
|
35
|
+
`protoc-gen-fletcher: unsupported platform ${platform}/${arch}. ` +
|
|
36
|
+
`Supported: linux/x64, win32/x64.`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function cacheDir() {
|
|
41
|
+
return path.join(os.homedir(), '.cache', 'protoc-gen-fletcher', VERSION);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function followRedirects(url, depth) {
|
|
45
|
+
if (depth > 5) {
|
|
46
|
+
return Promise.reject(new Error(`Too many redirects: ${url}`));
|
|
47
|
+
}
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
https
|
|
50
|
+
.get(url, (res) => {
|
|
51
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
52
|
+
res.resume();
|
|
53
|
+
return resolve(followRedirects(res.headers.location, depth + 1));
|
|
54
|
+
}
|
|
55
|
+
if (res.statusCode !== 200) {
|
|
56
|
+
return reject(
|
|
57
|
+
new Error(
|
|
58
|
+
`Download failed (${res.statusCode}): ${url}\n` +
|
|
59
|
+
`Check that the release exists at ` +
|
|
60
|
+
`https://github.com/eivacom/Fletcher/releases/tag/protoc-v${VERSION}`,
|
|
61
|
+
),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
const chunks = [];
|
|
65
|
+
res.on('data', (chunk) => chunks.push(chunk));
|
|
66
|
+
res.on('end', () => resolve(Buffer.concat(chunks)));
|
|
67
|
+
res.on('error', reject);
|
|
68
|
+
})
|
|
69
|
+
.on('error', reject);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function ensureBinary() {
|
|
74
|
+
const asset = platformAssetName();
|
|
75
|
+
const cacheBin = path.join(cacheDir(), asset);
|
|
76
|
+
if (fs.existsSync(cacheBin)) {
|
|
77
|
+
return cacheBin;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const url = `${RELEASE_BASE}/protoc-v${VERSION}/${asset}`;
|
|
81
|
+
process.stderr.write(`protoc-gen-fletcher: downloading ${url}\n`);
|
|
82
|
+
|
|
83
|
+
fs.mkdirSync(cacheDir(), { recursive: true });
|
|
84
|
+
const buf = await followRedirects(url, 0);
|
|
85
|
+
|
|
86
|
+
// Atomic write: write to a unique tmp file in the same dir, then rename.
|
|
87
|
+
// Multiple npm scripts may invoke the shim in parallel; rename within the
|
|
88
|
+
// same filesystem is atomic so concurrent callers cannot see a half-written
|
|
89
|
+
// file.
|
|
90
|
+
const tmp = `${cacheBin}.tmp.${process.pid}`;
|
|
91
|
+
fs.writeFileSync(tmp, buf, { mode: 0o755 });
|
|
92
|
+
fs.renameSync(tmp, cacheBin);
|
|
93
|
+
|
|
94
|
+
return cacheBin;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
(async () => {
|
|
98
|
+
try {
|
|
99
|
+
const binary = await ensureBinary();
|
|
100
|
+
// stdio: 'inherit' makes the child binary share this Node process's
|
|
101
|
+
// stdin/stdout/stderr handles. protoc spawns us with pipe-based
|
|
102
|
+
// stdin/stdout for the plugin protocol; the binary inherits those exact
|
|
103
|
+
// pipes and reads/writes them directly. Node never touches the bytes.
|
|
104
|
+
const result = spawnSync(binary, process.argv.slice(2), { stdio: 'inherit' });
|
|
105
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
process.stderr.write(`protoc-gen-fletcher: ${err.message}\n`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
})();
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@eiva/protoc-gen-fletcher",
|
|
3
|
+
"version": "0.1.1-alpha",
|
|
4
|
+
"description": "protoc plugin that generates typed TypeScript schema descriptors for Fletcher's positional wire format. Downloads the platform-matching native plugin binary from GitHub Releases on first invocation.",
|
|
5
|
+
"license": "LGPL-3.0-or-later",
|
|
6
|
+
"homepage": "https://github.com/eivacom/Fletcher/tree/main/protoc",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/eivacom/Fletcher.git",
|
|
10
|
+
"directory": "protoc/npm"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/eivacom/Fletcher/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"protoc",
|
|
17
|
+
"protobuf",
|
|
18
|
+
"fletcher",
|
|
19
|
+
"code-generation",
|
|
20
|
+
"typescript"
|
|
21
|
+
],
|
|
22
|
+
"bin": {
|
|
23
|
+
"protoc-gen-fletcher": "./bin/protoc-gen-fletcher.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"bin/",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=18"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@protobuf-ts/protoc": "^2.9.5"
|
|
34
|
+
}
|
|
35
|
+
}
|