Skip to content

feat: add TypeScript TOML config loader and consolidate types#3655

Closed
christierney wants to merge 3 commits intomainfrom
chris/type-consolidation
Closed

feat: add TypeScript TOML config loader and consolidate types#3655
christierney wants to merge 3 commits intomainfrom
chris/type-consolidation

Conversation

@christierney
Copy link
Collaborator

@christierney christierney commented Mar 5, 2026

Intent

Add a TypeScript-native TOML configuration loader that matches Go's config.FromFile behavior, as a building block for migrating away from the Go backend.

Fixes #3651
Fixes #3652

Type of Change

    • Bug Fix
    • New Feature
    • Breaking Change
    • Documentation
    • Refactor
    • Tooling

Approach

  • Add smol-toml, ajv, ajv-formats dependencies for TOML parsing and JSON Schema validation
  • Create src/toml/ module: loader, key converter, error factories, and JSON schema copy
  • Consolidate TS types to match Go and schema (remove dead types/fields, add missing ones)
  • Remove dead Go types (Schedule, AccessType, ConnectAccessControl) and unreachable code in content.go
  • Fix schema: auth_type in integration_requests (was camelCase), add additionalProperties: false to integration_requests items

User Impact

Minimal. Schema now accurately reflects what the code produces. The schema is also stricter now, so in theory if somebody had hand-edited their integration requests TOML and introduced errors, they will get better error messaging.

Automated Tests

New tests for new code. I used the existing Go config loading tests as a guide for coverage.

Directions for Reviewers

The type cleanup is hopefully fairly easy to follow. Unused stuff that got deleted should be easy to prove as unused since little to no code referenced it. It's a little hard to read the JSON schema manually and see that the TS types now align more closely with it, but the code for parsing and validating TOML helps prove that.

Nothing is calling the TS toml code yet (other than tests) but I tried to design it to be a clean building block for replacing the APIs, and there are some "downstream compatibility" tests to help demo that.

A note on the schema change: this could be considered breaking, since I'm renaming an existing field, but I think it's ok for a couple reasons:

  • the extension code actually uses the snake_case field name, not the camelCase the schema referenced. So nobody would have the camelCase version unless they wrote it by hand. This change brings the schema in line with reality.
  • the integration requests type was not doing strict field checking prior to this change, so we could argue that the type was not fully locked down until now

The schema now lives in two places (under the Go code and under TS). I think this is acceptable for now as we're in flux. We should clean this up as we get rid of the Go side.

Checklist

  • I have updated the root CHANGELOG.md to cover notable changes.

Mentioned the schema change since that is potentially user-visible. The rest is all internal changes.

@christierney christierney requested a review from a team as a code owner March 5, 2026 19:22
export type ConfigurationLocation = {
configurationName: string;
configurationPath: string;
configurationRelPath: string;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nobody was using this. We can always add it back if we want it but I think it's confusing

@@ -0,0 +1,253 @@
// Copyright (C) 2026 by Posit Software, PBC.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is based on a similar test on the Go side---it's basically checking that we have defined our schema correctly. (It's probably not comprehensive).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we make a follow-up ticket to try to make this more comprehensive? These seem like good tests.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe? I'm not sure about the approach which feels a little haphazard. But it is nice to prove the schema does what we think.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"target": "ES2023",
"outDir": "out",
"lib": ["ES2023", "DOM"],
"resolveJsonModule": true,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

required for loading the JSON schema file

Description: cfg.Description,
}
if cfg.Connect != nil {
if cfg.Connect.AccessControl != nil {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

due to validation, it was impossible for this to ever be not nil

});

it("passes through already-camelCase keys unchanged", () => {
const result = convertKeysToCamelCase({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this test actually validate camelCase keys?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's validating that keys which are already camelCase (authType, loadFactor, defaultImageName) get passed through unchanged

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohhh - yes, ok. Keys, not values. sorry, disregard

});

it("preserves environment keys (user-defined)", () => {
const result = convertKeysToCamelCase({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this actually test that we aren't camelCasing things? Should we include some snake_casing in this test to make the fact that things aren't changing more clear?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MY_API_KEY and DATABASE_URL are there, or are you thinking there should be lower_case fields?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got mixed up on keys vs values, disregard!

@christierney
Copy link
Collaborator Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

expect(isConfigurationError(result)).toBe(false);
const cfg = result as Configuration;

// validate defaults to true (matches Go New())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these code comments are helpful for now - eventually, we will want to probably want to make a sweep-through and delete the go references once the go implementation is gone.

// Copyright (C) 2026 by Posit Software, PBC.

import { describe, expect, it } from "vitest";
import Ajv2020 from "ajv/dist/2020";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it correct that we are pulling something that seems to be versioned for 2020?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's the version of JSON-schema we use:

"$schema": "https://json-schema.org/draft/2020-12/schema",

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also the most current version

@zackverham
Copy link
Collaborator

this all makes sense to me - looks good.

I don't know why that arm build step is failing - its failing everywhere, currently investigating.

Copy link
Collaborator

@dotNomad dotNomad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for that change 🎉

christierney and others added 3 commits March 5, 2026 16:33
Add a TypeScript-native TOML configuration loader that matches Go's
config.FromFile behavior, as a building block for migrating away from
the Go backend.

- Add smol-toml, ajv, ajv-formats dependencies for TOML parsing and
  JSON Schema validation
- Create src/toml/ module: loader, key converter, error factories,
  and JSON schema copy
- Consolidate TS types to match Go and schema (remove dead types/fields,
  add missing ones)
- Remove dead Go types (Schedule, AccessType, ConnectAccessControl) and
  unreachable code in content.go
- Fix schema: auth_type in integration_requests (was camelCase),
  add additionalProperties: false to integration_requests items

Fixes #3651
Fixes #3652

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jordan Jensen <jordan.jensen@posit.co>
@christierney christierney force-pushed the chris/type-consolidation branch from e35e6a3 to 250556d Compare March 5, 2026 21:33
@christierney
Copy link
Collaborator Author

#3662 includes these changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

load and validate config files consolidate types

3 participants