@ebay-dt/bonfire-cli 0.1.0-alpha.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +42 -0
  2. package/dist/command.d.ts +21 -2
  3. package/dist/command.d.ts.map +1 -1
  4. package/dist/command.js +235 -1
  5. package/dist/command.js.map +1 -1
  6. package/dist/convert.d.ts +47 -0
  7. package/dist/convert.d.ts.map +1 -0
  8. package/dist/convert.js +509 -0
  9. package/dist/convert.js.map +1 -0
  10. package/package.json +5 -3
  11. package/templates/instance/context/PROTOTYPE.md +108 -0
  12. package/templates/instance/context/ROOT.md +23 -0
  13. package/templates/instance/context/hooks/block-env-reads.mjs +144 -0
  14. package/templates/instance/context/mcp.json +8 -0
  15. package/templates/instance/context/settings.json +19 -0
  16. package/templates/instance/context/skills/color-scheme/SKILL.md +98 -0
  17. package/templates/instance/context/skills/item-data/SKILL.md +145 -0
  18. package/templates/instance/context/skills/setup-evomcp/SKILL.md +73 -0
  19. package/templates/instance/next.config.ts +10 -0
  20. package/templates/instance/src/actions/agents.ts +15 -0
  21. package/templates/instance/src/actions/prototypes.ts +37 -0
  22. package/templates/instance/src/app/(prototypes)/layout.tsx +40 -0
  23. package/templates/instance/src/app/(system)/api/prototype-dirty/route.ts +4 -0
  24. package/templates/instance/src/app/(system)/auth/login/route.ts +4 -0
  25. package/templates/instance/src/app/(system)/auth/logout/route.ts +4 -0
  26. package/templates/instance/src/app/(system)/auth/status/route.ts +4 -0
  27. package/templates/instance/src/app/(system)/layout.tsx +20 -0
  28. package/templates/instance/src/app/(system)/login/page.tsx +14 -0
  29. package/templates/instance/src/app/(system)/page.tsx +33 -0
  30. package/templates/instance/src/app/api/items/[itemId]/route.ts +21 -0
  31. package/templates/instance/src/app/api/items/route.ts +11 -0
  32. package/templates/instance/src/app/layout.tsx +56 -0
  33. package/templates/instance/src/bonfire.ts +25 -0
  34. package/templates/instance/src/lib/items/gateway-schemas.ts +100 -0
  35. package/templates/instance/src/lib/items/server.ts +220 -0
  36. package/templates/instance/src/proxy.ts +8 -0
@@ -0,0 +1,37 @@
1
+ 'use server'
2
+
3
+ import type {
4
+ CreatePrototypeInput,
5
+ DuplicatePrototypeInput,
6
+ EditPrototypeInput,
7
+ PrototypeCommandInput,
8
+ } from '@ebay-dt/bonfire-core'
9
+ import { bonfire } from '@/bonfire'
10
+
11
+ export async function createPrototype(input: CreatePrototypeInput) {
12
+ return bonfire.prototypes.actions.create(input)
13
+ }
14
+
15
+ export async function duplicatePrototype(input: DuplicatePrototypeInput) {
16
+ return bonfire.prototypes.actions.duplicate(input)
17
+ }
18
+
19
+ export async function editPrototype(input: EditPrototypeInput) {
20
+ return bonfire.prototypes.actions.edit(input)
21
+ }
22
+
23
+ export async function deletePrototype(input: PrototypeCommandInput) {
24
+ return bonfire.prototypes.actions.delete(input)
25
+ }
26
+
27
+ export async function savePrototype(input: PrototypeCommandInput) {
28
+ return bonfire.prototypes.actions.save(input)
29
+ }
30
+
31
+ export async function discardPrototype(input: PrototypeCommandInput) {
32
+ return bonfire.prototypes.actions.discard(input)
33
+ }
34
+
35
+ export async function deployPrototype(input: PrototypeCommandInput) {
36
+ return bonfire.prototypes.actions.deploy(input)
37
+ }
@@ -0,0 +1,40 @@
1
+ import type { ReactNode } from 'react'
2
+ import { notFound } from 'next/navigation'
3
+ import { AppHeader, PrototypeEnvironment } from '@ebay-dt/bonfire-react'
4
+ import { bonfire } from '@/bonfire'
5
+ import { openInClaudeCode, openInCursor } from '@/actions/agents'
6
+
7
+ export default async function PrototypesLayout({
8
+ children,
9
+ }: Readonly<{ children: ReactNode }>) {
10
+ const [{ headerProps }, prototype] = await Promise.all([
11
+ bonfire.auth.getAppLayoutModel(),
12
+ bonfire.prototypes.getCurrentRouteModel(),
13
+ ])
14
+
15
+ if (prototype === null) notFound()
16
+
17
+ const agentActions = { openInClaudeCode, openInCursor }
18
+ const header = <AppHeader {...headerProps} agentActions={agentActions} />
19
+
20
+ if (prototype.theme === undefined) {
21
+ return (
22
+ <>
23
+ {header}
24
+ {children}
25
+ </>
26
+ )
27
+ }
28
+
29
+ return (
30
+ <PrototypeEnvironment
31
+ prototypeUrl={prototype.url}
32
+ theme={prototype.theme}
33
+ themeRegistry={prototype.themeRegistry}
34
+ agentActions={agentActions}
35
+ >
36
+ {header}
37
+ {children}
38
+ </PrototypeEnvironment>
39
+ )
40
+ }
@@ -0,0 +1,4 @@
1
+ import { bonfire } from '@/bonfire'
2
+
3
+ export const runtime = 'nodejs'
4
+ export const GET = bonfire.prototypes.routes.dirty
@@ -0,0 +1,4 @@
1
+ import { bonfire } from '@/bonfire'
2
+
3
+ export const runtime = 'nodejs'
4
+ export const GET = bonfire.auth.routes.login
@@ -0,0 +1,4 @@
1
+ import { bonfire } from '@/bonfire'
2
+
3
+ export const runtime = 'nodejs'
4
+ export const POST = bonfire.auth.routes.logout
@@ -0,0 +1,4 @@
1
+ import { bonfire } from '@/bonfire'
2
+
3
+ export const runtime = 'nodejs'
4
+ export const GET = bonfire.auth.routes.status
@@ -0,0 +1,20 @@
1
+ import type { ReactNode } from 'react'
2
+ import { AppHeader } from '@ebay-dt/bonfire-react'
3
+ import { bonfire } from '@/bonfire'
4
+ import { openInClaudeCode, openInCursor } from '@/actions/agents'
5
+
6
+ export default async function SystemLayout({
7
+ children,
8
+ }: Readonly<{ children: ReactNode }>) {
9
+ const { headerProps } = await bonfire.auth.getAppLayoutModel()
10
+
11
+ return (
12
+ <>
13
+ <AppHeader
14
+ {...headerProps}
15
+ agentActions={{ openInClaudeCode, openInCursor }}
16
+ />
17
+ {children}
18
+ </>
19
+ )
20
+ }
@@ -0,0 +1,14 @@
1
+ import { GitHubCliLoginPage } from '@ebay-dt/bonfire-react'
2
+ import { bonfire } from '@/bonfire'
3
+ import type { Metadata } from 'next'
4
+
5
+ export const metadata: Metadata = { title: 'Sign in — Design Sandbox' }
6
+
7
+ type LoginPageProps = {
8
+ searchParams?: Promise<Record<string, string | string[] | undefined>>
9
+ }
10
+
11
+ export default async function LoginPage({ searchParams }: LoginPageProps) {
12
+ const model = await bonfire.auth.getLoginPageModel(searchParams)
13
+ return <GitHubCliLoginPage {...model} />
14
+ }
@@ -0,0 +1,33 @@
1
+ import { PrototypeDashboard } from '@ebay-dt/bonfire-react'
2
+ import { bonfire } from '@/bonfire'
3
+ import { openInClaudeCode, openInCursor } from '@/actions/agents'
4
+ import type { Metadata } from 'next'
5
+
6
+ interface PageProps {
7
+ searchParams: Promise<Record<string, string | string[] | undefined>>
8
+ }
9
+
10
+ export const metadata: Metadata = { title: 'Dashboard — Design Sandbox' }
11
+
12
+ export default async function DashboardPage({ searchParams }: PageProps) {
13
+ const [dashboard, user] = await Promise.all([
14
+ bonfire.prototypes.getDashboardModel(searchParams),
15
+ bonfire.auth.getCurrentUser(),
16
+ ])
17
+ const lifecycleEnabled = process.env.NODE_ENV !== 'production'
18
+
19
+ return (
20
+ <PrototypeDashboard
21
+ {...dashboard}
22
+ user={user}
23
+ {...(lifecycleEnabled
24
+ ? {
25
+ agentActions: {
26
+ openInCursor,
27
+ openInClaudeCode,
28
+ },
29
+ }
30
+ : {})}
31
+ />
32
+ )
33
+ }
@@ -0,0 +1,21 @@
1
+ import {
2
+ createItemDetailRoute,
3
+ type ItemRouteDiagnostic,
4
+ } from '@ebay-dt/bonfire-preset-ebay/data/items/server'
5
+ import { getItemById } from '@/lib/items/server'
6
+
7
+ function onDiagnostic({ operation, code }: ItemRouteDiagnostic) {
8
+ console.error(`Item ${operation} failed (${code}).`)
9
+ }
10
+
11
+ const handleItemDetail = createItemDetailRoute(
12
+ { getItemById },
13
+ { onDiagnostic }
14
+ )
15
+
16
+ export async function GET(
17
+ request: Request,
18
+ context: RouteContext<'/api/items/[itemId]'>
19
+ ) {
20
+ return handleItemDetail(request, context)
21
+ }
@@ -0,0 +1,11 @@
1
+ import {
2
+ createItemSearchRoute,
3
+ type ItemRouteDiagnostic,
4
+ } from '@ebay-dt/bonfire-preset-ebay/data/items/server'
5
+ import { searchItems } from '@/lib/items/server'
6
+
7
+ function onDiagnostic({ operation, code }: ItemRouteDiagnostic) {
8
+ console.error(`Item ${operation} failed (${code}).`)
9
+ }
10
+
11
+ export const GET = createItemSearchRoute({ searchItems }, { onDiagnostic })
@@ -0,0 +1,56 @@
1
+ import type { Metadata } from 'next'
2
+ import { NextLifecycleProvider } from '@ebay-dt/bonfire-next/client'
3
+ import { EbayDesignSystemProvider } from '@ebay-dt/bonfire-preset-ebay'
4
+ import { bonfire } from '@/bonfire'
5
+ import {
6
+ createPrototype,
7
+ deletePrototype,
8
+ discardPrototype,
9
+ duplicatePrototype,
10
+ editPrototype,
11
+ deployPrototype,
12
+ savePrototype,
13
+ } from '@/actions/prototypes'
14
+ import '@ebay-dt/bonfire-react/styles/defaults.css'
15
+ import '@ebay-dt/bonfire-preset-ebay/styles.css'
16
+
17
+ export const metadata: Metadata = {
18
+ title: 'Design Sandbox',
19
+ description: 'eBay Design Technology prototype sandbox',
20
+ icons: { icon: 'https://fav.farm/🤙' },
21
+ }
22
+
23
+ export default async function RootLayout({
24
+ children,
25
+ }: Readonly<{
26
+ children: React.ReactNode
27
+ }>) {
28
+ const lifecycleEnabled = process.env.NODE_ENV !== 'production'
29
+ const { htmlProps, headerProps } = await bonfire.auth.getAppLayoutModel()
30
+
31
+ return (
32
+ <html lang="en" {...htmlProps}>
33
+ <body>
34
+ <EbayDesignSystemProvider>
35
+ <NextLifecycleProvider
36
+ enabled={lifecycleEnabled}
37
+ deploymentAvailable={bonfire.prototypes.capabilities.deployment}
38
+ user={headerProps.user}
39
+ dirtyEndpoint="/api/prototype-dirty"
40
+ actions={{
41
+ create: createPrototype,
42
+ duplicate: duplicatePrototype,
43
+ edit: editPrototype,
44
+ delete: deletePrototype,
45
+ save: savePrototype,
46
+ discard: discardPrototype,
47
+ ...(lifecycleEnabled ? { deploy: deployPrototype } : {}),
48
+ }}
49
+ >
50
+ {children}
51
+ </NextLifecycleProvider>
52
+ </EbayDesignSystemProvider>
53
+ </body>
54
+ </html>
55
+ )
56
+ }
@@ -0,0 +1,25 @@
1
+ import 'server-only'
2
+ import { themes } from '@ebay-dt/bonfire-preset-ebay'
3
+ import { projectPrototypeContext } from '@ebay-dt/bonfire-context'
4
+ import {
5
+ createBonfireNext,
6
+ createDeploymentProvider,
7
+ } from '@ebay-dt/bonfire-next/server'
8
+ const deploymentProvider = createDeploymentProvider({
9
+ endpoint: 'https://dtsvc.vip.qa.ebay.com/dt/v1/bonfire-deploy',
10
+ })
11
+
12
+ export const bonfire = createBonfireNext({
13
+ appId: 'design-sandbox-next',
14
+ name: 'Design Sandbox',
15
+ auth: { github: { hostname: 'github.corp.ebay.com' } },
16
+ themes,
17
+ repositoryRoot: process.cwd(),
18
+ primaryBranch: process.env.BF_PROTOTYPE_BASE_BRANCH,
19
+ sessionSecret: process.env.BF_SESSION_SECRET,
20
+ disableAutoBranchSwitch: process.env.BF_DISABLE_AUTO_BRANCH_SWITCH,
21
+ deploymentProvider,
22
+ preparePrototypeFiles: async ({ prototypePath, repositoryRoot }) => {
23
+ await projectPrototypeContext({ repositoryRoot, prototypePath })
24
+ },
25
+ })
@@ -0,0 +1,100 @@
1
+ import { z } from 'zod'
2
+
3
+ const nullableString = z.string().nullable().optional()
4
+ const nullableNumber = z.number().nullable().optional()
5
+ const gatewayImageSchema = z.object({ imageUrl: nullableString }).nullable()
6
+ const gatewayPriceSchema = z
7
+ .object({
8
+ value: z.union([z.string(), z.number()]).nullable().optional(),
9
+ currency: nullableString,
10
+ convertedFromValue: z.union([z.string(), z.number()]).nullable().optional(),
11
+ })
12
+ .nullable()
13
+
14
+ export const gatewayErrorsSchema = z
15
+ .array(z.object({ message: nullableString }).passthrough())
16
+ .optional()
17
+
18
+ const gatewaySearchItemSchema = z
19
+ .object({
20
+ itemId: nullableString,
21
+ title: nullableString,
22
+ itemWebUrl: nullableString,
23
+ image: gatewayImageSchema.optional(),
24
+ condition: nullableString,
25
+ price: gatewayPriceSchema.optional(),
26
+ marketingPrice: z
27
+ .object({ originalPrice: gatewayPriceSchema.optional() })
28
+ .nullable()
29
+ .optional(),
30
+ })
31
+ .nullable()
32
+
33
+ export const gatewaySearchResponseSchema = z.object({
34
+ data: z
35
+ .object({
36
+ itemsBySearch: z
37
+ .object({
38
+ total: nullableNumber,
39
+ limit: nullableNumber,
40
+ offset: nullableNumber,
41
+ items: z.array(gatewaySearchItemSchema).nullable().optional(),
42
+ })
43
+ .nullable()
44
+ .optional(),
45
+ })
46
+ .optional(),
47
+ errors: gatewayErrorsSchema,
48
+ })
49
+
50
+ const gatewayItemSchema = z.object({
51
+ itemId: nullableString,
52
+ legacyItemId: nullableString,
53
+ title: nullableString,
54
+ bidCount: nullableNumber,
55
+ watchCount: nullableNumber,
56
+ brand: nullableString,
57
+ categories: z
58
+ .array(z.object({ categoryId: nullableString }).nullable())
59
+ .nullable()
60
+ .optional(),
61
+ categoryPath: nullableString,
62
+ color: nullableString,
63
+ conditionId: nullableString,
64
+ condition: nullableString,
65
+ conditionDescription: nullableString,
66
+ gender: nullableString,
67
+ image: gatewayImageSchema.optional(),
68
+ additionalImages: z.array(gatewayImageSchema).nullable().optional(),
69
+ localizedAspects: z
70
+ .array(
71
+ z
72
+ .object({
73
+ type: nullableString,
74
+ name: nullableString,
75
+ value: nullableString,
76
+ })
77
+ .nullable()
78
+ )
79
+ .nullable()
80
+ .optional(),
81
+ price: gatewayPriceSchema.optional(),
82
+ shippingOptions: z
83
+ .array(
84
+ z
85
+ .object({
86
+ shippingCarrierCode: nullableString,
87
+ quantityUsedForEstimate: nullableNumber,
88
+ trademarkSymbol: nullableString,
89
+ type: nullableString,
90
+ })
91
+ .nullable()
92
+ )
93
+ .nullable()
94
+ .optional(),
95
+ })
96
+
97
+ export const gatewayItemResponseSchema = z.object({
98
+ data: z.object({ item: gatewayItemSchema.nullable().optional() }).optional(),
99
+ errors: gatewayErrorsSchema,
100
+ })
@@ -0,0 +1,220 @@
1
+ import 'server-only'
2
+
3
+ import {
4
+ itemDetailSchema,
5
+ itemSearchPageSchema,
6
+ type ItemDetail,
7
+ type ItemSearchPage,
8
+ } from '@ebay-dt/bonfire-preset-ebay/data/items'
9
+ import {
10
+ gatewayItemResponseSchema,
11
+ gatewaySearchResponseSchema,
12
+ } from './gateway-schemas'
13
+
14
+ const DEFAULT_GATEWAY_URL = 'https://dtsvc.vip.qa.ebay.com/dt/v1/gateway-gql'
15
+
16
+ const SEARCH_QUERY = `
17
+ query Search($q: String!, $limit: Int!, $offset: Int!) {
18
+ itemsBySearch(q: $q, limit: $limit, offset: $offset) {
19
+ items {
20
+ itemId title itemWebUrl image { imageUrl } condition
21
+ price { value currency }
22
+ marketingPrice { originalPrice { value currency } }
23
+ }
24
+ total limit offset
25
+ }
26
+ }
27
+ `
28
+
29
+ const ITEM_QUERY = `
30
+ query ItemById($id: String!) {
31
+ item(id: $id) {
32
+ itemId legacyItemId title bidCount watchCount brand
33
+ categories { categoryId }
34
+ categoryPath color conditionId condition conditionDescription gender
35
+ image { imageUrl }
36
+ additionalImages { imageUrl }
37
+ localizedAspects { type name value }
38
+ price { convertedFromValue value }
39
+ shippingOptions {
40
+ shippingCarrierCode quantityUsedForEstimate trademarkSymbol type
41
+ }
42
+ }
43
+ }
44
+ `
45
+
46
+ async function requestGateway(
47
+ operationName: string,
48
+ query: string,
49
+ variables: Record<string, unknown>,
50
+ signal: AbortSignal
51
+ ): Promise<unknown> {
52
+ const endpoint = process.env.DT_GATEWAY_URL?.trim() || DEFAULT_GATEWAY_URL
53
+ const apiKey = process.env.DT_GATEWAY_API_KEY?.trim()
54
+ const response = await fetch(endpoint, {
55
+ method: 'POST',
56
+ headers: {
57
+ 'Content-Type': 'application/json',
58
+ ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
59
+ },
60
+ body: JSON.stringify({ operationName, query, variables }),
61
+ cache: 'no-store',
62
+ signal,
63
+ })
64
+
65
+ let result: unknown
66
+ try {
67
+ result = await response.json()
68
+ } catch {
69
+ throw new Error(`The item gateway returned HTTP ${response.status}.`)
70
+ }
71
+
72
+ if (!response.ok) {
73
+ throw new Error(`The item gateway returned HTTP ${response.status}.`)
74
+ }
75
+ return result
76
+ }
77
+
78
+ function graphQLError(errors?: Array<{ message?: string | null }>) {
79
+ return errors
80
+ ?.map(({ message }) => message)
81
+ .filter(Boolean)
82
+ .join('; ')
83
+ }
84
+
85
+ function optionalNumber(value: string | number | null | undefined) {
86
+ if (value == null || value === '') return undefined
87
+ const number = typeof value === 'number' ? value : Number(value)
88
+ return Number.isFinite(number) ? number : undefined
89
+ }
90
+
91
+ export async function searchItems(
92
+ query: string,
93
+ limit: number,
94
+ offset: number,
95
+ signal: AbortSignal
96
+ ): Promise<ItemSearchPage> {
97
+ const result = gatewaySearchResponseSchema.parse(
98
+ await requestGateway(
99
+ 'Search',
100
+ SEARCH_QUERY,
101
+ { q: query, limit, offset },
102
+ signal
103
+ )
104
+ )
105
+ const message = graphQLError(result.errors)
106
+ if (message) throw new Error(message)
107
+
108
+ const search = result.data?.itemsBySearch
109
+ return itemSearchPageSchema.parse({
110
+ total: search?.total ?? 0,
111
+ limit: search?.limit ?? limit,
112
+ offset: search?.offset ?? offset,
113
+ items:
114
+ search?.items?.flatMap((item) => {
115
+ if (!item?.itemId || !item.title || !item.itemWebUrl) return []
116
+ const priceValue = optionalNumber(item.price?.value)
117
+ const previousPriceValue = optionalNumber(
118
+ item.marketingPrice?.originalPrice?.value
119
+ )
120
+ return [
121
+ {
122
+ id: item.itemId,
123
+ title: item.title,
124
+ itemUrl: item.itemWebUrl,
125
+ imageUrl: item.image?.imageUrl ?? undefined,
126
+ condition: item.condition ?? undefined,
127
+ price:
128
+ priceValue != null && item.price?.currency
129
+ ? { value: priceValue, currency: item.price.currency }
130
+ : undefined,
131
+ previousPrice:
132
+ previousPriceValue != null &&
133
+ item.marketingPrice?.originalPrice?.currency
134
+ ? {
135
+ value: previousPriceValue,
136
+ currency: item.marketingPrice.originalPrice.currency,
137
+ }
138
+ : undefined,
139
+ },
140
+ ]
141
+ }) ?? [],
142
+ })
143
+ }
144
+
145
+ export async function getItemById(
146
+ itemId: string,
147
+ signal: AbortSignal
148
+ ): Promise<ItemDetail | null> {
149
+ const result = gatewayItemResponseSchema.parse(
150
+ await requestGateway('ItemById', ITEM_QUERY, { id: itemId }, signal)
151
+ )
152
+ const message = graphQLError(result.errors)
153
+ if (message) throw new Error(message)
154
+ const item = result.data?.item
155
+ if (!item) return null
156
+ if (!item.itemId || !item.title) {
157
+ throw new Error('The item gateway returned an incomplete item.')
158
+ }
159
+
160
+ const imageUrls = [
161
+ item.image?.imageUrl,
162
+ ...(item.additionalImages?.map((image) => image?.imageUrl) ?? []),
163
+ ].filter((url): url is string => Boolean(url))
164
+ const priceValue = optionalNumber(item.price?.value)
165
+ const convertedFromValue = optionalNumber(item.price?.convertedFromValue)
166
+
167
+ return itemDetailSchema.parse({
168
+ id: item.itemId,
169
+ legacyId: item.legacyItemId ?? undefined,
170
+ title: item.title,
171
+ images: [...new Set(imageUrls)].map((url) => ({ url })),
172
+ price:
173
+ priceValue == null
174
+ ? undefined
175
+ : { value: priceValue, convertedFromValue },
176
+ conditionId: item.conditionId ?? undefined,
177
+ condition: item.condition ?? undefined,
178
+ conditionDescription: item.conditionDescription ?? undefined,
179
+ brand: item.brand ?? undefined,
180
+ color: item.color ?? undefined,
181
+ gender: item.gender ?? undefined,
182
+ categoryPath:
183
+ item.categoryPath
184
+ ?.split('|')
185
+ .map((part) => part.trim())
186
+ .filter(Boolean) ?? [],
187
+ categoryIds:
188
+ item.categories?.flatMap((category) =>
189
+ category?.categoryId ? [category.categoryId] : []
190
+ ) ?? [],
191
+ aspects:
192
+ item.localizedAspects?.flatMap((aspect) =>
193
+ aspect?.name && aspect.value
194
+ ? [
195
+ {
196
+ name: aspect.name,
197
+ value: aspect.value,
198
+ type: aspect.type ?? undefined,
199
+ },
200
+ ]
201
+ : []
202
+ ) ?? [],
203
+ shippingOptions:
204
+ item.shippingOptions?.flatMap((option) =>
205
+ option
206
+ ? [
207
+ {
208
+ carrierCode: option.shippingCarrierCode ?? undefined,
209
+ quantityUsedForEstimate:
210
+ option.quantityUsedForEstimate ?? undefined,
211
+ trademarkSymbol: option.trademarkSymbol ?? undefined,
212
+ type: option.type ?? undefined,
213
+ },
214
+ ]
215
+ : []
216
+ ) ?? [],
217
+ bidCount: item.bidCount ?? undefined,
218
+ watchCount: item.watchCount ?? undefined,
219
+ })
220
+ }
@@ -0,0 +1,8 @@
1
+ import { bonfire } from '@/bonfire'
2
+
3
+ export const proxy = bonfire.auth.proxy
4
+
5
+ export const config = {
6
+ // Run on all routes except Next.js internals and static assets
7
+ matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
8
+ }