Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/expo/app/auth/(login)/reset-password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export default function ResetPasswordScreen() {
setIsLoading(true);

// Call the API to reset the password
await resetPassword(params.email, params.code, value.password);
await resetPassword(params.email, { code: params.code, newPassword: value.password });

// Show success message and navigate to login
Alert.alert(t('common.success'), t('auth.resetPasswordSuccess'), [
Expand Down
3 changes: 2 additions & 1 deletion apps/expo/features/auth/hooks/useAuthActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ export function useAuthActions() {
}
};

const resetPassword = async (email: string, code: string, newPassword: string) => {
const resetPassword = async (email: string, opts: { code: string; newPassword: string }) => {
const { code, newPassword } = opts;
try {
const response = await fetch(`${clientEnvs.EXPO_PUBLIC_API_URL}/api/auth/reset-password`, {
method: 'POST',
Expand Down
12 changes: 8 additions & 4 deletions apps/expo/features/catalog/hooks/useSimilarItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ export const getSimilarCatalogItems = async (
// API function for pack item similar items
export const getSimilarPackItems = async (
packId: string,
itemId: string,
params?: SimilarItemsParams,
opts: { itemId: string; params?: SimilarItemsParams },
): Promise<{ items: SimilarItem[]; total: number; sourceItem: PackItem }> => {
const { itemId, params } = opts;
try {
const queryParams = new URLSearchParams();
if (params?.limit) queryParams.append('limit', params.limit.toString());
Expand Down Expand Up @@ -72,12 +72,16 @@ export function useSimilarCatalogItems(id: string, params?: SimilarItemsParams)
}

// Hook for pack item similar items
export function useSimilarPackItems(packId: string, itemId: string, params?: SimilarItemsParams) {
export function useSimilarPackItems(
packId: string,
opts: { itemId: string; params?: SimilarItemsParams },
) {
const { itemId, params } = opts;
const { isQueryEnabledWithAccessToken } = useAuthenticatedQueryToolkit();

return useQuery({
queryKey: ['similarPackItems', packId, itemId, params],
queryFn: () => getSimilarPackItems(packId, itemId, params),
queryFn: () => getSimilarPackItems(packId, { itemId, params }),
enabled: isQueryEnabledWithAccessToken && !!packId && !!itemId,
staleTime: 5 * 60 * 1000, // 5 minutes
});
Expand Down
9 changes: 6 additions & 3 deletions apps/expo/features/packs/components/GapSuggestion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ export function GapSuggestion({ gap, packId }: GapSuggestionProps) {
});

const handleAddItem = async (item: CatalogItem) => {
await addItemToPack(packId, item, {
consumable: gap.consumable,
worn: gap.worn,
await addItemToPack(packId, {
catalogItem: item,
data: {
consumable: gap.consumable,
worn: gap.worn,
},
});
setCatalogSuggestionsModalVisible(false);
setIsAddressed(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ export const SimilarItemsForPackItem: React.FC<SimilarItemsForPackItemProps> = (
}) => {
const { t } = useTranslation();
const router = useRouter();
const { data, isLoading, isError } = useSimilarPackItems(packId, itemId, {
limit,
threshold,
const { data, isLoading, isError } = useSimilarPackItems(packId, {
itemId,
params: { limit, threshold },
});

const handleItemPress = (catalogItemId: string) => {
Expand Down
4 changes: 2 additions & 2 deletions apps/expo/features/packs/hooks/useAddCatalogItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export function useAddCatalogItem() {

const addItemToPack = async (
packId: string,
catalogItem: CatalogItem,
data?: Partial<PackItem>,
opts: { catalogItem: CatalogItem; data?: Partial<PackItem> },
) => {
const { catalogItem, data } = opts;
setIsLoading(true);
const cachedImageFilename = await cacheCatalogItemImage(catalogItem.images?.[0]);

Expand Down
9 changes: 5 additions & 4 deletions apps/guides/components/ui/chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ const ChartTooltipContent = React.forwardRef<
const [item] = payload;
assertDefined(item);
const key = `${labelKey || item.dataKey || item.name || 'value'}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const itemConfig = getPayloadConfigFromPayload(config, { payload: item, key });
const value =
!labelKey && typeof label === 'string'
? config[label as keyof typeof config]?.label || label
Expand Down Expand Up @@ -171,7 +171,7 @@ const ChartTooltipContent = React.forwardRef<
<div className="grid gap-1.5">
{payload.map((item, index) => {
const key = `${nameKey || item.name || item.dataKey || 'value'}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const itemConfig = getPayloadConfigFromPayload(config, { payload: item, key });
const indicatorColor = color || item.payload.fill || item.color;

return (
Expand Down Expand Up @@ -267,7 +267,7 @@ const ChartLegendContent = React.forwardRef<
>
{payload.map((item) => {
const key = `${nameKey || item.dataKey || 'value'}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const itemConfig = getPayloadConfigFromPayload(config, { payload: item, key });

return (
<div
Expand Down Expand Up @@ -296,7 +296,8 @@ const ChartLegendContent = React.forwardRef<
ChartLegendContent.displayName = 'ChartLegend';

// Helper to extract item config from a payload.
function getPayloadConfigFromPayload(config: ChartConfig, payload: unknown, key: string) {
function getPayloadConfigFromPayload(config: ChartConfig, opts: { payload: unknown; key: string }) {
const { payload, key } = opts;
if (typeof payload !== 'object' || payload === null) {
return undefined;
}
Expand Down
12 changes: 6 additions & 6 deletions apps/guides/scripts/enhance-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ function parseContentFile(filePath: string): {

function writeEnhancedContent(
filePath: string,
metadata: Record<string, unknown>,
enhancedContent: string,
opts: { metadata: Record<string, unknown>; enhancedContent: string },
): void {
const { metadata, enhancedContent } = opts;
const newFileContent = matter.stringify(enhancedContent, metadata);
fs.writeFileSync(filePath, newFileContent, 'utf8');
}
Expand All @@ -153,13 +153,13 @@ function writeEnhancedContent(

async function enhanceFile(
filePath: string,
options: CliOptions,
enhancementOptions: ContentEnhancementOptions,
opts: { cliOptions: CliOptions; enhancementOptions: ContentEnhancementOptions },
): Promise<{
enhanced: boolean;
productsAdded: number;
error?: string;
}> {
const { cliOptions: options, enhancementOptions } = opts;
try {
const fileName = path.basename(filePath);

Expand Down Expand Up @@ -212,7 +212,7 @@ async function enhanceFile(
}

// Write enhanced content
writeEnhancedContent(filePath, metadata, result.content);
writeEnhancedContent(filePath, { metadata, enhancedContent: result.content });

console.log(
chalk.green(` ✅ Enhanced ${fileName} with ${result.productsUsed.length} product links`),
Expand Down Expand Up @@ -282,7 +282,7 @@ async function enhanceContent(cliOptions: CliOptions): Promise<void> {
for (const filePath of filesToProcess) {
stats.processed++;

const result = await enhanceFile(filePath, cliOptions, enhancementOptions);
const result = await enhanceFile(filePath, { cliOptions, enhancementOptions });

if (result.error) {
stats.errors++;
Expand Down
6 changes: 3 additions & 3 deletions apps/guides/scripts/generate-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ function getExistingContent(): ContentMetadata[] {
// Generate topic ideas based on categories and existing content
async function generateTopicIdeas(
count: number,
categories?: ContentCategory[],
existingContent: ContentMetadata[] = [],
opts: { categories?: ContentCategory[]; existingContent?: ContentMetadata[] } = {},
): Promise<ContentMetadata[]> {
const { categories, existingContent = [] } = opts;
console.log(chalk.blue(`Generating ${count} topic ideas...`));

const categoryPrompt =
Expand Down Expand Up @@ -421,7 +421,7 @@ async function generatePosts(count: number, categories?: ContentCategory[]): Pro
console.log(chalk.blue(`Found ${existingContent.length} existing articles`));

// Generate topic ideas with awareness of existing content
const topics = await generateTopicIdeas(count, categories, existingContent);
const topics = await generateTopicIdeas(count, { categories, existingContent });
console.log(chalk.green(`✓ Generated ${topics.length} topic ideas`));

// Generate content for each topic
Expand Down
3 changes: 2 additions & 1 deletion packages/analytics/src/core/query-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,8 @@ export class QueryBuilder {
`;
}

trendsQuery(keyword: string, sites?: string[], days = 90): string {
trendsQuery(keyword: string, opts: { sites?: string[]; days?: number } = {}): string {
const { sites, days = 90 } = opts;
const source = SQLFragments.readCsvSource(this.bucketPath);
const kw = SQLFragments.escapeSql(keyword.toLowerCase());

Expand Down
2 changes: 1 addition & 1 deletion packages/analytics/test/core/query-builder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ describe('QueryBuilder', () => {
});

it('uses custom days parameter', () => {
const sql = qb.trendsQuery('tent', undefined, 30);
const sql = qb.trendsQuery('tent', { days: 30 });
expect(sql).toContain("INTERVAL '30 days'");
});
});
Expand Down
20 changes: 11 additions & 9 deletions packages/api/container_src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ const TikTokImportSchema = z.object({
*/
function detectMediaTypeAndExtension(
response: Response,
buffer?: ArrayBuffer,
isVideo = false,
opts: { buffer?: ArrayBuffer; isVideo?: boolean } = {},
): {
contentType: string;
extension: string;
} {
const { buffer, isVideo = false } = opts;
// Try to get content type from headers first
const headerContentType = response.headers.get('content-type');

Expand Down Expand Up @@ -169,9 +169,9 @@ function detectMediaTypeAndExtension(
*/
async function downloadAndRehostImage(
imageUrl: string,
contentId: string,
index: number,
opts: { contentId: string; index: number },
): Promise<string | null> {
const { contentId, index } = opts;
if (!s3Client || !env) {
console.warn('R2 client not available, skipping image rehosting');
return null;
Expand Down Expand Up @@ -202,7 +202,9 @@ async function downloadAndRehostImage(
const imageBuffer = await response.arrayBuffer();

// Detect the actual image type and extension
const { contentType, extension } = detectMediaTypeAndExtension(response, imageBuffer, false);
const { contentType, extension } = detectMediaTypeAndExtension(response, {
buffer: imageBuffer,
});

const timestamp = Date.now();
const imageKey = `tiktok-temp/${contentId}/${timestamp}-${index}.${extension}`;
Expand Down Expand Up @@ -264,7 +266,7 @@ async function uploadVideoToGoogle(videoUrl: string): Promise<string | null> {
console.log(`Video uploaded to Google AI. File URI: ${myfile.uri}, name: ${myfile.name}`);
// Wait for ACTIVE state
if (!myfile.name) throw new Error('Google AI upload did not return a file name');
await waitForFileToBeActiveGoogle(googleAi, myfile.name);
await waitForFileToBeActiveGoogle(googleAi, { fileName: myfile.name });
return myfile.uri || null;
} catch (error) {
console.error('Failed to upload video to Google:', error);
Expand All @@ -277,9 +279,9 @@ async function uploadVideoToGoogle(videoUrl: string): Promise<string | null> {
*/
async function waitForFileToBeActiveGoogle(
ai: GoogleGenAI,
fileName: string,
maxWaitTimeMs: number = 300000,
opts: { fileName: string; maxWaitTimeMs?: number },
): Promise<void> {
const { fileName, maxWaitTimeMs = 300000 } = opts;
const startTime = Date.now();
while (Date.now() - startTime < maxWaitTimeMs) {
const fileInfo = await ai.files.get({ name: fileName });
Expand Down Expand Up @@ -322,7 +324,7 @@ async function downloadAndRehostImages(

// Process all images in parallel with best effort approach
const results = await Promise.allSettled(
imageUrls.map((url, index) => downloadAndRehostImage(url, contentId, index)),
imageUrls.map((url, index) => downloadAndRehostImage(url, { contentId, index })),
);

const rehostedUrls: string[] = [];
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/routes/catalog/vectorSearchRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const handler: RouteHandler<typeof routeDefinition> = async (c) => {
const { q: query, limit = 10, offset = 0 } = c.req.valid('query');

const catalogService = new CatalogService(c);
const result = await catalogService.vectorSearch(query, limit, offset);
const result = await catalogService.vectorSearch(query, { limit, offset });

return c.json(result, 200);
} catch (error) {
Expand Down
5 changes: 3 additions & 2 deletions packages/api/src/routes/packs/analyzeImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ analyzeImageRoutes.openapi(analyzeImageRoute, async (c) => {
Bucket: PACKRAT_BUCKET_R2_BUCKET_NAME,
Key: image,
});
const imageUrl = await getPresignedUrl(c, command, {
expiresIn: 3600,
const imageUrl = await getPresignedUrl(c, {
command,
signOptions: { expiresIn: 3600 },
});

const imageDetectionService = new ImageDetectionService(c);
Expand Down
5 changes: 3 additions & 2 deletions packages/api/src/routes/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,9 @@ uploadRoutes.openapi(presignedRoute, async (c) => {
});

// Generate the presigned URL
const presignedUrl = await getPresignedUrl(c, command, {
expiresIn: 3600,
const presignedUrl = await getPresignedUrl(c, {
command,
signOptions: { expiresIn: 3600 },
});

return c.json(
Expand Down
8 changes: 4 additions & 4 deletions packages/api/src/services/__tests__/catalogService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ describe('CatalogService', () => {
});

it('returns empty result for empty query string', async () => {
const result = await service.vectorSearch('', 10, 0);
const result = await service.vectorSearch('', { limit: 10, offset: 0 });

expect(result).toEqual({
items: [],
Expand All @@ -106,7 +106,7 @@ describe('CatalogService', () => {
});

it('returns empty result for whitespace-only query', async () => {
const result = await service.vectorSearch(' ', 10, 0);
const result = await service.vectorSearch(' ', { limit: 10, offset: 0 });

expect(result).toEqual({
items: [],
Expand All @@ -121,7 +121,7 @@ describe('CatalogService', () => {
it('returns empty result when embedding generation fails', async () => {
vi.mocked(embeddingService.generateEmbedding).mockResolvedValueOnce(null);

const result = await service.vectorSearch('tent', 10, 0);
const result = await service.vectorSearch('tent', { limit: 10, offset: 0 });

expect(result).toEqual({
items: [],
Expand All @@ -148,7 +148,7 @@ describe('CatalogService', () => {
// We can't fully test the DB query without a real/mocked database,
// but we can verify the embedding generation was called correctly
try {
await service.vectorSearch('lightweight tent', 10, 0);
await service.vectorSearch('lightweight tent', { limit: 10, offset: 0 });
} catch (err) {
// DB query will fail since we don't have a proper mock, but that's OK
// We're just testing the input validation and embedding call
Expand Down
4 changes: 2 additions & 2 deletions packages/api/src/services/catalogService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,15 @@ export class CatalogService {

async vectorSearch(
q: string,
limit: number = 10,
offset: number = 0,
opts: { limit?: number; offset?: number } = {},
): Promise<{
items: (Omit<CatalogItem, 'embedding'> & { similarity: number })[];
total: number;
limit: number;
offset: number;
nextOffset: number;
}> {
const { limit = 10, offset = 0 } = opts;
if (!q || q.trim() === '') {
return {
items: [],
Expand Down
4 changes: 2 additions & 2 deletions packages/api/src/utils/ai/logging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ export interface AIRequestLog {

export function logAIRequest(
env: Env,
headers: Headers,
options: Partial<AIRequestLog>,
opts: { headers: Headers; log: Partial<AIRequestLog> },
): AIRequestLog {
const { headers, log: options } = opts;
const log: AIRequestLog = {
provider: env.AI_PROVIDER || 'openai',
model: options.model || 'gpt-4o',
Expand Down
5 changes: 4 additions & 1 deletion packages/api/src/utils/ai/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,10 @@ export function createTools(c: Context, userId: number) {
}),
execute: async ({ query, limit, offset }) => {
try {
const data = await catalogService.vectorSearch(query, limit || 10, offset || 0);
const data = await catalogService.vectorSearch(query, {
limit: limit || 10,
offset: offset || 0,
});
return {
success: true,
data,
Expand Down
Loading
Loading