export type WithExtras = T & Record; export interface ThemeFile { filename: string; content: string; type: 'liquid' | 'css' | 'js' | 'json' | 'other'; path: string; } export interface ThemeStructure { themeId: string; shopId: string; } export interface ThemeFileUpdate { filename: string; body: { type: 'TEXT'; value: string; }; } export interface LighthouseExtractedData { // General Information lighthouseVersion?: string; requestedUrl?: string; fetchTime?: string; userAgent?: string; overallPerformanceScore?: number; // Core Metrics - First Contentful Paint fcpValue?: number; fcpDisplay?: string; fcpScore?: number; // Core Metrics - Largest Contentful Paint lcpValue?: number; lcpDisplay?: string; lcpScore?: number; // Core Metrics - Total Blocking Time tbtValue?: number; tbtDisplay?: string; tbtScore?: number; // Core Metrics - Cumulative Layout Shift clsValue?: number; clsDisplay?: string; clsScore?: number; // Core Metrics - Speed Index speedIndexValue?: number; speedIndexDisplay?: string; speedIndexScore?: number; // Core Metrics - Time to Interactive ttiValue?: number; ttiDisplay?: string; ttiScore?: number; // Core Metrics - Max Potential FID maxPotentialFidValue?: number; maxPotentialFidDisplay?: string; maxPotentialFidScore?: number; // Core Metrics - First Meaningful Paint fmpScore?: number; fmpDisplay?: string; // Server and Network Performance serverResponseTimeValue?: number; serverResponseTimeDisplay?: string; serverResponseTimeSavingsMs?: number; networkRttScore?: number; networkRttValue?: number; networkRttDisplay?: string; networkServerLatencyScore?: number; networkServerLatencyValue?: number; networkServerLatencyDisplay?: string; // Critical Request Chains criticalRequestChainsDisplay?: string; criticalRequestChainsLongestDuration?: number; criticalRequestChainsData?: string; longestChainDuration?: number; longestChainLength?: number; longestChainTransferSize?: number; // Main Thread Performance mainThreadWorkValue?: number; mainThreadWorkDisplay?: string; mainThreadWorkDetails?: string; jsExecutionTimeValue?: number; jsExecutionTimeDisplay?: string; jsExecutionTimeDetails?: string; // Resource Optimization Opportunities usesRelPreconnectScore?: number; fontDisplayScore?: number; totalByteWeightValue?: number; totalByteWeightDisplay?: string; // Image Optimization deferOffscreenImagesScore?: number; deferOffscreenImagesSavingsBytes?: number; deferOffscreenImagesSavingsMs?: number; deferOffscreenImagesDetails?: string; serveImagesNextGenFormatsScore?: number; serveImagesNextGenFormatsSavingsBytes?: number; serveImagesNextGenFormatsSavingsMs?: number; serveImagesNextGenFormatsDetails?: string; properlySizeImagesScore?: number; properlySizeImagesSavingsBytes?: number; properlySizeImagesSavingsMs?: number; properlySizeImagesDetails?: string; usesOptimizedImagesScore?: number; usesOptimizedImagesSavingsBytes?: number; usesOptimizedImagesSavingsMs?: number; usesOptimizedImagesDetails?: string; // CSS/JS Optimization eliminateRenderBlockingResourcesScore?: number; eliminateRenderBlockingResourcesSavingsMs?: number; eliminateRenderBlockingResourcesDetails?: string; minifyCssScore?: number; minifyCssSavingsBytes?: number; minifyCssSavingsMs?: number; minifyCssDetails?: string; minifyJavaScriptScore?: number; minifyJavaScriptSavingsBytes?: number; minifyJavaScriptSavingsMs?: number; minifyJavaScriptDetails?: string; reduceUnusedCssScore?: number; reduceUnusedCssSavingsBytes?: number; reduceUnusedCssSavingsMs?: number; reduceUnusedCssDetails?: string; reduceUnusedJavaScriptScore?: number; reduceUnusedJavaScriptSavingsBytes?: number; reduceUnusedJavaScriptSavingsMs?: number; reduceUnusedJavaScriptDetails?: string; duplicatedJavaScriptScore?: number; duplicatedJavaScriptSavingsBytes?: number; duplicatedJavaScriptSavingsMs?: number; duplicatedJavaScriptDetails?: string; legacyJavaScriptScore?: number; legacyJavaScriptSavingsBytes?: number; legacyJavaScriptSavingsMs?: number; legacyJavaScriptDetails?: string; // Content Compression usesTextCompressionScore?: number; usesTextCompressionSavingsBytes?: number; usesTextCompressionSavingsMs?: number; usesTextCompressionDetails?: string; efficientAnimatedContentScore?: number; efficientAnimatedContentSavingsBytes?: number; efficientAnimatedContentSavingsMs?: number; efficientAnimatedContentDetails?: string; // LCP Optimization lcpLazyLoadedScore?: number; lcpLazyLoadedSavingsMs?: number; lcpLazyLoadedDetails?: string; prioritizeLcpImageScore?: number; prioritizeLcpImageSavingsMs?: number; prioritizeLcpImageDetails?: string; largestContentfulPaintElementScore?: number; largestContentfulPaintElementDisplay?: string; largestContentfulPaintElementDetails?: string; // Caching usesLongCacheTtlScore?: number; usesLongCacheTtlSavingsBytes?: number; usesLongCacheTtlDetails?: string; // Layout and Animations layoutShiftsScore?: number; layoutShiftsDisplay?: string; layoutShiftsDetails?: string; nonCompositedAnimationsScore?: number; nonCompositedAnimationsDisplay?: string; nonCompositedAnimationsDetails?: string; // DOM and Performance domSizeValue?: number; domSizeDisplay?: string; domSizeDetails?: string; longTasksScore?: number; longTasksDisplay?: string; longTasksDetails?: string; longTasksCount?: number; longestTaskDuration?: number; // Third Party thirdPartySummaryScore?: number; thirdPartySummaryDisplay?: string; thirdPartySummaryDetails?: string; thirdPartyFacadesScore?: number; thirdPartyFacadesDetails?: string; // Other Optimization Opportunities redirectsScore?: number; redirectsSavingsMs?: number; redirectsCount?: number; redirectsChain?: string; usesPassiveEventListenersScore?: number; noDocumentWriteScore?: number; unsizedImagesScore?: number; viewportScore?: number; viewportExplanation?: string; // Diagnostic Metrics userTimingsScore?: number; userTimingsDisplay?: string; mainThreadTasksScore?: number; mainThreadTasksDetails?: string; diagnosticsScore?: number; diagnosticsDetails?: string; metricsScore?: number; metricsValue?: number; metricsDisplay?: string; metricsDetails?: string; scriptTreemapDataScore?: number; scriptTreemapDataDetails?: string; resourceSummaryScore?: number; resourceSummaryDetails?: string; // Environment and Warnings runWarnings?: string; benchmarkIndex?: number; networkUserAgent?: string; mainDocumentUrl?: string; finalDisplayedUrl?: string; finalUrl?: string; // Enhanced Network and Resource Analysis jsFilesCount?: number; cssFilesCount?: number; imageFilesCount?: number; fontFilesCount?: number; thirdPartyFilesCount?: number; jsFilesDetails?: string; cssFilesDetails?: string; imageFilesDetails?: string; thirdPartyFilesDetails?: string; totalJsSize?: number; totalCssSize?: number; totalImageSize?: number; totalThirdPartySize?: number; // Enhanced Performance Metrics observedDomContentLoaded?: number; observedLoad?: number; observedFirstPaint?: number; observedFirstContentfulPaint?: number; observedLargestContentfulPaint?: number; observedTraceEnd?: number; [key: string]: any; } export interface ThemeFileMetadata { themeId: string; shopId: string; filename: string; filePath: string; fileType: string; content: string; importedAt: string; fileSize: number; } export interface SearchOptions { themeId?: string; shopId?: string; fileTypes?: string[]; limit?: number; certainty?: number; } export interface ImportData { className: string; objects: Array<{ properties: Record; vectors?: number[]; }>; } export interface ImportOptions { enableTextChunking?: boolean; textChunkingOptions?: TextChunkingOptions; batchSize?: number; } export type SupportedEncoding = 'cl100k_base' | 'p50k_base' | 'r50k_base' | 'gpt2'; export interface TextChunkingOptions { maxTokens?: number; chunkOverlap?: number; encodingName?: SupportedEncoding; } export interface ChunkedObject { properties: Record; vectors?: number[]; originalIndex?: number; chunkIndex?: number; totalChunks?: number; } export type FileUploadType = 'liquid' | 'css' | 'js' | 'json' | 'other'; export type ChangeLogType = 'updateThemeFile' | 'updateSettings'; export type ChangeLog = { createdAt: Date; changeType: ChangeLogType; details: ChangeLogUpdateThemeFile | ChangeLogUpdateSettings; }; export type ChangeLogUpdateThemeFile = { themeId: string; themeFiles: ThemeFileUpdate[]; }; export type ChangeLogUpdateSettings = { content: string; }; export type DataSchemaUpdate = { type: string; value: boolean; }; export type GSDInput = { customerRequest: string; missingField: string; schemaType: string; sgdThemeFile: string; }; export type SitemapGetSettingInput = { type?: 'xml' | 'html' | string; }; export type UpdateSettingInput = { type?: 'xml' | 'html' | string; value: boolean; }; export type Shop = { id: string; avatarShop: string; shopOwner: string; accessToken: string; accessTokenHash: string; appStatus: boolean; excludeSendEmail: boolean; countProductImage: number; countMetaTagsOptimize: number; deviceABTesting: string; domain: string; doneArticle: boolean; doneCollection: boolean; doneProduct: boolean; doneImage: boolean; doneOptimize: boolean; doneAllOptimizeAt: Date; doneOtherImage: boolean; email: string; google: boolean; hasNewAct: boolean; noLimitOptimizeImages?: boolean; inTestMode: boolean; isReverting: boolean; isSubscribed: boolean; installedAt: Date; installedAtTest: Date | string; isInstalled: boolean; isRated: boolean; showRemoveCode: boolean; showEmbedAuditSkipButton: boolean; isTrialUsed: boolean; // check if shop has been on trial yet. If true, shop have used trial but might have some trial days remaining doneProductLastId: string; // the last success cursor to start retry optimize image from if error occurs doneProductLineNo: string; name: string; noLimit: boolean; plan: ShopPlan | string; planInterval: IPlanInterval; trialEndsAt: Date | any; usedTrialDays: number; savedTime: number; savedCost: number; setupDone: boolean; setupDoneAt: Date; setupDoneOffset: number; settings: any; shopifyDomain: string; shopifyCountry: string; shopifyPlan: | 'trial' | 'affiliate' | 'partner_test' | 'staff' | 'shopify_plus' | 'basic' | 'professional' | 'advanced'; status: boolean; subStartAt: Date; startOptimizeAt: Date; subscriptionDate: Date; totalProductCount: number; totalProductImageCount: number; reviewApps: []; reviewPrimaryApp: string; uid: string; uninstalled: boolean; vendor: string; unlockFeatures: boolean; ignoreNewLimit: boolean; // bypass limit for features: Lazy load and Minify createdAt: Date; // from shopInfo proLegacy: boolean; // check if shop can upgrade to plan Pro_21 planDiscountCode: string; planDiscountCycle: number; promoType: IPromoType; promoShowAt: Date; promoLastPromptAt: Date; promoCountdownOffset: number; promoUsed: boolean; // check if shop upgraded with promotion previously promoSpecialOfferDelayType: '1 hour' | '1 day' | '3 day'; // A/B testing special offer delay time unlockSpeedUp: boolean; // check if this is a merchant store that runs real business, not a Shopify development/test store // this can also be true if the store belongs to avada.io or mageplaza.com user isNonDevShop: boolean; isLimitOptimizeUrl: boolean; isLimitImage: boolean; // limit optimize image by image count (if true) or product count (if false). true by default for new shop optimizingWarning: boolean; startRevertingAt: Date; doneRevertingAt: Date; promoBFCMUsed: boolean; promoBFCMCountdownOffset: number; isAvailableBFCMPromo: boolean; // status bfcm offer promoBFCMOfferDelayType: '3 minute' | '10 minute' | '20 minute'; // A/B testing bfcm offer delay time ; promoBFCMShowAt: Date; accessAppAt: Date; promoSaleSeasonShowAt: Date; // for new year sale promoSaleSeasonCountdownOffset: number; // for new year sale promoSaleSeasonUsed: boolean; // for new year sale promoSaleSeasonOfferDelayType: '3 minute' | '10 minute' | '20 minute'; // for new year sale isAvailableSaleSeasonPromo: boolean; // for new year sale promoSaleSeasonOffset: number; // for new year sale isFirstLogin: boolean; isAvailableValentineSale: boolean; // for valentine sale promoValentineSaleOfferDelayType: '3 minute'; // for valentine sale promoValentineSaleShowAt: Date; // for valentine sale promoValentineSaleUsed: boolean; // for valentine sale promoValentineSaleOffset: number; // for valentine sale promoValentineSaleCountdownOffset: number; // for valentine sale hasEverSubscribed: boolean; isAvailableHolidaySalePromo: boolean; promoHolidaySaleOfferDelayType: '3 minute'; promoHolidaySaleCountdownOffset: number; promoHolidaySaleOffset: number; promoHolidaySaleShowAt: Date; promoHolidaySaleUsed: boolean; isSendEmailPendingCharge: boolean; isAvailableSiteOS2: boolean; isAddSlashSiteMapUrl: boolean; // check if should add slash to sitemap url useEmbedBlock: boolean; appInstallationId: string; isUpdatingAsset: boolean; hasBackup: boolean; isRevertingTheme: boolean; isShowBannerBackup: boolean; backupAt: Date; isUnlimitedOptimizeOnTrial: boolean; isStoreGoToChargeGH: boolean; directUpgrade: boolean; hasStarterPlan: boolean; enterpriseLegacy: boolean; promoStickyShow: boolean | Date; totalLine: number; timeExecuteLoadJs: number; speedScoreTest: number; analysisUrl: string; allCheckList: 'warning' | 'success' | 'error'; /** * @trello https://trello.com/c/gkziMZt2 * Skip optimize handler */ excludeHandlers: string[]; /** * Check if function api, apiSa should use Firebase functions V2 for better speed */ useApiFunctionsV2: boolean; trialDaysExtend: number; /** * Check if should use lighthouse running on Firebase Functions V2 to scan or use PageSpeed API to get Lighthouse score */ useLocalMachineScan: boolean; // optimizedProductIdsMonthly: number; // Ids of product that have been image optimized in the month lastScanChecklist: Date; passwordQuery: string; passwordStore: string; newProductsOptimizeAt: Date; /** * Check if should pubsub for functions v1 or v2 for subscribeOptimize */ useOptimizerV1: false; /** * @link https://trello.com/c/IdRrBAqC */ bfcmBrPopup23Show: boolean; bfcmBr23Show: boolean; is365Trial: boolean; hiddenBannerMigrateScriptManager: boolean; /** * @description * Admin UI language for the shop * @link https://trello.com/c/IGQYlmJw */ adminLocale: string; primaryLocale: string; // Shop locale from shop info isCrmLogin: boolean; dismissedBanners: dismissedBannersType[]; /** * Fake score lighthouse */ scoreDesktop: string; scoreMobile: string; //Shop show report size after optimized isShowReport: boolean; auditLocale: string; // custom audit language closeAppWidget: boolean; firstOTMSendChatAt: Date; // time first optimize shop free lastOTM100DevZone: Date; // only devXone - optimize 100 IMAGE lastOTMAllDevZone: Date; // only devXone - optimize all IMAGE secondOTMSendChatAt: Date; showAdvancedPageSpeed: boolean; AIUsage: {metaCount: number; metaExtraLimit: number}; lastHistoryIds: object; historyId: string; optimizingType: object; isSkipOptimizeFilename: boolean; downgradeProcessId: string; isNewChat: boolean; // support customer new chat, isShowBannerBestSeller: true; /** * Tap affiliate for agency */ tapAffReferralCode: string; tapAffiliateProcessed: boolean; specific404Locations: string; }; export type UpdatedCoupon = { code: string; discountValue: number; validFor: string; discountType: 'percentage' | string; maxUses: number; createdAt: Date; shopId: string; customerName: string; }; export type SaleInput = { messages: Array<{ content?: string; role?: string; timestamp?: any; }>; };