@forwardimpact/libcodegen 0.1.60 → 0.1.61

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.
@@ -2,8 +2,15 @@
2
2
 
3
3
  import "@forwardimpact/libpreflight/node22";
4
4
 
5
- import fs, { readFileSync } from "node:fs";
6
- import fsAsync from "node:fs/promises";
5
+ // Bind protobufjs's `util.Long` before any other import evaluates. The
6
+ // `@grpc/proto-loader` import below pulls in protobufjs's descriptor extension,
7
+ // which calls `Root.fromJSON(...).resolveAll()` at module-evaluation time —
8
+ // resolving a 64-bit field default needs `util.Long`, which `bun --compile`
9
+ // leaves undefined (see long-init.js). This side-effect import must precede the
10
+ // proto-loader import so the binding is in place before that resolveAll runs.
11
+ import "../src/long-init.js";
12
+
13
+ import fs from "node:fs";
7
14
  import path from "node:path";
8
15
  import { execFileSync } from "node:child_process";
9
16
 
@@ -11,7 +18,7 @@ import protoLoader from "@grpc/proto-loader";
11
18
  import mustache from "mustache";
12
19
 
13
20
  import { createCli, SummaryRenderer } from "@forwardimpact/libcli";
14
- import { Finder } from "@forwardimpact/libutil";
21
+ import { createDefaultRuntime } from "@forwardimpact/libutil/runtime";
15
22
  import { Logger } from "@forwardimpact/libtelemetry";
16
23
  import {
17
24
  CodegenBase,
@@ -22,17 +29,8 @@ import {
22
29
  } from "@forwardimpact/libcodegen";
23
30
  import { createStorage } from "@forwardimpact/libstorage";
24
31
 
25
- // `bun build --compile` injects FIT_CODEGEN_VERSION via --define, eliminating
26
- // the readFileSync branch in the compiled binary (which would ENOENT against
27
- // the bunfs virtual mount). Source execution falls through to package.json.
28
- const VERSION =
29
- process.env.FIT_CODEGEN_VERSION ||
30
- JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"))
31
- .version;
32
-
33
32
  const definition = {
34
33
  name: "fit-codegen",
35
- version: VERSION,
36
34
  description:
37
35
  "Generate protobuf types, service clients, and definitions from .proto files in installed @forwardimpact/* packages (node_modules/@forwardimpact/*/proto/) and an optional project-local proto/ directory.",
38
36
  globalOptions: {
@@ -62,7 +60,11 @@ const definition = {
62
60
  ],
63
61
  };
64
62
 
65
- const cli = createCli(definition);
63
+ const runtime = createDefaultRuntime();
64
+ const cli = createCli(definition, {
65
+ runtime,
66
+ packageJsonUrl: new URL("../package.json", import.meta.url),
67
+ });
66
68
 
67
69
  /**
68
70
  * Create tar.gz bundle of all directories inside sourcePath
@@ -179,6 +181,7 @@ function createCodegen(
179
181
  mustache,
180
182
  protoLoader,
181
183
  fs,
184
+ runtime,
182
185
  ) {
183
186
  const base = new CodegenBase(
184
187
  protoDirs,
@@ -187,6 +190,7 @@ function createCodegen(
187
190
  mustache,
188
191
  protoLoader,
189
192
  fs,
193
+ runtime,
190
194
  );
191
195
  return {
192
196
  types: new CodegenTypes(base),
@@ -356,6 +360,7 @@ async function runCodegen(protoDirs, projectRoot, finder) {
356
360
  mustache,
357
361
  protoLoader,
358
362
  fs,
363
+ runtime,
359
364
  );
360
365
  await executeGeneration(codegens, sourcePath, parsedFlags);
361
366
 
@@ -370,8 +375,11 @@ async function runCodegen(protoDirs, projectRoot, finder) {
370
375
  */
371
376
  async function main() {
372
377
  try {
373
- const logger = new Logger("codegen");
374
- const finder = new Finder(fsAsync, logger, process);
378
+ const logger = new Logger("codegen", runtime);
379
+ // The shared runtime.finder carries a no-op logger; bind this CLI's logger
380
+ // so createPackageSymlinks (the one logging Finder consumer) keeps emitting
381
+ // symlink debug logs.
382
+ const finder = runtime.finder.withLogger(logger);
375
383
  const projectRoot = finder.findProjectRoot(process.cwd());
376
384
 
377
385
  const protoDirs = discoverProtoDirs(projectRoot);
@@ -385,7 +393,7 @@ async function main() {
385
393
 
386
394
  await runCodegen(protoDirs, projectRoot, finder);
387
395
  } catch (err) {
388
- const logger = new Logger("codegen");
396
+ const logger = new Logger("codegen", runtime);
389
397
  logger.exception("main", err);
390
398
  cli.error(err.message);
391
399
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forwardimpact/libcodegen",
3
- "version": "0.1.60",
3
+ "version": "0.1.61",
4
4
  "description": "Protobuf code generation — keep types in sync with proto definitions without hand-writing.",
5
5
  "keywords": [
6
6
  "codegen",
package/src/base.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { fileURLToPath } from "node:url";
2
2
  import protobuf from "protobufjs";
3
- import { createDefaultRuntime } from "@forwardimpact/libutil/runtime";
3
+ import "./long-init.js";
4
4
 
5
5
  /** Convert camelCase to snake_case (protobufjs normalizes field names) */
6
6
  function camelToSnake(str) {
@@ -71,7 +71,7 @@ export class CodegenBase {
71
71
  * @param {object} mustache - Mustache template rendering module
72
72
  * @param {object} protoLoader - Protocol buffer loader module
73
73
  * @param {object} fs - File system module (sync operations only)
74
- * @param {object} [runtime] - Optional runtime bag; falls back to createDefaultRuntime()
74
+ * @param {import("@forwardimpact/libutil/runtime").Runtime} runtime - Injected runtime bag
75
75
  */
76
76
  constructor(
77
77
  protoDirs,
@@ -90,6 +90,7 @@ export class CodegenBase {
90
90
  if (!mustache) throw new Error("mustache module is required");
91
91
  if (!protoLoader) throw new Error("protoLoader module is required");
92
92
  if (!fs) throw new Error("fs module is required");
93
+ if (!runtime) throw new Error("runtime is required");
93
94
 
94
95
  this.#protoDirs = protoDirs;
95
96
  this.#projectRoot = projectRoot;
@@ -97,7 +98,7 @@ export class CodegenBase {
97
98
  this.#mustache = mustache;
98
99
  this.#protoLoader = protoLoader;
99
100
  this.#fs = fs;
100
- this.#subprocess = (runtime ?? createDefaultRuntime()).subprocess;
101
+ this.#subprocess = runtime.subprocess;
101
102
  }
102
103
 
103
104
  /**
@@ -160,7 +161,7 @@ export class CodegenBase {
160
161
 
161
162
  /**
162
163
  * Load mustache template for given kind
163
- * @param {"service"|"client"|"exports"|"definition"|"definitions-exports"|"services-exports"} kind - Template kind
164
+ * @param {"service"|"client"|"definition"|"definitions-exports"|"services-exports"} kind - Template kind
164
165
  * @returns {string} Template content
165
166
  */
166
167
  loadTemplate(kind) {
@@ -0,0 +1,17 @@
1
+ // protobufjs populates `util.Long` through a dynamic `inquire("long")` that
2
+ // `bun build --compile` cannot resolve, leaving it undefined when a 64-bit
3
+ // field default is computed — crashing the compiled fit-codegen binary at
4
+ // startup (`util.Long.fromNumber is not a function`). Bind it explicitly.
5
+ //
6
+ // Imported for its side effect both by `bin/fit-codegen.js` (ahead of the
7
+ // `@grpc/proto-loader` import, whose descriptor extension runs `resolveAll()`
8
+ // at module-evaluation time) and by base.js (ahead of its own runtime
9
+ // `Root.resolveAll()`). ES module imports evaluate in source order, so an
10
+ // ordered side-effect import binds before the proto-loading code runs —
11
+ // inline binding statements in an entry body would not, since imports hoist
12
+ // above them.
13
+ import protobuf from "protobufjs";
14
+ import Long from "long";
15
+
16
+ protobuf.util.Long = Long;
17
+ protobuf.configure();
@@ -13,12 +13,13 @@ export class {{className}} extends Client {
13
13
  /**
14
14
  * Creates a new {{serviceName}} client instance
15
15
  * @param {object} config - Service configuration
16
+ * @param {import("@forwardimpact/libutil/runtime").Runtime} runtime - Injected runtime bag (required; the default auth factory reads SERVICE_SECRET from it)
16
17
  * @param {import("@forwardimpact/libtelemetry").Logger} [logger] - Optional logger instance
17
18
  * @param {import("@forwardimpact/libtelemetry").Tracer} [tracer] - Optional tracer for distributed tracing
18
19
  * @param {Function} [authFn] - Optional authentication function
19
20
  */
20
- constructor(config, logger = null, tracer = null, authFn = createAuth) {
21
- super(config, logger, tracer, createObserver, createGrpc, authFn);
21
+ constructor(config, runtime, logger = null, tracer = null, authFn = createAuth) {
22
+ super(config, runtime, logger, tracer, createObserver, createGrpc, authFn);
22
23
  }
23
24
 
24
25
  {{#methods}}