@databricks-solutions/lakebase-scm-utils 0.2.45 → 0.2.46

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.
Files changed (44) hide show
  1. package/README.md +13 -4
  2. package/dist/scripts/index.cjs +12 -3
  3. package/dist/scripts/index.js +12 -3
  4. package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +12 -3
  5. package/dist/scripts/lakebase/ci-resolve-branch.cli.js +12 -3
  6. package/dist/scripts/lakebase/collapse-heads.cli.cjs +12 -3
  7. package/dist/scripts/lakebase/collapse-heads.cli.js +12 -3
  8. package/dist/scripts/lakebase/detect-language.cli.cjs +12 -3
  9. package/dist/scripts/lakebase/detect-language.cli.js +12 -3
  10. package/dist/scripts/lakebase/doctor.cli.cjs +12 -3
  11. package/dist/scripts/lakebase/doctor.cli.js +12 -3
  12. package/dist/scripts/lakebase/get-connection.cli.cjs +12 -3
  13. package/dist/scripts/lakebase/get-connection.cli.js +12 -3
  14. package/dist/scripts/lakebase/index.cjs +12 -3
  15. package/dist/scripts/lakebase/index.d.cts +0 -11
  16. package/dist/scripts/lakebase/index.d.ts +0 -11
  17. package/dist/scripts/lakebase/index.js +12 -3
  18. package/dist/scripts/lakebase/infra-runner.cli.cjs +12 -3
  19. package/dist/scripts/lakebase/infra-runner.cli.js +12 -3
  20. package/dist/scripts/lakebase/new-migration.cli.cjs +12 -3
  21. package/dist/scripts/lakebase/new-migration.cli.js +12 -3
  22. package/dist/scripts/lakebase/schema-diff.cli.cjs +12 -3
  23. package/dist/scripts/lakebase/schema-diff.cli.js +12 -3
  24. package/dist/scripts/lakebase/schema-migrate.cli.cjs +12 -3
  25. package/dist/scripts/lakebase/schema-migrate.cli.js +12 -3
  26. package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +12 -3
  27. package/dist/scripts/lakebase/scm-claim-feature.cli.js +12 -3
  28. package/dist/scripts/lakebase/scm-doctor.cli.cjs +12 -3
  29. package/dist/scripts/lakebase/scm-doctor.cli.js +12 -3
  30. package/dist/scripts/lakebase/scm-merge.cli.cjs +12 -3
  31. package/dist/scripts/lakebase/scm-merge.cli.js +12 -3
  32. package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +12 -3
  33. package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +12 -3
  34. package/dist/scripts/util/index.cjs +2 -2
  35. package/dist/scripts/util/index.js +2 -2
  36. package/package.json +1 -1
  37. package/scripts/lakebase/constants.ts +23 -5
  38. package/scripts/lakebase/get-connection.ts +17 -3
  39. package/skills/lakebase-scm-workflows/README.md +2 -1
  40. package/templates/project/nodejs/package.json +3 -1
  41. package/templates/project/nodejs/src/index.js +8 -0
  42. package/templates/project/nodejs/src/openapi.js +20 -0
  43. package/templates/project/nodejs/src/routes/health.js +18 -0
  44. package/templates/project/nodejs/tests/app.test.js +16 -0
@@ -23,6 +23,7 @@ import {
23
23
  DEFAULT_DATABASE,
24
24
  DEFAULT_ENDPOINT,
25
25
  POSTGRES_PORT,
26
+ SCM_CLIENT_ENV,
26
27
  SCM_UTILS_APPLICATION_NAME,
27
28
  } from "./constants.js";
28
29
  import { substrateSelfVersion } from "./self-version.js";
@@ -39,11 +40,24 @@ import { KIT_TIMEOUTS } from "./kit-config.js";
39
40
  * `pg_stat_activity`. Never throws (an unreadable scm-utils version -> `scm-utils/unknown`; a
40
41
  * blank env is ignored), so labelling can never break a connection.
41
42
  */
43
+ /** Sanitize a consumer-provided application_name label: printable ASCII only (runs of control
44
+ * chars / whitespace collapse to a single '-'), trimmed of leading/trailing '-', and capped to
45
+ * Postgres's 63-byte application_name limit. Empty after cleaning -> the scm-utils default. */
46
+ function sanitizeApplicationName(raw: string): string {
47
+ const cleaned = raw.replace(/[^\x21-\x7e]+/g, "-").replace(/^-+|-+$/g, "");
48
+ if (!cleaned) return `${SCM_UTILS_APPLICATION_NAME}/${substrateSelfVersion()}`;
49
+ // Printable-ASCII only, so byte length == char length; trim to the 63-byte cap.
50
+ return cleaned.length > 63 ? cleaned.slice(0, 63) : cleaned;
51
+ }
52
+
42
53
  export function connectionApplicationName(): string {
54
+ // Precedence: a consumer's generic self-brand > Consort back-compat > scm-utils default.
55
+ // A NEW consumer just sets LAKEBASE_SCM_CLIENT="<brand>/<version>" — no scm-utils change needed.
56
+ const client = process.env[SCM_CLIENT_ENV]?.trim();
57
+ if (client) return sanitizeApplicationName(client);
43
58
  const consortVersion = process.env[CONSORT_VERSION_ENV]?.trim();
44
- return consortVersion
45
- ? `${CONSORT_APPLICATION_NAME}/${consortVersion}`
46
- : `${SCM_UTILS_APPLICATION_NAME}/${substrateSelfVersion()}`;
59
+ if (consortVersion) return `${CONSORT_APPLICATION_NAME}/${consortVersion}`;
60
+ return `${SCM_UTILS_APPLICATION_NAME}/${substrateSelfVersion()}`;
47
61
  }
48
62
  // AppKit / @databricks/lakebase re-exports a WorkspaceClient type that
49
63
  // matches what createLakebasePool expects. We accept `unknown` at the API
@@ -228,7 +228,8 @@ The same flow applies to the `--enable-e2e`-scaffolded `playwright.config.ts` +
228
228
  | `lakebase-infra-runner` | Run the `[Infra]`-tag suite (schema-diff + migration status + endpoint readiness) for a branch. Used by scaffolded `test:infra` scripts. |
229
229
  | `lakebase-update-commands` | Refresh a scaffolded project's `.claude/commands/{design,build}.md` from the kit's current templates. Interactive per-file confirm by default; `--force` skips prompts, `--dry-run` previews, `--json` emits a structured report. Hook files (`<name>.{pre,post}-hook.md`) are NEVER touched. |
230
230
  | `lakebase-feature-status` | One-screen snapshot of a TDD feature's workflow state. Pairs with `consort`. |
231
- | `lakebase-mcp-server` | Stdio MCP server exposing the full tool surface (parity with the CLI bins). For Claude Desktop / OpenAI Codex / Cursor-via-MCP / Genie Code consumers. |
231
+
232
+ > An MCP presentation of this same substrate surface ships in the `consort` package as `lakebase-mcp-server` (stdio; for Claude Desktop / OpenAI Codex / Cursor-via-MCP / Genie Code consumers). It is not an scm-utils bin.
232
233
 
233
234
  ## JS/TS exports
234
235
 
@@ -14,7 +14,9 @@
14
14
  "dotenv": "^16.4.0",
15
15
  "express": "^4.21.0",
16
16
  "knex": "^3.1.0",
17
- "pg": "^8.13.0"
17
+ "pg": "^8.13.0",
18
+ "swagger-jsdoc": "^6.2.8",
19
+ "swagger-ui-express": "^5.0.1"
18
20
  },
19
21
  "devDependencies": {
20
22
  "jest": "^29.7.0",
@@ -1,11 +1,19 @@
1
1
  require('dotenv').config();
2
2
  const express = require('express');
3
+ const swaggerUi = require('swagger-ui-express');
4
+ const openapiSpec = require('./openapi');
3
5
  const healthRoutes = require('./routes/health');
4
6
 
5
7
  const app = express();
6
8
  app.use(express.json());
7
9
  app.use('/', healthRoutes);
8
10
 
11
+ // Swagger / OpenAPI UI for acceptance review (parity with FastAPI's /docs): the interactive UI at
12
+ // /docs and the raw spec at /openapi.json, both derived from the route @openapi annotations. For an
13
+ // API-only story, the acceptance gate points the reviewer here to exercise the endpoints.
14
+ app.use('/docs', swaggerUi.serve, swaggerUi.setup(openapiSpec));
15
+ app.get('/openapi.json', (req, res) => res.json(openapiSpec));
16
+
9
17
  const PORT = process.env.PORT || 3000;
10
18
 
11
19
  if (require.main === module) {
@@ -0,0 +1,20 @@
1
+ const path = require('path');
2
+ const swaggerJsdoc = require('swagger-jsdoc');
3
+
4
+ // The OpenAPI spec is built from the `@openapi` JSDoc blocks on the route files, so the Swagger UI
5
+ // at /docs reflects the real endpoints as they are added — the Express analogue of FastAPI's
6
+ // automatic /docs. Annotate every route you add with an `@openapi` block (see src/routes/health.js
7
+ // for the pattern); it then appears in /docs and /openapi.json with no extra wiring.
8
+ const spec = swaggerJsdoc({
9
+ definition: {
10
+ openapi: '3.0.3',
11
+ info: {
12
+ title: '{{PROJECT_NAME}}',
13
+ version: '1.0.0',
14
+ description: 'API surface for acceptance review (Swagger UI at /docs).',
15
+ },
16
+ },
17
+ apis: [path.join(__dirname, 'routes', '*.js')],
18
+ });
19
+
20
+ module.exports = spec;
@@ -1,6 +1,24 @@
1
1
  const express = require('express');
2
2
  const router = express.Router();
3
3
 
4
+ /**
5
+ * @openapi
6
+ * /health:
7
+ * get:
8
+ * summary: Liveness probe
9
+ * description: Returns ok when the service is up. Pattern for annotating routes so they appear in /docs.
10
+ * responses:
11
+ * 200:
12
+ * description: Service is up
13
+ * content:
14
+ * application/json:
15
+ * schema:
16
+ * type: object
17
+ * properties:
18
+ * status:
19
+ * type: string
20
+ * example: ok
21
+ */
4
22
  router.get('/health', (req, res) => {
5
23
  res.json({ status: 'ok' });
6
24
  });
@@ -8,3 +8,19 @@ describe('Health check', () => {
8
8
  expect(res.body.status).toBe('ok');
9
9
  });
10
10
  });
11
+
12
+ describe('API docs (Swagger UI for acceptance review)', () => {
13
+ test('GET /openapi.json exposes the OpenAPI spec, including annotated routes', async () => {
14
+ const res = await request(app).get('/openapi.json');
15
+ expect(res.statusCode).toBe(200);
16
+ expect(res.body.openapi).toBeDefined();
17
+ // The @openapi annotation on the health route is picked up by swagger-jsdoc.
18
+ expect(res.body.paths['/health']).toBeDefined();
19
+ });
20
+
21
+ test('GET /docs/ serves the Swagger UI', async () => {
22
+ const res = await request(app).get('/docs/');
23
+ expect(res.statusCode).toBe(200);
24
+ expect(res.text).toMatch(/swagger-ui/i);
25
+ });
26
+ });