diff --git a/.vscode/settings.json b/.vscode/settings.json index 1c1d6cc..8a8ada5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,6 +7,9 @@ "editor.defaultFormatter": "biomejs.biome", "editor.formatOnSave": true }, + "editor.codeActionsOnSave": { + "source.organizeImports.biome": "explicit" + }, "typescript.tsdk": "node_modules/typescript/lib", "explorer.fileNesting.enabled": true } diff --git a/biome.json b/biome.json index c00b13f..bfcd045 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json", "assist": { "actions": { "source": { "organizeImports": "on" } } }, "formatter": { "enabled": true, diff --git a/package-lock.json b/package-lock.json index 453506e..2992814 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2571,10 +2571,11 @@ "dev": true }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } diff --git a/src/resources/agency/projects/interfaces/project.interface.ts b/src/resources/agency/projects/interfaces/project.interface.ts index 5bc2ac9..d294541 100644 --- a/src/resources/agency/projects/interfaces/project.interface.ts +++ b/src/resources/agency/projects/interfaces/project.interface.ts @@ -1,3 +1,4 @@ +import type { Brand, BrandResponse } from '../../brand/interfaces' import type { Domain, DomainResponse } from '../../domains/interfaces' export interface Project { @@ -11,6 +12,7 @@ export interface Project { timezone: string subdomain: string primaryDomain: string | null | Domain + brand: string | null | Brand published: boolean processed: boolean createdAt: number @@ -29,6 +31,7 @@ export interface ProjectResponse { timezone: string subdomain: string primary_domain: string | null | DomainResponse + brand: string | null | BrandResponse published: boolean processed: boolean created_at: number diff --git a/src/resources/agency/projects/projects.spec.ts b/src/resources/agency/projects/projects.spec.ts index 062be53..e31f988 100644 --- a/src/resources/agency/projects/projects.spec.ts +++ b/src/resources/agency/projects/projects.spec.ts @@ -41,6 +41,20 @@ describe('Project', () => { object: 'list', }) }) + + it('can retrieve a list of projects with an expandable brand', async () => { + fetchOnce(projectListFixture) + const projects = await blutui + .agency('foo') + .projects.list({ expand: ['brand'] }) + + expect(fetchURL()).toBe( + encodeURI(`${blutui.baseURL}/v1/agencies/foo/projects?expand[]=brand`) + ) + expect(projects).toMatchObject({ + object: 'list', + }) + }) }) describe('get', () => { diff --git a/src/resources/agency/projects/projects.ts b/src/resources/agency/projects/projects.ts index 3afbae1..d67d2b0 100644 --- a/src/resources/agency/projects/projects.ts +++ b/src/resources/agency/projects/projects.ts @@ -1,12 +1,15 @@ -import { - deserializeProject, - deserializeProjectList, - serializeCreateProjectOptions, - serializeUpdateProjectOptions, -} from './serializers' -import { deserializeDomainList } from '../domains/serializers' - import type { Agency } from '@/agency' +import type { + DeletedResponse, + Expandable, + List, + ListResponse, + PaginationOptions, +} from '@/types' +import type { Cassette, CassetteResponse } from '../cassettes/interfaces' +import { deserializeCassetteList } from '../cassettes/serializers' +import type { Domain, DomainResponse } from '../domains/interfaces' +import { deserializeDomainList } from '../domains/serializers' import type { CreateProjectOptions, Project, @@ -17,16 +20,14 @@ import type { SerializedUpdateProjectOptions, UpdateProjectOptions, } from './interfaces' -import type { Domain, DomainResponse } from '../domains/interfaces' -import type { Cassette, CassetteResponse } from '../cassettes/interfaces' -import type { - DeletedResponse, - Expandable, - List, - ListResponse, - PaginationOptions, -} from '@/types' -import { deserializeCassetteList } from '../cassettes/serializers' +import { + deserializeProject, + deserializeProjectList, + serializeCreateProjectOptions, + serializeUpdateProjectOptions, +} from './serializers' + +export type ProjectExpandable = Expandable<'primary_domain' | 'brand'> export class Projects { constructor(private readonly agency: Agency) {} @@ -35,7 +36,7 @@ export class Projects { * Get the projects list for the current agency. */ async list( - options?: PaginationOptions & Expandable<'primary_domain'> + options?: PaginationOptions & ProjectExpandable ): Promise> { const { data } = await this.agency.get>( 'projects', @@ -50,10 +51,7 @@ export class Projects { /** * Get a project's information by ID. */ - async get( - id: string, - options?: Expandable<'primary_domain'> - ): Promise { + async get(id: string, options?: ProjectExpandable): Promise { const { data } = await this.agency.get(`projects/${id}`, { query: options, }) @@ -152,7 +150,7 @@ export class Projects { */ async search( payload: SearchProjectOptions, - options?: PaginationOptions & Expandable<'primary_domain'> + options?: PaginationOptions & ProjectExpandable ): Promise> { const { data } = await this.agency.post< ListResponse, diff --git a/src/resources/agency/projects/serializers/project.serializer.ts b/src/resources/agency/projects/serializers/project.serializer.ts index 236a2f6..774b18d 100644 --- a/src/resources/agency/projects/serializers/project.serializer.ts +++ b/src/resources/agency/projects/serializers/project.serializer.ts @@ -1,8 +1,8 @@ +import type { List, ListResponse } from '@/types' import { deserializePaginationMeta } from '@/utils/serializers' +import { deserializeBrand } from '../../brand/serializers' import { deserializeDomain } from '../../domains/serializers' - import type { Project, ProjectResponse } from '../interfaces' -import type { List, ListResponse } from '@/types' export const deserializeProject = (project: ProjectResponse): Project => ({ id: project.id, @@ -18,6 +18,10 @@ export const deserializeProject = (project: ProjectResponse): Project => ({ project.primary_domain instanceof Object ? deserializeDomain(project.primary_domain) : project.primary_domain, + brand: + project.brand instanceof Object + ? deserializeBrand(project.brand) + : project.brand, published: project.published, processed: project.processed, createdAt: project.created_at, diff --git a/src/resources/project/menus/fixtures/menu-with-items.json b/src/resources/project/menus/fixtures/menu-with-items.json index c9ab0bd..00f5a04 100644 --- a/src/resources/project/menus/fixtures/menu-with-items.json +++ b/src/resources/project/menus/fixtures/menu-with-items.json @@ -2,17 +2,19 @@ "id": "9bfdb42b-1bf0-4510-978e-46aa329f8efa", "object": "menu", "name": "Primary Menu", - "items": [{ - "id": "99bc147e-966c-4dd0-8def-de817c63cf41", - "object": "menu_item", - "label": "Contact", - "url": "/contact", - "active": true, - "is_new_tab": false, - "order": 1, - "created_at": 1720758022, - "updated_at": 1720758046 - }], + "items": [ + { + "id": "99bc147e-966c-4dd0-8def-de817c63cf41", + "object": "menu_item", + "label": "Contact", + "url": "/contact", + "active": true, + "is_new_tab": false, + "order": 1, + "created_at": 1720758022, + "updated_at": 1720758046 + } + ], "created_at": 1716170007, "updated_at": 1716170007 } diff --git a/src/resources/project/redirect/redirect.admin.ts b/src/resources/project/redirect/redirect.admin.ts index 9d8c394..b7b8a74 100644 --- a/src/resources/project/redirect/redirect.admin.ts +++ b/src/resources/project/redirect/redirect.admin.ts @@ -41,9 +41,12 @@ export class Redirects { * Get a redirect's information by ID. */ async get(id: string, options?: Expandable<'items'>): Promise { - const { data } = await this.project.get(`redirects/${id}`, { - query: options, - }) + const { data } = await this.project.get( + `redirects/${id}`, + { + query: options, + } + ) return deserializeRedirect(data) } @@ -80,7 +83,9 @@ export class Redirects { * Remove the redirect for the current project. */ async remove(id: string): Promise { - const { data } = await this.project.delete(`redirects/${id}`) + const { data } = await this.project.delete( + `redirects/${id}` + ) return data }