(data: CreateToolData)
| 189 | } |
| 190 | |
| 191 | export async function createTool(data: CreateToolData): Promise<ToolRow> { |
| 192 | await ensureToolsTables(); |
| 193 | const db = getDb(); |
| 194 | const userEmail = getRequestUserEmail(); |
| 195 | if (!userEmail) throw new Error("no authenticated user"); |
| 196 | const orgId = getRequestOrgId(); |
| 197 | const id = randomUUID(); |
| 198 | const now = new Date().toISOString(); |
| 199 | const row: ToolRow = { |
| 200 | id, |
| 201 | name: data.name, |
| 202 | description: data.description ?? "", |
| 203 | content: data.content ?? "", |
| 204 | icon: data.icon ?? null, |
| 205 | createdAt: now, |
| 206 | updatedAt: now, |
| 207 | ownerEmail: userEmail, |
| 208 | orgId: orgId ?? null, |
| 209 | // Default to org-visibility when the user has an active organization so |
| 210 | // teammates see the tool in their sidebar — matching how analytics |
| 211 | // dashboards/analyses are scoped (`templates/analytics/server/lib/ |
| 212 | // dashboards-store.ts:356`). Solo users (no org) get the private |
| 213 | // default. Owners can still flip back to private via update-tool. |
| 214 | visibility: orgId ? "org" : "private", |
| 215 | }; |
| 216 | await db.insert(tools).values(row); |
| 217 | return row; |
| 218 | } |
| 219 | |
| 220 | export interface UpdateToolData { |
| 221 | name?: string; |
no test coverage detected