All files / layers / L1 / contracts projects.ts

83.33% Statements 35/42
87.5% Branches 14/16
68.75% Functions 11/16
81.57% Lines 31/38

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75  57x   3x 3x 3x 1x     1x     3x 3x 1x     1x     3x   57x 104x     4x 9x   1x   9x   9x 9x 5x 1x   4x       9x 9x 4x 1x   3x       9x               3x                     3x 6x      
import { load } from 'js-yaml'
import type { ApiContract } from '@/layers/interfaces'
import type { components } from '@/types/api'
 
type Project = components['schemas']['Project']
type CreateProjectRequest = components['schemas']['CreateProjectRequest']
tyIpe UpdateProjectRequest = components['schemas']['UpdateProjectRequest']

// Form-side bodies: generated request types now carry the API object shapes
// (config, secrets), but the UI form diverges — secrets arrives as a plain
// string (password field) and config as a YAML string or a JSON object.
type ProjectCreateBody = Omit<Partial<CreateProjectRequest>, 'config' | 'secrets'> & {
  config?: string | Record<string, unknown> | null
  secrets?: string
}I
type ProjectUpdateBody = Omit<Partial<UpdateProjectRequest>, 'config' | 'secrets'> & {
  config?: string | Record<string, unknown> | null
  secrets?: string
}
 
type ProjectListQuery = {
  [key: string]: string | number | boolean | undefined
}
 
type JsonObject = Record<string, unknown>
 
const webhookSecrets = (value: string): JsonObject => ({
  webhooks: { github_pr: { webhook_secret: value } },
})
 
function normalizeBody(input: JsonObject): JsonObject {
  const body = { ...input }
 
  const secrets = body['secrets']
  if (typeof secrets === 'string') {
    if (secrets === '') {
      delete body['secrets']
    } else {
      body['secrets'] = webhookSecrets(secrets)
    }
  }
 
  const config = body['config']
  if (typeof config === 'string') {
    if (config === '') {
      delete body['config']
    } else {
      body['config'] = load(config)
    }
  }
 
  return body
}
 
export const projectsContract: ApiContract<
  Project,
  ProjectCreateBody,
  ProjectUpdateBody,
  ProjectListQuery
> = {
  idOf: (e) => e.id,
  entityPath: 'projects',
  endpoints: {
    list: '/projects',
    detail: (id) => `/projects/${id}`,
    create: '/projects',
    update: (id) => `/projects/${id}`,
    remove: (id) => `/projects/${id}`,
  },
  request: {
    create: (input) => normalizeBody(input as JsonObject) as ProjectCreateBody,
    update: (input) => normalizeBody(input as JsonObject) as ProjectUpdateBody,
  },
}