@forwardimpact/librpc 0.1.103 → 0.1.105
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/bin/fit-unary.js +16 -10
- package/package.json +3 -3
- package/src/base.js +6 -2
- package/src/server.js +8 -1
package/bin/fit-unary.js
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "@forwardimpact/libpreflight/node22";
|
|
3
3
|
|
|
4
|
-
import { readFileSync } from "node:fs";
|
|
5
4
|
import { createCli } from "@forwardimpact/libcli";
|
|
6
5
|
import { createClient, createTracer } from "@forwardimpact/librpc";
|
|
7
6
|
import { createLogger } from "@forwardimpact/libtelemetry";
|
|
7
|
+
import { createDefaultRuntime } from "@forwardimpact/libutil/runtime";
|
|
8
|
+
|
|
9
|
+
const runtime = createDefaultRuntime();
|
|
8
10
|
|
|
9
11
|
// `bun build --compile` injects FIT_UNARY_VERSION via --define, eliminating
|
|
10
12
|
// the readFileSync branch in the compiled binary (which would ENOENT against
|
|
11
13
|
// the bunfs virtual mount). Source execution falls through to package.json.
|
|
12
14
|
const VERSION =
|
|
13
|
-
|
|
14
|
-
JSON.parse(
|
|
15
|
-
.
|
|
15
|
+
runtime.proc.env.FIT_UNARY_VERSION ||
|
|
16
|
+
JSON.parse(
|
|
17
|
+
runtime.fsSync.readFileSync(
|
|
18
|
+
new URL("../package.json", import.meta.url),
|
|
19
|
+
"utf8",
|
|
20
|
+
),
|
|
21
|
+
).version;
|
|
16
22
|
|
|
17
23
|
const definition = {
|
|
18
24
|
name: "fit-unary",
|
|
@@ -27,7 +33,7 @@ const definition = {
|
|
|
27
33
|
examples: ['fit-unary memory GetWindow \'{"resource_id":"..."}\''],
|
|
28
34
|
};
|
|
29
35
|
|
|
30
|
-
const cli = createCli(definition);
|
|
36
|
+
const cli = createCli(definition, { runtime });
|
|
31
37
|
const logger = createLogger("cli");
|
|
32
38
|
|
|
33
39
|
/**
|
|
@@ -35,13 +41,13 @@ const logger = createLogger("cli");
|
|
|
35
41
|
* @returns {Promise<void>}
|
|
36
42
|
*/
|
|
37
43
|
async function main() {
|
|
38
|
-
const parsed = cli.parse(
|
|
39
|
-
if (!parsed)
|
|
44
|
+
const parsed = cli.parse(runtime.proc.argv.slice(2));
|
|
45
|
+
if (!parsed) return runtime.proc.exit(0);
|
|
40
46
|
|
|
41
47
|
const [service, method, requestJson] = parsed.positionals;
|
|
42
48
|
if (!service || !method) {
|
|
43
49
|
cli.usageError("expected arguments: <service> <method> [json-request]");
|
|
44
|
-
|
|
50
|
+
return runtime.proc.exit(2);
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
const request = requestJson ? JSON.parse(requestJson) : {};
|
|
@@ -49,11 +55,11 @@ async function main() {
|
|
|
49
55
|
const client = await createClient(service, logger, tracer);
|
|
50
56
|
|
|
51
57
|
const response = await client.callUnary(method, request);
|
|
52
|
-
|
|
58
|
+
runtime.proc.stdout.write(JSON.stringify(response, null, 2) + "\n");
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
main().catch((error) => {
|
|
56
62
|
logger.exception("main", error);
|
|
57
63
|
cli.error(error.message);
|
|
58
|
-
|
|
64
|
+
runtime.proc.exit(1);
|
|
59
65
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forwardimpact/librpc",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.105",
|
|
4
4
|
"description": "gRPC server and client framework — ship service endpoints without reimplementing transport.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"grpc",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"jobs": [
|
|
21
21
|
{
|
|
22
22
|
"user": "Platform Builders",
|
|
23
|
-
"goal": "
|
|
23
|
+
"goal": "Ship Service Endpoints Without Boilerplate",
|
|
24
24
|
"trigger": "Starting a new service and reaching for last project's copy-pasted transport boilerplate.",
|
|
25
|
-
"bigHire": "ship a service endpoint without reimplementing transport.",
|
|
25
|
+
"bigHire": "ship a gRPC service endpoint without reimplementing transport.",
|
|
26
26
|
"littleHire": "call a service without managing connections or retries.",
|
|
27
27
|
"competesWith": "copy-pasting boilerplate; hand-writing protobuf clients; tolerating the duplication"
|
|
28
28
|
}
|
package/src/base.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import grpc from "@grpc/grpc-js";
|
|
2
2
|
|
|
3
3
|
import { createObserver } from "@forwardimpact/libtelemetry";
|
|
4
|
+
import { createDefaultProc } from "@forwardimpact/libutil/runtime";
|
|
4
5
|
|
|
5
6
|
import { Interceptor, HmacAuth } from "./auth.js";
|
|
6
7
|
import { definitions } from "./generated/definitions/exports.js";
|
|
@@ -23,12 +24,15 @@ export function createGrpc() {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
|
-
* Default auth factory that creates authentication interceptor
|
|
27
|
+
* Default auth factory that creates authentication interceptor.
|
|
28
|
+
* Reads `SERVICE_SECRET` through `createDefaultProc().env` (a late-binding
|
|
29
|
+
* Proxy over `process.env`) rather than touching the `process` global
|
|
30
|
+
* directly — same read semantics as before, no ambient-dep smell.
|
|
27
31
|
* @param {string} serviceName - Name of the service for the interceptor
|
|
28
32
|
* @returns {Interceptor} Configured interceptor instance
|
|
29
33
|
*/
|
|
30
34
|
export function createAuth(serviceName) {
|
|
31
|
-
const secret =
|
|
35
|
+
const secret = createDefaultProc().env.SERVICE_SECRET;
|
|
32
36
|
if (!secret) {
|
|
33
37
|
throw new Error(
|
|
34
38
|
`SERVICE_SECRET environment variable is required for service ${serviceName}`,
|
package/src/server.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
capitalizeFirstLetter,
|
|
7
7
|
} from "./base.js";
|
|
8
8
|
import { healthDefinition, createHealthHandlers } from "./health.js";
|
|
9
|
+
import { createDefaultRuntime } from "@forwardimpact/libutil/runtime";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* gRPC Server class using pre-compiled service definitions
|
|
@@ -14,6 +15,7 @@ import { healthDefinition, createHealthHandlers } from "./health.js";
|
|
|
14
15
|
export class Server extends Rpc {
|
|
15
16
|
#server;
|
|
16
17
|
#service;
|
|
18
|
+
#runtime;
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* Creates a gRPC server for a service
|
|
@@ -24,6 +26,8 @@ export class Server extends Rpc {
|
|
|
24
26
|
* @param {(serviceName: string, logger: object, tracer: object) => object} observerFn - Observer factory
|
|
25
27
|
* @param {() => {grpc: object}} grpcFn - gRPC factory
|
|
26
28
|
* @param {(serviceName: string) => object} authFn - Auth factory
|
|
29
|
+
* @param {import("@forwardimpact/libutil/runtime").Runtime} [runtime] - Optional runtime bag;
|
|
30
|
+
* falls back to `createDefaultRuntime()` so existing service callers keep working.
|
|
27
31
|
*/
|
|
28
32
|
constructor(
|
|
29
33
|
service,
|
|
@@ -33,11 +37,13 @@ export class Server extends Rpc {
|
|
|
33
37
|
observerFn = createObserver,
|
|
34
38
|
grpcFn = createGrpc,
|
|
35
39
|
authFn = createAuth,
|
|
40
|
+
runtime = null,
|
|
36
41
|
) {
|
|
37
42
|
if (!service) throw new Error("service is required");
|
|
38
43
|
|
|
39
44
|
super(config, logger, tracer, observerFn, grpcFn, authFn);
|
|
40
45
|
this.#service = service;
|
|
46
|
+
this.#runtime = runtime ?? createDefaultRuntime();
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
/** Starts the gRPC server */
|
|
@@ -204,6 +210,7 @@ export class Server extends Rpc {
|
|
|
204
210
|
|
|
205
211
|
/** Sets up graceful shutdown handlers */
|
|
206
212
|
#setupShutdown() {
|
|
213
|
+
const runtime = this.#runtime;
|
|
207
214
|
const shutdown = async () => {
|
|
208
215
|
this.observer().logger()?.info("Server", "Shutting down...");
|
|
209
216
|
|
|
@@ -212,7 +219,7 @@ export class Server extends Rpc {
|
|
|
212
219
|
await this.#service.shutdown();
|
|
213
220
|
}
|
|
214
221
|
|
|
215
|
-
this.#server.tryShutdown(() =>
|
|
222
|
+
this.#server.tryShutdown(() => runtime.proc.exit(0));
|
|
216
223
|
};
|
|
217
224
|
process.on("SIGINT", shutdown);
|
|
218
225
|
process.on("SIGTERM", shutdown);
|