mirror of
https://github.com/simstudioai/sim.git
synced 2026-02-09 22:25:33 -05:00
removed unused route
This commit is contained in:
@@ -1,111 +0,0 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateJiraCloudId, validateJiraIssueKey } from '@/lib/core/security/input-validation'
|
||||
import { getJiraCloudId } from '@/tools/jira/utils'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('JiraIssueAPI')
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const auth = await checkSessionOrInternalAuth(request)
|
||||
if (!auth.success || !auth.userId) {
|
||||
return NextResponse.json({ error: auth.error || 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const { domain, accessToken, issueId, cloudId: providedCloudId } = await request.json()
|
||||
if (!domain) {
|
||||
logger.error('Missing domain in request')
|
||||
return NextResponse.json({ error: 'Domain is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
logger.error('Missing access token in request')
|
||||
return NextResponse.json({ error: 'Access token is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!issueId) {
|
||||
logger.error('Missing issue ID in request')
|
||||
return NextResponse.json({ error: 'Issue ID is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
const cloudId = providedCloudId || (await getJiraCloudId(domain, accessToken))
|
||||
logger.info('Using cloud ID:', cloudId)
|
||||
|
||||
const cloudIdValidation = validateJiraCloudId(cloudId, 'cloudId')
|
||||
if (!cloudIdValidation.isValid) {
|
||||
return NextResponse.json({ error: cloudIdValidation.error }, { status: 400 })
|
||||
}
|
||||
|
||||
const issueIdValidation = validateJiraIssueKey(issueId, 'issueId')
|
||||
if (!issueIdValidation.isValid) {
|
||||
return NextResponse.json({ error: issueIdValidation.error }, { status: 400 })
|
||||
}
|
||||
|
||||
const url = `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/issue/${issueId}`
|
||||
|
||||
logger.info('Fetching Jira issue from:', url)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
logger.error('Jira API error:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
})
|
||||
|
||||
let errorMessage
|
||||
try {
|
||||
const errorData = await response.json()
|
||||
logger.error('Error details:', errorData)
|
||||
errorMessage = errorData.message || `Failed to fetch issue (${response.status})`
|
||||
} catch (_e) {
|
||||
errorMessage = `Failed to fetch issue: ${response.status} ${response.statusText}`
|
||||
}
|
||||
return NextResponse.json({ error: errorMessage }, { status: response.status })
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
logger.info('Successfully fetched issue:', data.key)
|
||||
|
||||
const issueInfo: any = {
|
||||
id: data.key,
|
||||
name: data.fields.summary,
|
||||
mimeType: 'jira/issue',
|
||||
url: `https://${domain}/browse/${data.key}`,
|
||||
modifiedTime: data.fields.updated,
|
||||
webViewLink: `https://${domain}/browse/${data.key}`,
|
||||
status: data.fields.status?.name,
|
||||
description: data.fields.description,
|
||||
priority: data.fields.priority?.name,
|
||||
assignee: data.fields.assignee?.displayName,
|
||||
reporter: data.fields.reporter?.displayName,
|
||||
project: {
|
||||
key: data.fields.project?.key,
|
||||
name: data.fields.project?.name,
|
||||
},
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
issue: issueInfo,
|
||||
cloudId,
|
||||
})
|
||||
} catch (error) {
|
||||
logger.error('Error processing request:', error)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to retrieve Jira issue',
|
||||
details: (error as Error).message,
|
||||
},
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { randomUUID } from 'crypto'
|
||||
import type { ItemCreateParams } from '@1password/sdk'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
@@ -62,15 +63,13 @@ export async function POST(request: NextRequest) {
|
||||
}))
|
||||
: undefined
|
||||
|
||||
// Cast to any because toSdkCategory/toSdkFieldType return string literals
|
||||
// that match SDK enum values but TypeScript can't verify this at compile time
|
||||
const item = await client.items.create({
|
||||
vaultId: params.vaultId,
|
||||
category: toSdkCategory(params.category) as any,
|
||||
category: toSdkCategory(params.category),
|
||||
title: params.title || '',
|
||||
tags: parsedTags,
|
||||
fields: parsedFields as any,
|
||||
})
|
||||
fields: parsedFields,
|
||||
} as ItemCreateParams)
|
||||
|
||||
return NextResponse.json(normalizeSdkItem(item))
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { randomUUID } from 'crypto'
|
||||
import type { Item } from '@1password/sdk'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
@@ -79,9 +80,9 @@ export async function POST(request: NextRequest) {
|
||||
autofillBehavior: 'AnywhereOnWebsite' as const,
|
||||
}))
|
||||
: existing.websites,
|
||||
}
|
||||
} as Item
|
||||
|
||||
const result = await client.items.put(sdkItem as any)
|
||||
const result = await client.items.put(sdkItem)
|
||||
return NextResponse.json(normalizeSdkItem(result))
|
||||
}
|
||||
|
||||
|
||||
@@ -35,11 +35,7 @@ export async function POST(request: NextRequest) {
|
||||
const body = await request.json()
|
||||
const params = UpdateItemSchema.parse(body)
|
||||
const creds = resolveCredentials(params)
|
||||
const ops = JSON.parse(params.operations) as Array<{
|
||||
op: string
|
||||
path: string
|
||||
value?: unknown
|
||||
}>
|
||||
const ops = JSON.parse(params.operations) as JsonPatchOperation[]
|
||||
|
||||
logger.info(
|
||||
`[${requestId}] Updating item ${params.itemId} in vault ${params.vaultId} (${creds.mode} mode)`
|
||||
@@ -48,7 +44,6 @@ export async function POST(request: NextRequest) {
|
||||
if (creds.mode === 'service_account') {
|
||||
const client = await createOnePasswordClient(creds.serviceAccountToken!)
|
||||
|
||||
// SDK doesn't support PATCH — fetch, apply patches, then put
|
||||
const item = await client.items.get(params.vaultId, params.itemId)
|
||||
|
||||
for (const op of ops) {
|
||||
@@ -89,8 +84,15 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Apply a single RFC6902 JSON Patch operation to a mutable SDK Item. */
|
||||
function applyPatch(item: Record<string, any>, op: { op: string; path: string; value?: unknown }) {
|
||||
interface JsonPatchOperation {
|
||||
op: 'add' | 'remove' | 'replace'
|
||||
path: string
|
||||
value?: unknown
|
||||
}
|
||||
|
||||
/** Apply a single RFC6902 JSON Patch operation to a mutable object. */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function applyPatch(item: Record<string, any>, op: JsonPatchOperation) {
|
||||
const segments = op.path.split('/').filter(Boolean)
|
||||
|
||||
if (segments.length === 1) {
|
||||
@@ -103,7 +105,6 @@ function applyPatch(item: Record<string, any>, op: { op: string; path: string; v
|
||||
return
|
||||
}
|
||||
|
||||
// Navigate to parent of target
|
||||
let target = item
|
||||
for (let i = 0; i < segments.length - 1; i++) {
|
||||
const seg = segments[i]
|
||||
|
||||
@@ -1,12 +1,112 @@
|
||||
import type {
|
||||
Item,
|
||||
ItemCategory,
|
||||
ItemField,
|
||||
ItemFieldType,
|
||||
ItemOverview,
|
||||
ItemSection,
|
||||
VaultOverview,
|
||||
Website,
|
||||
} from '@1password/sdk'
|
||||
import { createLogger } from '@sim/logger'
|
||||
|
||||
const logger = createLogger('OnePasswordRouteUtils')
|
||||
|
||||
/** Connect-format field type strings returned by normalization. */
|
||||
type ConnectFieldType =
|
||||
| 'STRING'
|
||||
| 'CONCEALED'
|
||||
| 'EMAIL'
|
||||
| 'URL'
|
||||
| 'OTP'
|
||||
| 'PHONE'
|
||||
| 'DATE'
|
||||
| 'MONTH_YEAR'
|
||||
| 'MENU'
|
||||
| 'ADDRESS'
|
||||
| 'REFERENCE'
|
||||
| 'SSHKEY'
|
||||
| 'CREDIT_CARD_NUMBER'
|
||||
| 'CREDIT_CARD_TYPE'
|
||||
|
||||
/** Connect-format category strings returned by normalization. */
|
||||
type ConnectCategory =
|
||||
| 'LOGIN'
|
||||
| 'PASSWORD'
|
||||
| 'API_CREDENTIAL'
|
||||
| 'SECURE_NOTE'
|
||||
| 'SERVER'
|
||||
| 'DATABASE'
|
||||
| 'CREDIT_CARD'
|
||||
| 'IDENTITY'
|
||||
| 'SSH_KEY'
|
||||
| 'DOCUMENT'
|
||||
| 'SOFTWARE_LICENSE'
|
||||
| 'EMAIL_ACCOUNT'
|
||||
| 'MEMBERSHIP'
|
||||
| 'PASSPORT'
|
||||
| 'REWARD_PROGRAM'
|
||||
| 'DRIVER_LICENSE'
|
||||
| 'BANK_ACCOUNT'
|
||||
| 'MEDICAL_RECORD'
|
||||
| 'OUTDOOR_LICENSE'
|
||||
| 'WIRELESS_ROUTER'
|
||||
| 'SOCIAL_SECURITY_NUMBER'
|
||||
| 'CUSTOM'
|
||||
|
||||
/** Normalized vault shape matching the Connect API response. */
|
||||
export interface NormalizedVault {
|
||||
id: string
|
||||
name: string
|
||||
description: null
|
||||
attributeVersion: number
|
||||
contentVersion: number
|
||||
items: number
|
||||
type: string
|
||||
createdAt: string | null
|
||||
updatedAt: string | null
|
||||
}
|
||||
|
||||
/** Normalized item overview shape matching the Connect API response. */
|
||||
export interface NormalizedItemOverview {
|
||||
id: string
|
||||
title: string
|
||||
vault: { id: string }
|
||||
category: ConnectCategory
|
||||
urls: Array<{ href: string; label: string | null; primary: boolean }>
|
||||
favorite: boolean
|
||||
tags: string[]
|
||||
version: number
|
||||
state: string | null
|
||||
createdAt: string | null
|
||||
updatedAt: string | null
|
||||
lastEditedBy: null
|
||||
}
|
||||
|
||||
/** Normalized field shape matching the Connect API response. */
|
||||
export interface NormalizedField {
|
||||
id: string
|
||||
label: string
|
||||
type: ConnectFieldType
|
||||
purpose: string
|
||||
value: string | null
|
||||
section: { id: string } | null
|
||||
generate: boolean
|
||||
recipe: null
|
||||
entropy: null
|
||||
}
|
||||
|
||||
/** Normalized full item shape matching the Connect API response. */
|
||||
export interface NormalizedItem extends NormalizedItemOverview {
|
||||
fields: NormalizedField[]
|
||||
sections: Array<{ id: string; label: string }>
|
||||
}
|
||||
|
||||
/**
|
||||
* SDK field type string values → Connect field type mapping.
|
||||
* Uses string literals instead of enum imports to avoid loading the WASM module at build time.
|
||||
*/
|
||||
const SDK_TO_CONNECT_FIELD_TYPE: Record<string, string> = {
|
||||
const SDK_TO_CONNECT_FIELD_TYPE: Record<string, ConnectFieldType> = {
|
||||
Text: 'STRING',
|
||||
Concealed: 'CONCEALED',
|
||||
Email: 'EMAIL',
|
||||
@@ -24,7 +124,7 @@ const SDK_TO_CONNECT_FIELD_TYPE: Record<string, string> = {
|
||||
}
|
||||
|
||||
/** SDK category string values → Connect category mapping. */
|
||||
const SDK_TO_CONNECT_CATEGORY: Record<string, string> = {
|
||||
const SDK_TO_CONNECT_CATEGORY: Record<string, ConnectCategory> = {
|
||||
Login: 'LOGIN',
|
||||
Password: 'PASSWORD',
|
||||
ApiCredentials: 'API_CREDENTIAL',
|
||||
@@ -52,7 +152,7 @@ const SDK_TO_CONNECT_CATEGORY: Record<string, string> = {
|
||||
}
|
||||
|
||||
/** Connect category → SDK category string mapping. */
|
||||
const CONNECT_TO_SDK_CATEGORY: Record<string, string> = {
|
||||
const CONNECT_TO_SDK_CATEGORY: Record<string, `${ItemCategory}`> = {
|
||||
LOGIN: 'Login',
|
||||
PASSWORD: 'Password',
|
||||
API_CREDENTIAL: 'ApiCredentials',
|
||||
@@ -77,7 +177,7 @@ const CONNECT_TO_SDK_CATEGORY: Record<string, string> = {
|
||||
}
|
||||
|
||||
/** Connect field type → SDK field type string mapping. */
|
||||
const CONNECT_TO_SDK_FIELD_TYPE: Record<string, string> = {
|
||||
const CONNECT_TO_SDK_FIELD_TYPE: Record<string, `${ItemFieldType}`> = {
|
||||
STRING: 'Text',
|
||||
CONCEALED: 'Concealed',
|
||||
EMAIL: 'Email',
|
||||
@@ -98,10 +198,10 @@ const CONNECT_TO_SDK_FIELD_TYPE: Record<string, string> = {
|
||||
export type ConnectionMode = 'service_account' | 'connect'
|
||||
|
||||
export interface CredentialParams {
|
||||
connectionMode?: ConnectionMode
|
||||
serviceAccountToken?: string
|
||||
serverUrl?: string
|
||||
apiKey?: string
|
||||
connectionMode?: ConnectionMode | null
|
||||
serviceAccountToken?: string | null
|
||||
serverUrl?: string | null
|
||||
apiKey?: string | null
|
||||
}
|
||||
|
||||
export interface ResolvedCredentials {
|
||||
@@ -172,7 +272,7 @@ export async function connectRequest(options: {
|
||||
}
|
||||
|
||||
/** Normalize an SDK VaultOverview to match Connect API vault shape. */
|
||||
export function normalizeSdkVault(vault: Record<string, any>) {
|
||||
export function normalizeSdkVault(vault: VaultOverview): NormalizedVault {
|
||||
return {
|
||||
id: vault.id,
|
||||
name: vault.title,
|
||||
@@ -189,13 +289,13 @@ export function normalizeSdkVault(vault: Record<string, any>) {
|
||||
}
|
||||
|
||||
/** Normalize an SDK ItemOverview to match Connect API item summary shape. */
|
||||
export function normalizeSdkItemOverview(item: Record<string, any>) {
|
||||
export function normalizeSdkItemOverview(item: ItemOverview): NormalizedItemOverview {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
vault: { id: item.vaultId },
|
||||
category: SDK_TO_CONNECT_CATEGORY[item.category] ?? 'CUSTOM',
|
||||
urls: (item.websites ?? []).map((w: Record<string, any>) => ({
|
||||
urls: item.websites.map((w: Website) => ({
|
||||
href: w.url,
|
||||
label: w.label ?? null,
|
||||
primary: false,
|
||||
@@ -213,13 +313,13 @@ export function normalizeSdkItemOverview(item: Record<string, any>) {
|
||||
}
|
||||
|
||||
/** Normalize a full SDK Item to match Connect API FullItem shape. */
|
||||
export function normalizeSdkItem(item: Record<string, any>) {
|
||||
export function normalizeSdkItem(item: Item): NormalizedItem {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
vault: { id: item.vaultId },
|
||||
category: SDK_TO_CONNECT_CATEGORY[item.category] ?? 'CUSTOM',
|
||||
urls: (item.websites ?? []).map((w: Record<string, any>) => ({
|
||||
urls: item.websites.map((w: Website) => ({
|
||||
href: w.url,
|
||||
label: w.label ?? null,
|
||||
primary: false,
|
||||
@@ -228,7 +328,7 @@ export function normalizeSdkItem(item: Record<string, any>) {
|
||||
tags: item.tags ?? [],
|
||||
version: item.version ?? 0,
|
||||
state: null,
|
||||
fields: (item.fields ?? []).map((field: Record<string, any>) => ({
|
||||
fields: item.fields.map((field: ItemField) => ({
|
||||
id: field.id,
|
||||
label: field.title,
|
||||
type: SDK_TO_CONNECT_FIELD_TYPE[field.fieldType] ?? 'STRING',
|
||||
@@ -239,7 +339,7 @@ export function normalizeSdkItem(item: Record<string, any>) {
|
||||
recipe: null,
|
||||
entropy: null,
|
||||
})),
|
||||
sections: (item.sections ?? []).map((section: Record<string, any>) => ({
|
||||
sections: item.sections.map((section: ItemSection) => ({
|
||||
id: section.id,
|
||||
label: section.title,
|
||||
})),
|
||||
@@ -252,11 +352,11 @@ export function normalizeSdkItem(item: Record<string, any>) {
|
||||
}
|
||||
|
||||
/** Convert a Connect-style category string to the SDK category string. */
|
||||
export function toSdkCategory(category: string): string {
|
||||
export function toSdkCategory(category: string): `${ItemCategory}` {
|
||||
return CONNECT_TO_SDK_CATEGORY[category] ?? 'Login'
|
||||
}
|
||||
|
||||
/** Convert a Connect-style field type string to the SDK field type string. */
|
||||
export function toSdkFieldType(type: string): string {
|
||||
export function toSdkFieldType(type: string): `${ItemFieldType}` {
|
||||
return CONNECT_TO_SDK_FIELD_TYPE[type] ?? 'Text'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user