From cc6d3b901acc8e592c572190fd5b4d761cc3ca15 Mon Sep 17 00:00:00 2001 From: Rob Colbert Date: Tue, 28 Apr 2026 12:42:32 -0400 Subject: [PATCH] refactor gadget-code model interfaces to @gadget/api Moved all Mongoose model interfaces to @gadget/api to commonize the data structures being passed around the system as JSON objects via HTTP and Socket.IO. --- gadget-code/package.json | 1 + gadget-code/src/models/ai-provider.ts | 9 ++++- gadget-code/src/models/chat-session.ts | 1 + gadget-code/src/models/chat-turn.ts | 14 ++++--- gadget-code/src/models/csrf-token.ts | 2 +- gadget-code/src/models/drone-monitor.ts | 37 +------------------ gadget-code/src/models/drone-registration.ts | 21 +---------- gadget-code/src/models/email-verification.ts | 4 +- gadget-code/src/models/project.ts | 5 ++- gadget-code/src/models/user.ts | 3 +- gadget-code/src/models/web-token.ts | 3 +- gadget-code/src/models/web-visit.ts | 3 +- gadget-drone/package.json | 1 + packages/api/.gitignore | 1 + packages/api/package.json | 28 ++++++++++++++ packages/api/src/index.ts | 3 ++ packages/api/src/interfaces/ai-provider.ts | 2 + packages/api/src/interfaces/chat-session.ts | 6 ++- packages/api/src/interfaces/chat-turn.ts | 9 ++++- packages/api/src/interfaces/drone-monitor.ts | 35 ++++++++++++++++++ .../api/src/interfaces/drone-registration.ts | 23 ++++++++++++ packages/api/src/interfaces/project.ts | 3 ++ packages/api/src/interfaces/user.ts | 2 + packages/api/tsconfig.json | 24 ++++++++++++ pnpm-lock.yaml | 35 ++++++++++++++---- 25 files changed, 197 insertions(+), 78 deletions(-) create mode 100644 packages/api/.gitignore create mode 100644 packages/api/package.json create mode 100644 packages/api/src/interfaces/drone-monitor.ts create mode 100644 packages/api/src/interfaces/drone-registration.ts create mode 100644 packages/api/tsconfig.json diff --git a/gadget-code/package.json b/gadget-code/package.json index 081ea1e..872c005 100644 --- a/gadget-code/package.json +++ b/gadget-code/package.json @@ -23,6 +23,7 @@ "dependencies": { "@fortawesome/fontawesome-free": "^6.7.2", "@gadget/ai": "workspace:*", + "@gadget/api": "workspace:*", "ansicolor": "^2.0.3", "bull": "^4.16.5", "chart.js": "^4.5.0", diff --git a/gadget-code/src/models/ai-provider.ts b/gadget-code/src/models/ai-provider.ts index acd1313..07fe66e 100644 --- a/gadget-code/src/models/ai-provider.ts +++ b/gadget-code/src/models/ai-provider.ts @@ -2,7 +2,14 @@ // Copyright (C) 2026 Robert Colbert // All Rights Reserved -import { Schema, Document, model } from "mongoose"; +import { Schema, model } from "mongoose"; + +import { + IAiModel, + IAiModelCapabilities, + IAiModelSettings, + IAiProvider, +} from "@gadget/api"; export const AiModelCapabilitiesSchema = new Schema( { diff --git a/gadget-code/src/models/chat-session.ts b/gadget-code/src/models/chat-session.ts index dcc1bca..d2b1c0d 100644 --- a/gadget-code/src/models/chat-session.ts +++ b/gadget-code/src/models/chat-session.ts @@ -3,6 +3,7 @@ // All Rights Reserved import { Types, Schema, model } from "mongoose"; +import { ChatSessionMode, IChatSession, IChatSessionPin } from "@gadget/api"; export const ChatSessionPinSchema = new Schema({ content: { type: String, required: true }, diff --git a/gadget-code/src/models/chat-turn.ts b/gadget-code/src/models/chat-turn.ts index 8dcfd89..2072cd5 100644 --- a/gadget-code/src/models/chat-turn.ts +++ b/gadget-code/src/models/chat-turn.ts @@ -2,12 +2,16 @@ // Copyright (C) 2026 Robert Colbert // All Rights Reserved -import { Types, Schema, Document, model } from "mongoose"; +import { Types, Schema, model } from "mongoose"; -import { IUser } from "./user.js"; -import { IProject } from "./project.js"; -import { ChatSessionMode, IChatSession } from "./chat-session.js"; -import { IAiProvider } from "./ai-provider.js"; +import { + ChatSessionMode, + ChatTurnStatus, + IChatSubagentProcess, + IChatToolCall, + IChatTurn, + IChatTurnStats, +} from "@gadget/api"; export const ChatTurnStatsSchema = new Schema({ toolCallCount: { type: Number, default: 0, required: true }, diff --git a/gadget-code/src/models/csrf-token.ts b/gadget-code/src/models/csrf-token.ts index 3e771a8..0153d88 100644 --- a/gadget-code/src/models/csrf-token.ts +++ b/gadget-code/src/models/csrf-token.ts @@ -3,9 +3,9 @@ // All Rights Reserved import { Schema, Types, model } from "mongoose"; -import { IUser } from "./user.js"; import { DtpLog } from "../lib/log.js"; +import { IUser } from "@gadget/api"; const log = new DtpLog({ name: "CsrfTokenModel", slug: "csrfToken", diff --git a/gadget-code/src/models/drone-monitor.ts b/gadget-code/src/models/drone-monitor.ts index 4601e4b..18f1979 100644 --- a/gadget-code/src/models/drone-monitor.ts +++ b/gadget-code/src/models/drone-monitor.ts @@ -2,47 +2,14 @@ // Copyright (C) 2026 Robert Colbert // All Rights Reserved -import { Types, Schema, Document, model } from "mongoose"; -import { IDroneRegistration } from "./drone-registration"; +import { Types, Schema, model } from "mongoose"; +import { IDroneMonitor, IMemoryMonitor } from "@gadget/api"; -/* - * Memory Monitor interface & schema - */ -export interface IMemoryMonitor { - count: number; - bytes: number; -} export const MemoryMonitorSchema = new Schema({ count: { type: Number, default: 0, required: true }, bytes: { type: Number, default: 0, required: true }, }); -/* - * DroneMonitor interface & schema - */ -export interface IDroneMonitor extends Document { - _id: Types.ObjectId; - registration: IDroneRegistration | Types.ObjectId; - timestamp: Date; - memory: { - rss: number; - v8: { - heapTotal: number; - heapUsed: number; - heapExternal: number; - }; - os: { - total: number; - free: number; - }; - ai: { - subagents: IMemoryMonitor; - fileOperations: IMemoryMonitor; - toolCalls: IMemoryMonitor; - }; - logs: IMemoryMonitor; - }; -} export const DroneMonitorSchema = new Schema({ registration: { type: Types.ObjectId, required: true, index: 1 }, timestamp: { type: Date, required: true, index: -1 }, diff --git a/gadget-code/src/models/drone-registration.ts b/gadget-code/src/models/drone-registration.ts index 60ea221..56d4348 100644 --- a/gadget-code/src/models/drone-registration.ts +++ b/gadget-code/src/models/drone-registration.ts @@ -2,25 +2,8 @@ // Copyright (C) 2026 Robert Colbert // All Rights Reserved -import { Document, Schema, Types, model } from "mongoose"; -import { IUser } from "./user"; - -export enum DroneStatus { - Starting = "starting", - Available = "available", - Busy = "busy", - Offline = "offline", -} - -export interface IDroneRegistration extends Document { - _id: Types.ObjectId; - createdAt: Date; - updatedAt: Date; - user: IUser | Types.ObjectId; - hostname: string; - status: DroneStatus; - currentJobId?: string; -} +import { Schema, model } from "mongoose"; +import { DroneStatus, IDroneRegistration } from "@gadget/api"; export const DroneRegistrationSchema = new Schema({ createdAt: { type: Date, required: true }, diff --git a/gadget-code/src/models/email-verification.ts b/gadget-code/src/models/email-verification.ts index 40c0a4d..044c674 100644 --- a/gadget-code/src/models/email-verification.ts +++ b/gadget-code/src/models/email-verification.ts @@ -3,9 +3,9 @@ // All Rights Reserved import { Schema, Types, model } from "mongoose"; +import { IUser } from "@gadget/api"; import { DtpLog } from "../lib/log.js"; -import { IUser } from "./user.js"; const log = new DtpLog({ name: "EmailVerificationModel", slug: "emailVerification", @@ -37,7 +37,7 @@ export const EmailVerificationSchema = new Schema({ export const EmailVerification = model( "EmailVerification", - EmailVerificationSchema + EmailVerificationSchema, ); export default EmailVerification; diff --git a/gadget-code/src/models/project.ts b/gadget-code/src/models/project.ts index 4b7e6b1..8a77988 100644 --- a/gadget-code/src/models/project.ts +++ b/gadget-code/src/models/project.ts @@ -2,8 +2,9 @@ // Copyright (C) 2026 Robert Colbert // All Rights Reserved -import { Types, Schema, Document, model } from "mongoose"; -import { IUser } from "./user.js"; +import { Types, Schema, model } from "mongoose"; + +import { IProject } from "@gadget/api"; export const ProjectSchema = new Schema({ createdAt: { type: Date, default: Date.now, required: true }, diff --git a/gadget-code/src/models/user.ts b/gadget-code/src/models/user.ts index adb6017..d5a18b4 100644 --- a/gadget-code/src/models/user.ts +++ b/gadget-code/src/models/user.ts @@ -2,9 +2,10 @@ // Copyright (C) 2026 Robert Colbert // All Rights Reserved -import { Types, Schema, Document, model } from "mongoose"; +import { Schema, model } from "mongoose"; import { DtpLog } from "../lib/log.js"; +import { IUser, IUserFlags } from "@gadget/api"; const log = new DtpLog({ name: "UserModel", slug: "user", diff --git a/gadget-code/src/models/web-token.ts b/gadget-code/src/models/web-token.ts index 067acde..17ba9fe 100644 --- a/gadget-code/src/models/web-token.ts +++ b/gadget-code/src/models/web-token.ts @@ -3,7 +3,8 @@ // All Rights Reserved import { Schema, Types, model } from "mongoose"; -import { IUser } from "./user.js"; + +import { IUser } from "@gadget/api"; import { DtpLog } from "../lib/log.js"; const log = new DtpLog({ diff --git a/gadget-code/src/models/web-visit.ts b/gadget-code/src/models/web-visit.ts index 234d044..a2b164b 100644 --- a/gadget-code/src/models/web-visit.ts +++ b/gadget-code/src/models/web-visit.ts @@ -5,7 +5,8 @@ import { Schema, Types, Document, model } from "mongoose"; import { DtpLog } from "../lib/log.js"; -import { IUser } from "./user.js"; +import { IUser } from "@gadget/api"; + const log = new DtpLog({ name: "WebVisitModel", slug: "webVisit", diff --git a/gadget-drone/package.json b/gadget-drone/package.json index f9f7154..5c31691 100644 --- a/gadget-drone/package.json +++ b/gadget-drone/package.json @@ -21,6 +21,7 @@ "packageManager": "pnpm@10.33.2+sha512.a90faf6feeab71ad6c6e57f94e0fe1a12f5dcc22cd754db40ae9593eb6a3e0b6b12e3540218bb37ae083404b1f2ce6db2a4121e979829b4aff94b99f49da1cf8", "dependencies": { "@gadget/ai": "workspace:*", + "@gadget/api": "workspace:*", "ansicolor": "^2.0.3", "dayjs": "^1.11.20", "dotenv": "^17.4.2", diff --git a/packages/api/.gitignore b/packages/api/.gitignore new file mode 100644 index 0000000..1521c8b --- /dev/null +++ b/packages/api/.gitignore @@ -0,0 +1 @@ +dist diff --git a/packages/api/package.json b/packages/api/package.json new file mode 100644 index 0000000..0508108 --- /dev/null +++ b/packages/api/package.json @@ -0,0 +1,28 @@ +{ + "name": "@gadget/api", + "version": "1.0.0", + "description": "Gadget Code API shared interfaces", + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "tsc", + "dev": "tsc --watch" + }, + "keywords": ["gadget", "api", "interfaces", "mongoose"], + "author": "Rob Colbert", + "license": "Apache-2.0", + "dependencies": { + "mongoose": "^8.16.1" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "typescript": "^6.0.3" + } +} \ No newline at end of file diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 68b21f9..03b4e4e 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -7,5 +7,8 @@ export * from "./interfaces/ai-provider.ts"; export * from "./interfaces/user.ts"; export * from "./interfaces/project.ts"; +export * from "./interfaces/drone-registration.ts"; +export * from "./interfaces/drone-monitor.ts"; + export * from "./interfaces/chat-session.ts"; export * from "./interfaces/chat-turn.ts"; diff --git a/packages/api/src/interfaces/ai-provider.ts b/packages/api/src/interfaces/ai-provider.ts index ef53b31..16ebdc8 100644 --- a/packages/api/src/interfaces/ai-provider.ts +++ b/packages/api/src/interfaces/ai-provider.ts @@ -46,6 +46,8 @@ export interface IAiModel { settings?: IAiModelSettings; } +import { Document } from "mongoose"; + export interface IAiProvider extends Document { name: string; apiType: AiApiType; diff --git a/packages/api/src/interfaces/chat-session.ts b/packages/api/src/interfaces/chat-session.ts index a2b1d68..c1f6c23 100644 --- a/packages/api/src/interfaces/chat-session.ts +++ b/packages/api/src/interfaces/chat-session.ts @@ -2,6 +2,10 @@ // Copyright (C) 2026 Rob Colbert // Licensed under the Apache License, Version 2.0 +import { Document, Types } from "mongoose"; +import type { IUser } from "./user.js"; +import type { IProject } from "./project.js"; + export enum ChatSessionMode { Plan = "plan", // for planning and brainstorming Build = "build", // for building and coding @@ -29,4 +33,4 @@ export interface IChatSession extends Document { outputTokens: number; }; pins: IChatSessionPin[]; -} +} \ No newline at end of file diff --git a/packages/api/src/interfaces/chat-turn.ts b/packages/api/src/interfaces/chat-turn.ts index d1b4d9d..e849131 100644 --- a/packages/api/src/interfaces/chat-turn.ts +++ b/packages/api/src/interfaces/chat-turn.ts @@ -2,6 +2,13 @@ // Copyright (C) 2026 Rob Colbert // Licensed under the Apache License, Version 2.0 +import { Document, Types } from "mongoose"; +import type { IUser } from "./user.js"; +import type { IProject } from "./project.js"; +import type { IChatSession } from "./chat-session.js"; +import type { IAiProvider } from "./ai-provider.js"; +import { ChatSessionMode } from "./chat-session.js"; + export enum ChatTurnStatus { Processing = "processing", Finished = "finished", @@ -52,4 +59,4 @@ export interface IChatTurn extends Document { toolCalls: IChatToolCall[]; subagents: IChatSubagentProcess[]; // subagents used while processing this turn stats: IChatTurnStats; -} +} \ No newline at end of file diff --git a/packages/api/src/interfaces/drone-monitor.ts b/packages/api/src/interfaces/drone-monitor.ts new file mode 100644 index 0000000..c95b511 --- /dev/null +++ b/packages/api/src/interfaces/drone-monitor.ts @@ -0,0 +1,35 @@ +// src/interfaces/drone-monitor.ts +// Copyright (C) 2026 Rob Colbert +// Licensed under the Apache License, Version 2.0 + +import { Types, Document } from "mongoose"; +import { IDroneRegistration } from "./drone-registration.ts"; + +export interface IMemoryMonitor { + count: number; + bytes: number; +} + +export interface IDroneMonitor extends Document { + _id: Types.ObjectId; + registration: IDroneRegistration | Types.ObjectId; + timestamp: Date; + memory: { + rss: number; + v8: { + heapTotal: number; + heapUsed: number; + heapExternal: number; + }; + os: { + total: number; + free: number; + }; + ai: { + subagents: IMemoryMonitor; + fileOperations: IMemoryMonitor; + toolCalls: IMemoryMonitor; + }; + logs: IMemoryMonitor; + }; +} diff --git a/packages/api/src/interfaces/drone-registration.ts b/packages/api/src/interfaces/drone-registration.ts new file mode 100644 index 0000000..81e8a87 --- /dev/null +++ b/packages/api/src/interfaces/drone-registration.ts @@ -0,0 +1,23 @@ +// src/interfaces/drone-registration.ts +// Copyright (C) 2026 Rob Colbert +// Licensed under the Apache License, Version 2.0 + +import { Types, Document } from "mongoose"; +import { IUser } from "./user.ts"; + +export enum DroneStatus { + Starting = "starting", + Available = "available", + Busy = "busy", + Offline = "offline", +} + +export interface IDroneRegistration extends Document { + _id: Types.ObjectId; + createdAt: Date; + updatedAt: Date; + user: IUser | Types.ObjectId; + hostname: string; + status: DroneStatus; + currentJobId?: string; +} diff --git a/packages/api/src/interfaces/project.ts b/packages/api/src/interfaces/project.ts index c6392ce..e35b8b8 100644 --- a/packages/api/src/interfaces/project.ts +++ b/packages/api/src/interfaces/project.ts @@ -2,6 +2,9 @@ // Copyright (C) 2026 Rob Colbert // Licensed under the Apache License, Version 2.0 +import { Document, Types } from "mongoose"; +import type { IUser } from "./user.js"; + export interface IProject extends Document { createdAt: Date; user: IUser | Types.ObjectId; diff --git a/packages/api/src/interfaces/user.ts b/packages/api/src/interfaces/user.ts index 01b144b..a02cfff 100644 --- a/packages/api/src/interfaces/user.ts +++ b/packages/api/src/interfaces/user.ts @@ -9,6 +9,8 @@ export interface IUserFlags { isBanned: boolean; } +import { Document, Types } from "mongoose"; + export interface IUser extends Document { _id: Types.ObjectId; email: string; diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json new file mode 100644 index 0000000..6414465 --- /dev/null +++ b/packages/api/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "lib": ["ES2022"], + "outDir": "./dist", + "rootDir": "./src", + "typeRoots": ["node_modules/@types", "types"], + "types": ["node"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "allowImportingTsExtensions": true, + "rewriteRelativeImportExtensions": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "src/**/*.test.ts"] +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f3ff179..0caa286 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,6 +16,9 @@ importers: '@gadget/ai': specifier: workspace:* version: link:../packages/ai + '@gadget/api': + specifier: workspace:* + version: link:../packages/api ansicolor: specifier: ^2.0.3 version: 2.0.3 @@ -239,6 +242,9 @@ importers: '@gadget/ai': specifier: workspace:* version: link:../packages/ai + '@gadget/api': + specifier: workspace:* + version: link:../packages/api ansicolor: specifier: ^2.0.3 version: 2.0.3 @@ -302,6 +308,19 @@ importers: specifier: ^6.0.3 version: 6.0.3 + packages/api: + dependencies: + mongoose: + specifier: ^8.16.1 + version: 8.23.1 + devDependencies: + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + typescript: + specifier: ^6.0.3 + version: 6.0.3 + packages: '@adobe/css-tools@4.4.4': @@ -3690,7 +3709,7 @@ snapshots: '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 24.12.2 + '@types/node': 25.6.0 '@types/browser-sync@2.29.1': dependencies: @@ -3711,7 +3730,7 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 24.12.2 + '@types/node': 25.6.0 '@types/cookie-parser@1.4.10(@types/express@5.0.6)': dependencies: @@ -3719,7 +3738,7 @@ snapshots: '@types/cors@2.8.19': dependencies: - '@types/node': 24.12.2 + '@types/node': 25.6.0 '@types/deep-eql@4.0.2': {} @@ -3727,7 +3746,7 @@ snapshots: '@types/express-serve-static-core@5.1.1': dependencies: - '@types/node': 24.12.2 + '@types/node': 25.6.0 '@types/qs': 6.15.0 '@types/range-parser': 1.2.7 '@types/send': 1.2.1 @@ -3799,7 +3818,7 @@ snapshots: '@types/send@1.2.1': dependencies: - '@types/node': 24.12.2 + '@types/node': 25.6.0 '@types/serve-favicon@2.5.7': dependencies: @@ -3808,7 +3827,7 @@ snapshots: '@types/serve-static@2.2.0': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 24.12.2 + '@types/node': 25.6.0 '@types/uikit@3.23.0': {} @@ -3822,7 +3841,7 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 24.12.2 + '@types/node': 25.6.0 '@vitejs/plugin-react@6.0.1(vite@8.0.10(@types/node@24.12.2)(esbuild@0.25.12)(jiti@2.6.1)(less@4.6.4)(tsx@4.21.0))': dependencies: @@ -4334,7 +4353,7 @@ snapshots: engine.io@6.6.7: dependencies: '@types/cors': 2.8.19 - '@types/node': 24.12.2 + '@types/node': 25.6.0 '@types/ws': 8.18.1 accepts: 1.3.8 base64id: 2.0.0