From 865145b552165755f9f33c06974db45dbf28e75b Mon Sep 17 00:00:00 2001 From: Evgenii Kniazev Date: Fri, 17 Apr 2026 17:12:56 +0100 Subject: [PATCH] feat(contracts): introduce proto contracts tree and wire.v1 envelope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `contracts/` at the repo root as the source of truth for the cross-component interface shapes described in the design doc. This PR ships the first slice (`appkit/v1/wire.proto`) and the build wiring needed for subsequent contracts to land without further monorepo changes. What's included - `contracts/buf.yaml` + `contracts/buf.gen.yaml` — buf module config and codegen pipeline using @bufbuild/protoc-gen-es (local, no remote plugin resolution). - `contracts/appkit/v1/wire.proto` — SseEnvelope, SseError, ResultFormat enum. Covers the SSE envelope, structured error frames, and SQL warehouse result-format negotiation. Route conventions, heartbeat/reconnect, and the `window.__appkit__` client-config payload are deferred to follow-up PRs. - `packages/contracts/` — new workspace package `@databricks/appkit-contracts`. Runs `buf generate` via `tools/generate-contracts.ts` and re-exports the typed bindings. Built with tsdown, follows existing `packages/shared/` conventions. - `packages/appkit/src/stream/types.ts` — imports the generated `SseEnvelope` and adds a compile-time compatibility anchor against the existing `BufferedEvent` shape. Non-breaking; `BufferedEvent` will retire in favour of the generated type in a follow-up. - Root `package.json` — `contracts:generate` and `contracts:lint` scripts. - `docs/docs/contracts.md` — short intro page linking back to the design doc and outlining the four planned follow-up contracts. Follow-ups tracked by the design doc - `appkit/v1/query.proto` — typed SQL query schemas (replaces the TS-only `QueryRegistry` augmentation). - `appkit/v1/plugin.proto` — plugin manifest (replaces the JSON Schema in `packages/shared/src/schemas/plugin-manifest.schema.json`). - `agenteval/v1/*.proto` — versioned eval framework to app protocol. - `appkit/v1/deploy.proto` — app manifest consumed by `databricks apps deploy`. Verification - `pnpm contracts:lint` — clean. - `pnpm contracts:generate` — produces `packages/contracts/src/generated/appkit/v1/wire_pb.ts`. - `pnpm -r typecheck` — all 8 workspace projects pass. - `pnpm build` — full monorepo build succeeds, `@databricks/appkit-contracts` emits dist/ via tsdown, publint clean. - `pnpm test` — 1564 tests pass (no new or changed tests in this PR). This PR and its description are AI-assisted by Isaac. Signed-off-by: Evgenii Kniazev --- contracts/README.md | 37 ++++ contracts/appkit/v1/wire.proto | 59 ++++++ contracts/buf.gen.yaml | 8 + contracts/buf.yaml | 10 + docs/docs/contracts.md | 54 +++++ knip.json | 1 + packages/appkit/package.json | 1 + packages/appkit/src/stream/types.ts | 10 + packages/appkit/tsconfig.json | 3 +- packages/contracts/package.json | 36 ++++ .../src/generated/appkit/v1/wire_pb.ts | 191 ++++++++++++++++++ packages/contracts/src/index.ts | 4 + packages/contracts/tsconfig.json | 12 ++ packages/contracts/tsdown.config.ts | 22 ++ pnpm-lock.yaml | 143 ++++++++++++- tools/generate-contracts.ts | 21 ++ tsconfig.json | 1 + 17 files changed, 611 insertions(+), 2 deletions(-) create mode 100644 contracts/README.md create mode 100644 contracts/appkit/v1/wire.proto create mode 100644 contracts/buf.gen.yaml create mode 100644 contracts/buf.yaml create mode 100644 docs/docs/contracts.md create mode 100644 packages/contracts/package.json create mode 100644 packages/contracts/src/generated/appkit/v1/wire_pb.ts create mode 100644 packages/contracts/src/index.ts create mode 100644 packages/contracts/tsconfig.json create mode 100644 packages/contracts/tsdown.config.ts create mode 100644 tools/generate-contracts.ts diff --git a/contracts/README.md b/contracts/README.md new file mode 100644 index 00000000..1c93a275 --- /dev/null +++ b/contracts/README.md @@ -0,0 +1,37 @@ +# AppKit Data Contracts + +Proto definitions that are the single source of truth for the interfaces +between AppKit components: TS/Python/Rust backends, the React SDK, the +`databricks` CLI, the agent-eval framework, and scaffolding tooling. + +See the design doc (linked from `docs/docs/contracts.md`) for the full +five-contract plan. This directory ships the first slice of that plan — +`appkit/v1/wire.proto` — as an intro. + +## Layout + +``` +contracts/ + buf.yaml # buf module + lint/breaking rules + buf.gen.yaml # codegen config (TS via @bufbuild/protoc-gen-es) + appkit/v1/ + wire.proto # HTTP + SSE envelope, error frames, result-format enum +``` + +## Regenerating TS bindings + +```bash +pnpm --filter=@databricks/appkit-contracts generate +``` + +Generated output lands in `packages/contracts/src/generated/` and is re-exported +from `@databricks/appkit-contracts`. + +## Follow-ups + +Planned additions, tracked against the design doc: + +- `appkit/v1/query.proto` — typed SQL query schemas (DESCRIBE QUERY -> bindings). +- `appkit/v1/plugin.proto` — plugin manifest, replacing the JSON Schema in `packages/shared/src/schemas/plugin-manifest.schema.json`. +- `agenteval/v1/*.proto` — eval runs, scorers, traces, streaming envelope. +- `appkit/v1/deploy.proto` — app manifest consumed by `databricks apps deploy`. diff --git a/contracts/appkit/v1/wire.proto b/contracts/appkit/v1/wire.proto new file mode 100644 index 00000000..6564edfa --- /dev/null +++ b/contracts/appkit/v1/wire.proto @@ -0,0 +1,59 @@ +// Wire-protocol contract for AppKit (draft, v1). +// +// This proto defines the HTTP + SSE surface every AppKit backend must serve. +// It is the single source of truth for the TS, Python, and Rust ports, +// and for the React SDK that consumes the stream. +// +// Scope of this initial draft is intentionally small: envelope shape, +// structured error frames, and SQL warehouse result-format negotiation. +// Route conventions, heartbeat/reconnect semantics, and the client-config +// payload will land in follow-up PRs. +syntax = "proto3"; + +package appkit.v1; + +// Envelope for a single Server-Sent Event frame emitted by an AppKit backend +// and parsed by the React SDK via connectSSE(). Structurally compatible with +// the current BufferedEvent type in packages/appkit/src/stream/types.ts. +message SseEnvelope { + // Monotonically increasing stream event identifier. Clients echo the most + // recent id back via the Last-Event-ID header to resume a stream. + string id = 1; + + // Event type. Opaque to the envelope; interpreted per-plugin. + string event = 2; + + // UTF-8 payload. Binary content should be base64-encoded by the emitter. + string data = 3; + + // Emission timestamp in milliseconds since epoch (wall clock on the emitter). + int64 timestamp_ms = 4; +} + +// Structured error frame. Emitted over the same SSE transport as SseEnvelope +// but distinguished by event="error". +message SseError { + SseErrorCode code = 1; + string message = 2; +} + +enum SseErrorCode { + SSE_ERROR_CODE_UNSPECIFIED = 0; + SSE_ERROR_CODE_TEMPORARY_UNAVAILABLE = 1; + SSE_ERROR_CODE_TIMEOUT = 2; + SSE_ERROR_CODE_INTERNAL_ERROR = 3; + SSE_ERROR_CODE_INVALID_REQUEST = 4; + SSE_ERROR_CODE_STREAM_ABORTED = 5; + SSE_ERROR_CODE_STREAM_EVICTED = 6; + SSE_ERROR_CODE_UPSTREAM_ERROR = 7; +} + +// SQL warehouse result-format negotiation. Backends attempt formats in the +// order specified by their fallback chain — the canonical TS chain today is +// ARROW_STREAM -> JSON -> ARROW. +enum ResultFormat { + RESULT_FORMAT_UNSPECIFIED = 0; + RESULT_FORMAT_ARROW_STREAM = 1; + RESULT_FORMAT_JSON = 2; + RESULT_FORMAT_ARROW = 3; +} diff --git a/contracts/buf.gen.yaml b/contracts/buf.gen.yaml new file mode 100644 index 00000000..efb7b64a --- /dev/null +++ b/contracts/buf.gen.yaml @@ -0,0 +1,8 @@ +version: v2 +clean: true +plugins: + - local: ../node_modules/.bin/protoc-gen-es + out: ../packages/contracts/src/generated + opt: + - target=ts + - import_extension=js diff --git a/contracts/buf.yaml b/contracts/buf.yaml new file mode 100644 index 00000000..9cc41a4c --- /dev/null +++ b/contracts/buf.yaml @@ -0,0 +1,10 @@ +version: v2 +modules: + - path: . + name: buf.build/databricks/appkit +lint: + use: + - STANDARD +breaking: + use: + - FILE diff --git a/docs/docs/contracts.md b/docs/docs/contracts.md new file mode 100644 index 00000000..e72da781 --- /dev/null +++ b/docs/docs/contracts.md @@ -0,0 +1,54 @@ +--- +title: Data Contracts +sidebar_position: 9 +--- + +# Data Contracts + +AppKit exposes several interfaces that today are kept in sync by convention: +the HTTP + SSE surface between backend and React SDK, the typed query pipeline +(`DESCRIBE QUERY` → `QueryRegistry`), the plugin manifest schema, and the app +contract the `databricks` CLI consumes at deploy time. As AppKit grows second +and third backend implementations (Python, Rust) the cost of keeping those +conventions in sync grows with the language count. + +The `contracts/` directory at the repo root holds the proto definitions that +will become the single source of truth for all of these interfaces. Each +language binding is regenerated from the same protos; consumers import what +they need. + +## Current scope + +This intro PR ships the first slice: + +- **`appkit/v1/wire.proto`** — the HTTP + SSE envelope. Defines `SseEnvelope`, + `SseError`, and `ResultFormat` (warehouse result-format negotiation). + Consumed today by `packages/appkit/src/stream/types.ts` as a type-level + compatibility anchor; follow-up PRs will retire the hand-written + `BufferedEvent` in favor of the generated type. + +## Regenerating + +```bash +pnpm contracts:lint # buf lint over contracts/ +pnpm contracts:generate # regenerate TS bindings into packages/contracts/src/generated/ +``` + +Generated output lives under `packages/contracts/src/generated/` and is +re-exported from `@databricks/appkit-contracts`. + +## Planned follow-ups + +Per the design doc (see [Enforcing Data Contracts in +AppKit](https://docs.google.com/document/d/1yWWt7sLVpmuDhYs-bIWFEE9hiI6MlxjO6YS4AuN4v6k/edit)), +four more contracts will land in subsequent PRs: + +- `appkit/v1/query.proto` — typed SQL query schemas (`DESCRIBE QUERY` → + bindings in every language, replacing today's TS-only + `QueryRegistry` augmentation). +- `appkit/v1/plugin.proto` — plugin manifest, replacing + `packages/shared/src/schemas/plugin-manifest.schema.json`. +- `agenteval/v1/*.proto` — versioned eval framework ↔ app protocol. +- `appkit/v1/deploy.proto` — app manifest consumed by + `databricks apps deploy` (runtime, entrypoint, build steps, static-asset + layout, health route, required env). diff --git a/knip.json b/knip.json index b777d8c2..209d489d 100644 --- a/knip.json +++ b/knip.json @@ -3,6 +3,7 @@ "ignoreWorkspaces": [ "packages/shared", "packages/lakebase", + "packages/contracts", "apps/**", "docs" ], diff --git a/packages/appkit/package.json b/packages/appkit/package.json index c658a9e3..086fee59 100644 --- a/packages/appkit/package.json +++ b/packages/appkit/package.json @@ -51,6 +51,7 @@ }, "dependencies": { "@ast-grep/napi": "0.37.0", + "@databricks/appkit-contracts": "workspace:*", "@databricks/lakebase": "workspace:*", "@databricks/sdk-experimental": "0.16.0", "@opentelemetry/api": "1.9.0", diff --git a/packages/appkit/src/stream/types.ts b/packages/appkit/src/stream/types.ts index 3841bfd1..5734b771 100644 --- a/packages/appkit/src/stream/types.ts +++ b/packages/appkit/src/stream/types.ts @@ -1,3 +1,4 @@ +import type { SseEnvelope } from "@databricks/appkit-contracts"; import type { Context } from "@opentelemetry/api"; import type { IAppResponse } from "shared"; import type { EventRingBuffer } from "./buffers"; @@ -33,6 +34,15 @@ export interface BufferedEvent { timestamp: number; } +// Compile-time anchor against contracts/appkit/v1/wire.proto. When BufferedEvent +// and the generated SseEnvelope diverge, tsc fails here — a signal that either +// the contract or the implementation needs updating. Follow-up PRs will retire +// BufferedEvent in favour of the generated type. +type _BufferedEventSseEnvelopeCompat = { + id: BufferedEvent["id"] extends SseEnvelope["id"] ? true : never; + data: BufferedEvent["data"] extends SseEnvelope["data"] ? true : never; +}; + export interface StreamEntry { streamId: string; generator: AsyncGenerator; diff --git a/packages/appkit/tsconfig.json b/packages/appkit/tsconfig.json index 5265a688..58991bf1 100644 --- a/packages/appkit/tsconfig.json +++ b/packages/appkit/tsconfig.json @@ -7,7 +7,8 @@ "@/*": ["src/*"], "@tools/*": ["../../tools/*"], "shared": ["../../packages/shared/src"], - "@databricks/lakebase": ["../../packages/lakebase/src"] + "@databricks/lakebase": ["../../packages/lakebase/src"], + "@databricks/appkit-contracts": ["../../packages/contracts/src"] } }, "include": ["src/**/*"], diff --git a/packages/contracts/package.json b/packages/contracts/package.json new file mode 100644 index 00000000..8142e393 --- /dev/null +++ b/packages/contracts/package.json @@ -0,0 +1,36 @@ +{ + "name": "@databricks/appkit-contracts", + "type": "module", + "version": "0.0.1", + "private": true, + "description": "Shared proto data contracts for AppKit (wire, query, plugin, agenteval, deploy). Single source of truth for cross-language interface shapes.", + "exports": { + ".": { + "development": "./src/index.ts", + "default": "./dist/index.js" + }, + "./package.json": "./package.json" + }, + "scripts": { + "generate": "tsx ../../tools/generate-contracts.ts", + "build:package": "pnpm run generate && tsdown --config tsdown.config.ts", + "build:watch": "tsdown --config tsdown.config.ts --watch", + "typecheck": "tsc --noEmit", + "clean": "rm -rf dist", + "clean:full": "rm -rf dist node_modules src/generated" + }, + "dependencies": { + "@bufbuild/protobuf": "2.11.0" + }, + "devDependencies": { + "@bufbuild/buf": "1.47.2", + "@bufbuild/protoc-gen-es": "2.11.0" + }, + "types": "./dist/index.d.ts", + "publishConfig": { + "exports": { + ".": "./dist/index.js", + "./package.json": "./package.json" + } + } +} diff --git a/packages/contracts/src/generated/appkit/v1/wire_pb.ts b/packages/contracts/src/generated/appkit/v1/wire_pb.ts new file mode 100644 index 00000000..f6d3b67b --- /dev/null +++ b/packages/contracts/src/generated/appkit/v1/wire_pb.ts @@ -0,0 +1,191 @@ +// Wire-protocol contract for AppKit (draft, v1). +// +// This proto defines the HTTP + SSE surface every AppKit backend must serve. +// It is the single source of truth for the TS, Python, and Rust ports, +// and for the React SDK that consumes the stream. +// +// Scope of this initial draft is intentionally small: envelope shape, +// structured error frames, and SQL warehouse result-format negotiation. +// Route conventions, heartbeat/reconnect semantics, and the client-config +// payload will land in follow-up PRs. + +// @generated by protoc-gen-es v2.11.0 with parameter "target=ts,import_extension=js" +// @generated from file appkit/v1/wire.proto (package appkit.v1, syntax proto3) +/* eslint-disable */ + +import type { Message } from "@bufbuild/protobuf"; +import type { + GenEnum, + GenFile, + GenMessage, +} from "@bufbuild/protobuf/codegenv2"; +import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2"; + +/** + * Describes the file appkit/v1/wire.proto. + */ +export const file_appkit_v1_wire: GenFile = + /*@__PURE__*/ + fileDesc( + "ChRhcHBraXQvdjEvd2lyZS5wcm90bxIJYXBwa2l0LnYxIkwKC1NzZUVudmVsb3BlEgoKAmlkGAEgASgJEg0KBWV2ZW50GAIgASgJEgwKBGRhdGEYAyABKAkSFAoMdGltZXN0YW1wX21zGAQgASgDIkIKCFNzZUVycm9yEiUKBGNvZGUYASABKA4yFy5hcHBraXQudjEuU3NlRXJyb3JDb2RlEg8KB21lc3NhZ2UYAiABKAkqpAIKDFNzZUVycm9yQ29kZRIeChpTU0VfRVJST1JfQ09ERV9VTlNQRUNJRklFRBAAEigKJFNTRV9FUlJPUl9DT0RFX1RFTVBPUkFSWV9VTkFWQUlMQUJMRRABEhoKFlNTRV9FUlJPUl9DT0RFX1RJTUVPVVQQAhIhCh1TU0VfRVJST1JfQ09ERV9JTlRFUk5BTF9FUlJPUhADEiIKHlNTRV9FUlJPUl9DT0RFX0lOVkFMSURfUkVRVUVTVBAEEiEKHVNTRV9FUlJPUl9DT0RFX1NUUkVBTV9BQk9SVEVEEAUSIQodU1NFX0VSUk9SX0NPREVfU1RSRUFNX0VWSUNURUQQBhIhCh1TU0VfRVJST1JfQ09ERV9VUFNUUkVBTV9FUlJPUhAHKn4KDFJlc3VsdEZvcm1hdBIdChlSRVNVTFRfRk9STUFUX1VOU1BFQ0lGSUVEEAASHgoaUkVTVUxUX0ZPUk1BVF9BUlJPV19TVFJFQU0QARIWChJSRVNVTFRfRk9STUFUX0pTT04QAhIXChNSRVNVTFRfRk9STUFUX0FSUk9XEANiBnByb3RvMw", + ); + +/** + * Envelope for a single Server-Sent Event frame emitted by an AppKit backend + * and parsed by the React SDK via connectSSE(). Structurally compatible with + * the current BufferedEvent type in packages/appkit/src/stream/types.ts. + * + * @generated from message appkit.v1.SseEnvelope + */ +export type SseEnvelope = Message<"appkit.v1.SseEnvelope"> & { + /** + * Monotonically increasing stream event identifier. Clients echo the most + * recent id back via the Last-Event-ID header to resume a stream. + * + * @generated from field: string id = 1; + */ + id: string; + + /** + * Event type. Opaque to the envelope; interpreted per-plugin. + * + * @generated from field: string event = 2; + */ + event: string; + + /** + * UTF-8 payload. Binary content should be base64-encoded by the emitter. + * + * @generated from field: string data = 3; + */ + data: string; + + /** + * Emission timestamp in milliseconds since epoch (wall clock on the emitter). + * + * @generated from field: int64 timestamp_ms = 4; + */ + timestampMs: bigint; +}; + +/** + * Describes the message appkit.v1.SseEnvelope. + * Use `create(SseEnvelopeSchema)` to create a new message. + */ +export const SseEnvelopeSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_appkit_v1_wire, 0); + +/** + * Structured error frame. Emitted over the same SSE transport as SseEnvelope + * but distinguished by event="error". + * + * @generated from message appkit.v1.SseError + */ +export type SseError = Message<"appkit.v1.SseError"> & { + /** + * @generated from field: appkit.v1.SseErrorCode code = 1; + */ + code: SseErrorCode; + + /** + * @generated from field: string message = 2; + */ + message: string; +}; + +/** + * Describes the message appkit.v1.SseError. + * Use `create(SseErrorSchema)` to create a new message. + */ +export const SseErrorSchema: GenMessage = + /*@__PURE__*/ + messageDesc(file_appkit_v1_wire, 1); + +/** + * @generated from enum appkit.v1.SseErrorCode + */ +export enum SseErrorCode { + /** + * @generated from enum value: SSE_ERROR_CODE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: SSE_ERROR_CODE_TEMPORARY_UNAVAILABLE = 1; + */ + TEMPORARY_UNAVAILABLE = 1, + + /** + * @generated from enum value: SSE_ERROR_CODE_TIMEOUT = 2; + */ + TIMEOUT = 2, + + /** + * @generated from enum value: SSE_ERROR_CODE_INTERNAL_ERROR = 3; + */ + INTERNAL_ERROR = 3, + + /** + * @generated from enum value: SSE_ERROR_CODE_INVALID_REQUEST = 4; + */ + INVALID_REQUEST = 4, + + /** + * @generated from enum value: SSE_ERROR_CODE_STREAM_ABORTED = 5; + */ + STREAM_ABORTED = 5, + + /** + * @generated from enum value: SSE_ERROR_CODE_STREAM_EVICTED = 6; + */ + STREAM_EVICTED = 6, + + /** + * @generated from enum value: SSE_ERROR_CODE_UPSTREAM_ERROR = 7; + */ + UPSTREAM_ERROR = 7, +} + +/** + * Describes the enum appkit.v1.SseErrorCode. + */ +export const SseErrorCodeSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_appkit_v1_wire, 0); + +/** + * SQL warehouse result-format negotiation. Backends attempt formats in the + * order specified by their fallback chain — the canonical TS chain today is + * ARROW_STREAM -> JSON -> ARROW. + * + * @generated from enum appkit.v1.ResultFormat + */ +export enum ResultFormat { + /** + * @generated from enum value: RESULT_FORMAT_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: RESULT_FORMAT_ARROW_STREAM = 1; + */ + ARROW_STREAM = 1, + + /** + * @generated from enum value: RESULT_FORMAT_JSON = 2; + */ + JSON = 2, + + /** + * @generated from enum value: RESULT_FORMAT_ARROW = 3; + */ + ARROW = 3, +} + +/** + * Describes the enum appkit.v1.ResultFormat. + */ +export const ResultFormatSchema: GenEnum = + /*@__PURE__*/ + enumDesc(file_appkit_v1_wire, 1); diff --git a/packages/contracts/src/index.ts b/packages/contracts/src/index.ts new file mode 100644 index 00000000..248a5413 --- /dev/null +++ b/packages/contracts/src/index.ts @@ -0,0 +1,4 @@ +// Re-exports generated bindings for the AppKit proto contracts. +// Source protos live at ../../contracts/ and are regenerated via +// `pnpm --filter=@databricks/appkit-contracts generate`. +export * from "./generated/appkit/v1/wire_pb.js"; diff --git a/packages/contracts/tsconfig.json b/packages/contracts/tsconfig.json new file mode 100644 index 00000000..4a6e68b3 --- /dev/null +++ b/packages/contracts/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/contracts/tsdown.config.ts b/packages/contracts/tsdown.config.ts new file mode 100644 index 00000000..1b081ce7 --- /dev/null +++ b/packages/contracts/tsdown.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + name: "contracts", + entry: ["src/index.ts"], + outDir: "dist", + format: "esm", + platform: "neutral", + dts: true, + clean: false, + hash: false, + unbundle: true, + skipNodeModulesBundle: true, + external: [/^@bufbuild\//], + tsconfig: "./tsconfig.json", + outExtensions: () => ({ + js: ".js", + }), + exports: { + devExports: "development", + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ca11b81..c3084c44 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -245,6 +245,9 @@ importers: '@ast-grep/napi': specifier: 0.37.0 version: 0.37.0 + '@databricks/appkit-contracts': + specifier: workspace:* + version: link:../contracts '@databricks/lakebase': specifier: workspace:* version: link:../lakebase @@ -506,6 +509,19 @@ importers: specifier: 1.4.0 version: 1.4.0 + packages/contracts: + dependencies: + '@bufbuild/protobuf': + specifier: 2.11.0 + version: 2.11.0 + devDependencies: + '@bufbuild/buf': + specifier: 1.47.2 + version: 1.47.2 + '@bufbuild/protoc-gen-es': + specifier: 2.11.0 + version: 2.11.0(@bufbuild/protobuf@2.11.0) + packages/lakebase: dependencies: '@databricks/sdk-experimental': @@ -1458,9 +1474,69 @@ packages: '@braintree/sanitize-url@7.1.1': resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} + '@bufbuild/buf-darwin-arm64@1.47.2': + resolution: {integrity: sha512-74WerFn06y+azgVfsnzhfbI5wla/OLPDnIvaNJBWHaqya/3bfascJkDylW2GVNHmwG1K/cscpmcc/RJPaO7ntQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@bufbuild/buf-darwin-x64@1.47.2': + resolution: {integrity: sha512-adAiOacOQe8Ym/YXPCEiq9mrPeKRmDtF2TgqPWTcDy6mF7TqR7hMJINkEEuMd1EeACmXnzMOnXlm9ICtvdYgPg==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@bufbuild/buf-linux-aarch64@1.47.2': + resolution: {integrity: sha512-52vY+Owffr5diw2PyfQJqH+Fld6zW6NhNZak4zojvc2MjZKubWM0TfNyM9jXz2YrwyB+cyxkabE60nBI80m37w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@bufbuild/buf-linux-armv7@1.47.2': + resolution: {integrity: sha512-g9KtpObDeHZ/VG/0b5ZCieOao7L/WYZ0fPqFSs4N07D3APgEDhJG6vLyUcDgJMDgyLcgkNjNz0+XdYQb/tXyQw==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@bufbuild/buf-linux-x64@1.47.2': + resolution: {integrity: sha512-MODCK2BzD1Mgoyr+5Sp8xA8qMNdytj8hYheyhA5NnCGTkQf8sfqAjpBSAAmKk6Zar8HOlVXML6tzE/ioDFFGwQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@bufbuild/buf-win32-arm64@1.47.2': + resolution: {integrity: sha512-563YKYWJl3LrCY3G3+zuhb8HwOs6DzWslwGPFkKV2hwHyWyvd1DR1JjiLvw9zX64IKNctQ0HempSqc3kcboaqQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@bufbuild/buf-win32-x64@1.47.2': + resolution: {integrity: sha512-Sqcdv7La2xBDh3bTdEYb2f4UTMMqCcYe/D0RELhvQ5wDn6I35V3/2YT1OF5fRuf0BZLCo0OdO37S9L47uHSz2g==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@bufbuild/buf@1.47.2': + resolution: {integrity: sha512-glY5kCAoO4+a7HvDb+BLOdoHSdCk4mdXdkp53H8JFz7maOnkxCiHHXgRX+taFyEu25N8ybn7NjZFrZSdRwq2sA==} + engines: {node: '>=12'} + hasBin: true + '@bufbuild/protobuf@2.11.0': resolution: {integrity: sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==} + '@bufbuild/protoc-gen-es@2.11.0': + resolution: {integrity: sha512-VzQuwEQDXipbZ1soWUuAWm1Z0C3B/IDWGeysnbX6ogJ6As91C2mdvAND/ekQ4YIWgen4d5nqLfIBOWLqCCjYUA==} + engines: {node: '>=20'} + hasBin: true + peerDependencies: + '@bufbuild/protobuf': 2.11.0 + peerDependenciesMeta: + '@bufbuild/protobuf': + optional: true + + '@bufbuild/protoplugin@2.11.0': + resolution: {integrity: sha512-lyZVNFUHArIOt4W0+dwYBe5GBwbKzbOy8ObaloEqsw9Mmiwv2O48TwddDoHN4itylC+BaEGqFdI1W8WQt2vWJQ==} + '@cdxgen/cdxgen-plugins-bin-darwin-amd64@2.0.2': resolution: {integrity: sha512-IfkU8hpVRA2Yf4MQ6tYgI8AlAYCasT/9T3UqggYe24aH55dNXc2x3vcIxrhBTIKv8rSidUrh4pttx8t2ke0pcQ==} cpu: [x64] @@ -5159,6 +5235,11 @@ packages: resolution: {integrity: sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript/vfs@1.6.4': + resolution: {integrity: sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==} + peerDependencies: + typescript: '*' + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} @@ -11251,6 +11332,11 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true + typescript@5.6.3: resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} @@ -13042,9 +13128,55 @@ snapshots: '@braintree/sanitize-url@7.1.1': {} - '@bufbuild/protobuf@2.11.0': + '@bufbuild/buf-darwin-arm64@1.47.2': + optional: true + + '@bufbuild/buf-darwin-x64@1.47.2': + optional: true + + '@bufbuild/buf-linux-aarch64@1.47.2': + optional: true + + '@bufbuild/buf-linux-armv7@1.47.2': + optional: true + + '@bufbuild/buf-linux-x64@1.47.2': + optional: true + + '@bufbuild/buf-win32-arm64@1.47.2': + optional: true + + '@bufbuild/buf-win32-x64@1.47.2': optional: true + '@bufbuild/buf@1.47.2': + optionalDependencies: + '@bufbuild/buf-darwin-arm64': 1.47.2 + '@bufbuild/buf-darwin-x64': 1.47.2 + '@bufbuild/buf-linux-aarch64': 1.47.2 + '@bufbuild/buf-linux-armv7': 1.47.2 + '@bufbuild/buf-linux-x64': 1.47.2 + '@bufbuild/buf-win32-arm64': 1.47.2 + '@bufbuild/buf-win32-x64': 1.47.2 + + '@bufbuild/protobuf@2.11.0': {} + + '@bufbuild/protoc-gen-es@2.11.0(@bufbuild/protobuf@2.11.0)': + dependencies: + '@bufbuild/protoplugin': 2.11.0 + optionalDependencies: + '@bufbuild/protobuf': 2.11.0 + transitivePeerDependencies: + - supports-color + + '@bufbuild/protoplugin@2.11.0': + dependencies: + '@bufbuild/protobuf': 2.11.0 + '@typescript/vfs': 1.6.4(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + '@cdxgen/cdxgen-plugins-bin-darwin-amd64@2.0.2': optional: true @@ -17551,6 +17683,13 @@ snapshots: '@typescript-eslint/types': 8.49.0 eslint-visitor-keys: 4.2.1 + '@typescript/vfs@1.6.4(typescript@5.4.5)': + dependencies: + debug: 4.4.3 + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + '@ungap/structured-clone@1.3.0': {} '@vercel/oidc@3.0.5': {} @@ -24550,6 +24689,8 @@ snapshots: transitivePeerDependencies: - supports-color + typescript@5.4.5: {} + typescript@5.6.3: {} typescript@5.9.3: {} diff --git a/tools/generate-contracts.ts b/tools/generate-contracts.ts new file mode 100644 index 00000000..495a9564 --- /dev/null +++ b/tools/generate-contracts.ts @@ -0,0 +1,21 @@ +#!/usr/bin/env tsx +// Regenerate TS bindings for the proto contracts under contracts/. +// Invoked by `pnpm --filter=@databricks/appkit-contracts generate`. + +import { spawnSync } from "node:child_process"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const here = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(here, ".."); +const contractsDir = resolve(repoRoot, "contracts"); +const bufBin = resolve(repoRoot, "node_modules", ".bin", "buf"); + +const result = spawnSync(bufBin, ["generate"], { + cwd: contractsDir, + stdio: "inherit", +}); + +if (result.status !== 0) { + process.exit(result.status ?? 1); +} diff --git a/tsconfig.json b/tsconfig.json index 1da2d8e9..6b2c458e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,6 +15,7 @@ "paths": { "@databricks/appkit": ["packages/appkit/*"], "@databricks/appkit-ui": ["packages/appkit-ui/*"], + "@databricks/appkit-contracts": ["packages/contracts/src"], "shared": ["packages/shared/src"], "@tools/*": ["tools/*"] }