@zorgo/next 1.1.1 → 1.1.2

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.
package/dist/server.mjs CHANGED
@@ -1 +1,422 @@
1
- function a0_0x46b6(){const _0x3315d7=['i0y1rJvgnq','DgftEKi','C3rHDhvZ','iGPJDxn0B21Fzg9TywLUid0GDhj1zqOkw1TYB3v0zxnDxqPWyxr0zxjUid0GiND3DY4','zNjVBq','CKn2zvK','C2L0zsb0B2TLBIbPCYbUB3qGysb3zwXSlwzVCM1Lzcbkv1qGkg5VihbHEwXVywqGC2vNBwvUDcK','CvPiDxe','ChvIBgLJl2LTywDLCY8','CgfYC2u','ifjLC3bVBNnLoIa','ChjPBwfYEq','q291BgqGBM90ihjLywnOihrOzsbZAxrLlxrVA2vUigvUzhbVAw50igf0ia','ywnJzw50','ChjLyNvPBgq6igzYyw5JAgLZzsbOyxmGBM8GBwvUDsbPDgvTCYb5zxqG4OcuigDLBMvYyxrPBMCGyw4Gzw1WDhKGBwvUDs4GqwrKigL0zw1ZigLUihrOzsbKyxnOyM9HCMqGyw5KihjLyNvPBgqGDg8GCg9WDwXHDguGDgHLihn0B3jLzNjVBNqU','nty4ntHsCe1TC2G','Bg9NBY5WBMC','Dg9tDhjPBMC','D3jHBMDSzxiUDg9TBa','rKPmAfi','oWOGic0TzM9UDc1Zyw5ZoIaI','DMfYAwfUDhm','Ahr0Chm6lY9Zy2HLBweUB3jN','iGPTywLUid0GiI5VCgvUlw5LEhqVD29YA2vYlMPZiGPJB21WyxrPyMLSAxr5x2rHDguGpsaImJaYnc0Wos0YmYiky29TCgf0AwjPBgL0Ev9MBgfNCYa9ifSIBM9KzwPZx2nVBxbHDcjDcGOJiej1BMrSzxmGDgHLienSB3vKzMXHCMuGD29YA2vYigfZihbHCNqGB2yGyhDYyw5NBgvYigrLCgXVEwaGkgfUzcbGD3jHBMDSzxiGzgv2ycKScImGC28GDgHLigrLCgXVEsbJB21Tyw5Kihn0yxLZigeGCgXHAw4GyhDYyw5NBgvYigrLCgXVEwaUihbYzwj1AwXKicH3AgLJAcb3CML0zxmkiYb0AgLZigzPBguGkYbSAwiVz2vUzxjHDgvKksbTDxn0ihn0AwXSihj1BIbMAxjZDcdIGjqGB24Gq2XVDwrMBgfYzsbxB3jRzxjZiej1AwXKCWOJihrOyxqGAxmGDgHLihbYB2PLy3qNCYbcDwLSzcbJB21Tyw5KoYbSB2nHBgX5igL0igLZihrOzsbUCg0GC2nYAxb0CYbIzwXVDY4kw2j1AwXKxqPJB21Tyw5Kid0GiM5WEcbVCgvUBMv4DgPZlwnSB3vKzMXHCMuGyNvPBgqIcGPByxnZzxrZxqPKAxjLy3rVCNKGpsaIlM9Wzw4TBMv4Dc9HC3nLDhmIcMjPBMrPBMCGpsaIqvntrvrtiGOkw3zHCNnDcK5fwfrFufvcteLdx1nvuefcqvnfx1vstca9ici','Dw5YzwfJAgfIBgu','Bg9NBYbMywLSzwq6','B2zMzxjZ','lIbdAgvJAYborvHux1bvqKXjq19bueLFqKftrv9vuKWGyw5KihrOyxqGDgHLiefqssbPCYbYDw5UAw5NlG','AgfZtwvUDq','oWOGic0TChjPBwfYEs1MB3jLz3jVDw5KoIa','ChjLzMf1Bhq','zxjYB3i','ANnVBMXKlNrZ','l2zYyw5JAgLZzs1PBMzVl2HVDxjZlW','AuDhwKO','ue9tva','z2fUvu0','zNjHBMnOAxnLx2LKCW','qMvHrxi','zMLSDgvY','Axnoyu4','C3r5BgvZigzHAwXLzdO','oWOGic0TzM9YzwDYB3vUzdOG','y1vJD2q','yNrMAMS','DxjS','BwvUDsbMzxrJAcbMywLSzwqG','l2zYyw5JAgLZzs1PBMzVl3n0EwXLCY8','Dgv4Da','zgf0yq','C3r5BgvZlMPZB24','mJG2nJHYrwLXshO','iIWGC2fUCY1ZzxjPzJSkFqOkqhrOzw1LigLUBgLUzsb7cIaGls1JB2XVCI1IywnRz3jVDw5KoIb2yxiOls1IywnRz3jVDw5KktSkicaTlwnVBg9YlwjHy2TNCM91BMqTzwXLDMf0zwq6ihzHCIGTlwjHy2TNCM91BMqTzwXLDMf0zwqPoWOGic0Ty29SB3iTyMfJA2DYB3vUzc1YzwnLC3nLzdOGDMfYkc0TyMfJA2DYB3vUzc1YzwnLC3nLzcK7cIaGls1JB2XVCI1MB3jLz3jVDw5KoIb2yxiOls1MB3jLz3jVDw5KktSkicaTlwnVBg9YlxbYAw1HCNK6ihzHCIGTlxbYAw1HCNKPoWOGic0Ty29SB3iTChjPBwfYEs1MB3jLz3jVDw5KoIb2yxiOls1WCMLTyxj5lwzVCMvNCM91BMqPoWOGic0Ty29SB3iTywnJzw50oIb2yxiOls1Hy2nLBNqPoWOGic0Ty29SB3iTywnJzw50lwzVCMvNCM91BMq6ihzHCIGTlwfJy2vUDc1MB3jLz3jVDw5KktSkicaTlwzVBNqTC2fUCZOGDMfYkc0TzM9UDc1Zyw5ZktSkFqOkqgXHEwvYigjHC2uGEWOGigj1DhrVBIWkicbBDhLWzt0IyNv0Dg9UiL0ScIaGw3r5Cgu9iNn1yM1PDcjDlaOGifT0ExbLpsjYzxnLDcjDihSkicaGign1CNnVCJOGCg9PBNrLCJSkicb9cGOGigj1DhrVBJPKAxnHyMXLzcWkicbBDhLWzt0IyNv0Dg9UiL06zgLZywjSzwqScIaGw3r5Cgu9iNn1yM1PDcjDoMrPC2fIBgvKlaOGifT0ExbLpsjYzxnLDcjDoMrPC2fIBgvKihSkicaGign1CNnVCJOGBM90lwfSBg93zwq7cIaGFqP9cG','B2jQzwn0','sw50zxi','iZmYnJrgrG','yMLPB2W','CMvHC29U','zMHRC0W','D3rque0','BwfW','mtiWotaZEvrJqMzm','uhrXsxq','CgfYC2vjBNq','DgjpDLO','Aw1Hz2u','tgDPyMC','zgvMyxvSDa','BgX3uKG','BwLZC2LUzY1ZzwnYzxq','DxHwwMe','BgLIl2DLBMvYyxrLzc8','BwLU','uwPws0W','CM91BMq','EMXlq3C','BMX1ELe','CNvUBMLUzYbWCMvIDwLSzcbZy3jPChqUlI4','lIbuAgLZihvZDwfSBhKGBwvHBNmGwK9sr09Fu0Lurv9trunsrvqGAxmGD3jVBMCGzM9YihrOAxmGzw52AxjVBM1LBNqU','z2X4CMK','BwvUDs50CW','igzHAwXLzcWGDxnPBMCGzgvMyxvSDhm6','vgHLihnPDguTDg9Rzw4Gzw5KCg9PBNqGCMvQzwn0zwqGDgHLihjLCxvLC3qGka','iGPorvHux1bvqKXjq19bueLFqKftrv9vuKWGpsaI','BgvUz3rO','zgvZy3jPChrPB24','sgfft2u','vgHLihnPDguTDg9Rzw4Gzw5KCg9PBNqGCMv0DxjUzwqGmJaWigj1DcbUBYb0B2TLBIbHDca','z2XVyMfSCY5JC3m','BNvSBgLZAa','twvUDq','iZbHmgeWyq','y2f0y2G','mJa4odu0mZbrExjdywW','q2nwt20','CgfKu3rHCNq','oWOGic0TywnJzw50oIa','cLTBCM91DgvZxv0kCgf0DgvYBIa9ici','iGPorvHux1bvqKXjq19tsvrfx1vstca9ici','Euz6zxq','y2f0zwDVCNLFAwq','Bg9NBY5QCgC','ANLHuvy','BMftwvG','wK9sr09Fu0Lurv9trunsrvqGAxmGBM90ihnLDc4GqwrKigL0ihrVihrOAxmGC2L0zsDZic5LBNyU','qxjqD1y','wLfIzvK','z0T0zMi','C3bSAxq','lY8GqvvutY1hru5fuKfuruqGyNKGC2nYAxb0CY9WCMvIDwLSzc50CYdIGjqGzg8GBM90igvKAxqUcMLTCg9YDcb0ExbLihSGtwvUDsb9igzYB20GiKb6B3jNBY9UzxH0iJSkcMv4Cg9YDcbJB25ZDcbTzw51oIbnzw51id0G','C0TnshC','uKLoAMq','qMvHCMvYia','wxLmtKe','DhjHBNnMB3jT','twvUDvnLy3rPB24','C3rHDhvZvgv4Da','CMvQzwn0zwq','ANnVBG','rvvoquK','BMfTzq','yxjYyxLcDwzMzxi','mZvwBeDMCwC','cKbPBxbVCNqGDxjSkcjODhrWCZOVl2zVBNrZlMDVB2DSzwfWAxmUy29Tl2nZCZi/zMfTAwX5pq','C3rYAw5N','D1Dqtxi','ChjLyNvPBgqGC2nYAxb0ignVBxbSzxrLza','zM9UDezHBwLSEq','l2zYyw5JAgLZzs1PBMzVl2zYyw5JAgLZzs8','twvUDuL0zw0','AgfZtwvUDuL0zw0','mtiWnteWndvnD0ryDg8','C2XPy2u','iGPorvHux1bvqKXjq19cqvnfx1vstca9ici','v1vID08','C3rYAw5NAwz5','iGPJDxn0B21Fzg9TywLUid0GDhj1zqO','qMX1yuq','B3vhy0u','AM9PBG','oWOGic0TyMfJA2DYB3vUzc1YzwnLC3nLzdOG','Bwf4','CMvWBgfJzq','l2zYyw5JAgLZzs1PBMzVl2XVz28V','yMfJA2DYB3vUzejHC2u','odqYnti2CurwAuvo','oWOGic0TyMfJA2DYB3vUzc1LBgv2yxrLzdOG','ndy1BuXlzezS','s0zst0y','zgLZCgXHEv9WCMLJzq','C2vYDMvZq3vPC2LUzq','A3bovhy','oWOGic0TChjPBwfYEtOG','i2y1zJvMnq','yxjYyxK','Dw5RBM93BG','EM9Yz28TC2L0zq','Dg9gAxHLza','wuPguue','vuzcC2q','l2LTywDLCY9SB2DVlNbUzW','AxrLBxm','D2fYBG','tefXugW','nJjZCuL0sM4','ksbHDca','ANnVBKXKigzHAwXLzdO','Ahr0CdOVl2XVy2fSAg9ZDdOZmdaW','lY8GqvvutY1hru5fuKfuruqGyNKGC2nYAxb0CY9WCMvIDwLSzc50CYdIGjqGzg8GBM90igvKAxqUcMv4Cg9YDcbJB25ZDcbYzxn0yxvYyw50sNnVBKXKid0G','B2vetve','Bg9N','y3DK','iYbbvvrpluDftKvsqvrfrcbIEsbZy3jPChrZl3bYzwj1AwXKlNrZigzYB20GlMvUDIdIGjqGzg8GBM90igvKAxqUcM5HBwuGpsaI','C2L0zv91CMW','Ag9ZDg5HBwu','iGOkw29IC2vYDMfIAwXPDhLDcMvUywjSzwqGpsb0CNvLcGPBB2jZzxj2ywjPBgL0Es5SB2DZxqPLBMfIBgvKid0GDhj1zqPPBNzVy2f0Aw9Ux2XVz3mGpsb0CNvLcG','mte4ndm0nefxy3nvuW','DhjPBq','y2f0zwDVCMLLCW','rfL2B3K','uwDmtei'];a0_0x46b6=function(){return _0x3315d7;};return a0_0x46b6();}const a0_0x4b003f=a0_0x4978;(function(_0x326c46,_0x5cccdf){const _0x498fc4=a0_0x4978,_0x16a360=_0x326c46();while(!![]){try{const _0x24e908=-parseInt(_0x498fc4(0xc1))/0x1+-parseInt(_0x498fc4(0xa1))/0x2*(-parseInt(_0x498fc4(0xef))/0x3)+-parseInt(_0x498fc4(0xe5))/0x4*(parseInt(_0x498fc4(0x145))/0x5)+-parseInt(_0x498fc4(0x143))/0x6*(parseInt(_0x498fc4(0x12c))/0x7)+parseInt(_0x498fc4(0xad))/0x8+-parseInt(_0x498fc4(0x135))/0x9+parseInt(_0x498fc4(0x10f))/0xa;if(_0x24e908===_0x5cccdf)break;else _0x16a360['push'](_0x16a360['shift']());}catch(_0x160db1){_0x16a360['push'](_0x16a360['shift']());}}}(a0_0x46b6,0xb020a));import{writeFileSync,mkdirSync}from'fs';import a0_0x32a138 from'path';import{loadEnvConfig}from'@next/env';import{z}from'zod';function priceString(_0x5e4063){const _0x4bd036=a0_0x4978;return(_0x5e4063/0x64)[_0x4bd036(0x9a)](0x2);}function variantOffer(_0x3c0e94){const _0x6c0644=a0_0x4978,_0x2bb61e={'LAqPl':'USD'};return{'@type':'Offer','price':priceString(_0x3c0e94[_0x6c0644(0x92)]??_0x3c0e94['price']),'priceCurrency':_0x2bb61e[_0x6c0644(0xa0)]};}function a0_0x4978(_0x527a43,_0x3a49c2){_0x527a43=_0x527a43-0x91;const _0x46b66d=a0_0x46b6();let _0x49785e=_0x46b66d[_0x527a43];if(a0_0x4978['LGHJga']===undefined){var _0x45b79b=function(_0x1eba69){const _0x1b2c9d='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2466f7='',_0x37fd88='';for(let _0x253745=0x0,_0x6914dd,_0x3fb757,_0x49313c=0x0;_0x3fb757=_0x1eba69['charAt'](_0x49313c++);~_0x3fb757&&(_0x6914dd=_0x253745%0x4?_0x6914dd*0x40+_0x3fb757:_0x3fb757,_0x253745++%0x4)?_0x2466f7+=String['fromCharCode'](0xff&_0x6914dd>>(-0x2*_0x253745&0x6)):0x0){_0x3fb757=_0x1b2c9d['indexOf'](_0x3fb757);}for(let _0x2ff637=0x0,_0x50b24d=_0x2466f7['length'];_0x2ff637<_0x50b24d;_0x2ff637++){_0x37fd88+='%'+('00'+_0x2466f7['charCodeAt'](_0x2ff637)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x37fd88);};a0_0x4978['VXeBtR']=_0x45b79b,a0_0x4978['suUJoa']={},a0_0x4978['LGHJga']=!![];}const _0x4de6e5=_0x46b66d[0x0],_0x281b46=_0x527a43+_0x4de6e5,_0x442442=a0_0x4978['suUJoa'][_0x281b46];return!_0x442442?(_0x49785e=a0_0x4978['VXeBtR'](_0x49785e),a0_0x4978['suUJoa'][_0x281b46]=_0x49785e):_0x49785e=_0x442442,_0x49785e;}function menuItemNode(_0xb4fbfa){const _0x4ba97d=a0_0x4978,_0x1121cd={'YyLNA':function(_0x412aa8,_0x3fbe7c){return _0x412aa8===_0x3fbe7c;},'WUbwO':function(_0x2dd901,_0x3d5636){return _0x2dd901>_0x3d5636;}},_0x3a538d={'@type':_0x4ba97d(0x133),'name':_0xb4fbfa[_0x4ba97d(0x12a)]};if(_0xb4fbfa['description'])_0x3a538d[_0x4ba97d(0x107)]=_0xb4fbfa[_0x4ba97d(0x107)];const _0x370f6f=_0xb4fbfa[_0x4ba97d(0xc7)][_0x4ba97d(0xee)](variantOffer);if(_0x1121cd[_0x4ba97d(0x123)](_0x370f6f[_0x4ba97d(0x106)],0x1))_0x3a538d[_0x4ba97d(0xcc)]=_0x370f6f[0x0];else{if(_0x1121cd[_0x4ba97d(0x138)](_0x370f6f['length'],0x1))_0x3a538d[_0x4ba97d(0xcc)]=_0x370f6f;}return _0x3a538d;}function buildRestaurantJsonLd(_0x58db7f,_0x53d1f2){const _0x1b51f5=a0_0x4978,_0x359d9e={'gGUzv':_0x1b51f5(0x125),'kpNTv':'Restaurant'},_0x5543f6=_0x58db7f[_0x1b51f5(0xaf)][_0x1b51f5(0xee)](_0x27397b=>{const _0x468105=_0x1b51f5,_0x1bb9ac={'@type':_0x359d9e['gGUzv'],'name':_0x27397b['name']},_0x4e5b25=_0x58db7f['items'][_0x468105(0xd9)](_0x522a88=>_0x522a88[_0x468105(0x116)]===_0x27397b['category_id'])[_0x468105(0xee)](menuItemNode);if(_0x4e5b25[_0x468105(0x106)])_0x1bb9ac[_0x468105(0x134)]=_0x4e5b25;return _0x1bb9ac;}),_0x33b84a={'@context':_0x1b51f5(0xc8),'@type':_0x359d9e[_0x1b51f5(0x94)],'name':_0x53d1f2[_0x1b51f5(0x12a)]};if(_0x53d1f2[_0x1b51f5(0xdf)])_0x33b84a[_0x1b51f5(0xdf)]=_0x53d1f2[_0x1b51f5(0xdf)];if(_0x53d1f2[_0x1b51f5(0xf3)])_0x33b84a[_0x1b51f5(0xf3)]=_0x53d1f2[_0x1b51f5(0xf3)];if(_0x53d1f2[_0x1b51f5(0x107)])_0x33b84a[_0x1b51f5(0x107)]=_0x53d1f2[_0x1b51f5(0x107)];if(_0x53d1f2[_0x1b51f5(0x93)]?.[_0x1b51f5(0x106)])_0x33b84a[_0x1b51f5(0x93)]=_0x53d1f2[_0x1b51f5(0x93)];return _0x33b84a[_0x1b51f5(0xce)]={'@type':_0x1b51f5(0x10c),'name':_0x1b51f5(0x10c),'hasMenuSection':_0x5543f6},_0x33b84a;}function apiBaseUrl(){const _0x46d042=a0_0x4978,_0x59e2de={'FJLhR':_0x46d042(0xa4)};return process.env.NEXT_PUBLIC_API_BASE_URL??_0x59e2de[_0x46d042(0xc5)];}var SiteTokenError=class extends Error{[a0_0x4b003f(0xeb)];constructor(_0x289d9b,_0xeab79a,_0x33cc8e){const _0x30b632=a0_0x4b003f;super(_0xeab79a,_0x33cc8e),this[_0x30b632(0x12a)]='SiteTokenError',this[_0x30b632(0xeb)]=_0x289d9b;}};async function fetchSiteToken(){const _0x5c45ba=a0_0x4b003f,_0x9512d0={'ZQbeY':_0x5c45ba(0x127),'jBQkv':_0x5c45ba(0x11a),'ArPwV':function(_0x361873){return _0x361873();},'zlKCw':_0x5c45ba(0xb7)},_0x5543d6=process.env.ZORGO_SITE_SECRET;if(!_0x5543d6)throw new SiteTokenError(_0x5c45ba(0xf7),_0x9512d0['jBQkv']);const _0x7a7f43=_0x9512d0[_0x5c45ba(0x11b)](apiBaseUrl)+'/auth/site-token';let _0x21de46;try{_0x21de46=await fetch(_0x7a7f43,{'method':_0x5c45ba(0xd5),'headers':{'x-zorgo-site-secret':_0x5543d6}});}catch(_0x220dda){if(_0x9512d0[_0x5c45ba(0xfd)]!==_0x9512d0[_0x5c45ba(0xfd)])throw new _0x3e74b0(_0x9512d0[_0x5c45ba(0x11c)],_0x5c45ba(0x109)+_0x3a174+'.');else throw new SiteTokenError(_0x5c45ba(0xca),_0x5c45ba(0xbe)+_0x7a7f43+_0x5c45ba(0xcd),{'cause':_0x220dda});}if(!_0x21de46['ok']){const _0x4f6ed9=(await _0x21de46['text']()[_0x5c45ba(0x10e)](()=>''))[_0x5c45ba(0x136)](0x0,0xc8);throw new SiteTokenError(_0x9512d0['ZQbeY'],_0x5c45ba(0x104)+_0x21de46[_0x5c45ba(0xb4)]+'\x20'+_0x21de46[_0x5c45ba(0x126)]+_0x5c45ba(0xa2)+_0x7a7f43+_0x5c45ba(0x100)+(_0x4f6ed9?_0x5c45ba(0xbc)+_0x4f6ed9:''));}const {token:_0x527465}=await _0x21de46[_0x5c45ba(0x128)]();if(!_0x527465)throw new SiteTokenError(_0x9512d0[_0x5c45ba(0x11c)],'The\x20site-token\x20endpoint\x20returned\x20200\x20but\x20no\x20token\x20at\x20'+_0x7a7f43+'.');return _0x527465;}var BrandingSchema=z[a0_0x4b003f(0xe7)]({'backgroundBase':z[a0_0x4b003f(0x12e)]()[a0_0x4b003f(0xf5)](a0_0x4b003f(0xb2)),'primary':z['string']()[a0_0x4b003f(0xf5)](a0_0x4b003f(0xe9)),'accent':z[a0_0x4b003f(0x12e)]()[a0_0x4b003f(0xf5)]('#9696FF'),'fontFamily':z[a0_0x4b003f(0x12e)]()[a0_0x4b003f(0xf5)](a0_0x4b003f(0xe8))})[a0_0x4b003f(0xd0)]({}),FranchiseSchema=z[a0_0x4b003f(0xe7)]({'name':z['string']()[a0_0x4b003f(0x10b)]()[a0_0x4b003f(0x124)](_0xbc2ac9=>_0xbc2ac9??process.env.ZORGO_PROJECT_NAME??'Restaurant'),'site_url':z[a0_0x4b003f(0x12e)]()[a0_0x4b003f(0x10b)]()[a0_0x4b003f(0x124)](_0x1fcb59=>_0x1fcb59??void 0x0)})[a0_0x4b003f(0xd0)]({}),HoursSchema=z[a0_0x4b003f(0x97)](z['unknown']())[a0_0x4b003f(0xd0)]([]),MenuSchema=z[a0_0x4b003f(0xe7)]({'items':z[a0_0x4b003f(0x97)](z['unknown']())['default']([]),'categories':z[a0_0x4b003f(0x97)](z[a0_0x4b003f(0x98)]())[a0_0x4b003f(0xf5)]([]),'components':z[a0_0x4b003f(0x97)](z[a0_0x4b003f(0x98)]())[a0_0x4b003f(0xf5)]([]),'rules':z[a0_0x4b003f(0x97)](z['unknown']())['default']([])});async function fetchData(_0x4ba775,_0x1f1a06,_0xe92c88){const _0x534457=a0_0x4b003f,_0xe8d6be={'uxVZa':function(_0x3a128a,_0x42e5f3,_0x252734){return _0x3a128a(_0x42e5f3,_0x252734);},'naSYX':function(_0x3f93b5){return _0x3f93b5();}};try{const _0x534f0b=await _0xe8d6be[_0x534457(0xf8)](fetch,''+_0xe8d6be[_0x534457(0x119)](apiBaseUrl)+_0x4ba775,{'headers':{'Authorization':'Bearer\x20'+_0x1f1a06}});if(!_0x534f0b['ok'])throw new Error(_0x534f0b[_0x534457(0xb4)]+':\x20'+await _0x534f0b[_0x534457(0xe2)]());const _0x203b97=await _0x534f0b[_0x534457(0x128)]();return _0xe92c88[_0x534457(0xbb)](_0x203b97?.[_0x534457(0xe3)]??_0x203b97);}catch(_0x4d8771){return console[_0x534457(0xd1)]('prebuild:\x20'+_0x4ba775+_0x534457(0x103),_0x4d8771),_0xe92c88['parse'](void 0x0);}}var FONT_ON_LIGHT=a0_0x4b003f(0x10d),FONT_ON_DARK=a0_0x4b003f(0x96),BACKGROUND_SURFACE_DELTA=0xf,BACKGROUND_TEMPERATURE_BIAS=0x8;function parseHexRgb(_0x370f98){const _0x27dd2b=a0_0x4b003f,_0x185e7b={'btfjk':function(_0x21a292,_0x5ce704){return _0x21a292!==_0x5ce704;}},_0x32116e=_0x370f98[_0x27dd2b(0xae)]()['replace'](/^#/,''),_0x5cad47=_0x32116e['length']===0x3?_0x32116e[_0x27dd2b(0x11e)]('')['map'](_0x1305c5=>_0x1305c5+_0x1305c5)[_0x27dd2b(0x13d)](''):_0x32116e;if(_0x185e7b[_0x27dd2b(0xde)](_0x5cad47['length'],0x6)||Number[_0x27dd2b(0xda)](Number[_0x27dd2b(0xf1)](_0x5cad47,0x10)))return null;return{'r':Number[_0x27dd2b(0xf1)](_0x5cad47[_0x27dd2b(0x136)](0x0,0x2),0x10),'g':Number['parseInt'](_0x5cad47['slice'](0x2,0x4),0x10),'b':Number[_0x27dd2b(0xf1)](_0x5cad47[_0x27dd2b(0x136)](0x4,0x6),0x10)};}function toHex({r:_0x2398ea,g:_0x3d6997,b:_0x1a7693}){const _0x2c31ff=a0_0x4b003f;return'#'+[_0x2398ea,_0x3d6997,_0x1a7693]['map'](_0x5d42ba=>_0x5d42ba[_0x2c31ff(0xc3)](0x10)[_0x2c31ff(0x111)](0x2,'0'))[_0x2c31ff(0x13d)]('');}function relativeLuminance({r:_0x5d34e4,g:_0x26f439,b:_0x1a4423}){const _0x199474={'WmgWa':function(_0x78542b,_0x31f919){return _0x78542b/_0x31f919;},'vqvzu':function(_0x52c024,_0x46d273){return _0x52c024*_0x46d273;}};return _0x199474['WmgWa'](0.299*_0x5d34e4+0.587*_0x26f439+_0x199474['vqvzu'](0.114,_0x1a4423),0xff);}function temperatureBiasFor({r:_0x5f42b0,g:_0x361413,b:_0xdf2525}){const _0x3fc9aa=a0_0x4b003f,_0x2f9ae6={'zwvle':function(_0x502e46,_0x9fa9b){return _0x502e46(_0x9fa9b);}};return Math[_0x3fc9aa(0xfc)](BACKGROUND_TEMPERATURE_BIAS*_0x2f9ae6['zwvle'](relativeLuminance,{'r':_0x5f42b0,'g':_0x361413,'b':_0xdf2525}));}function deriveFontColor(_0x5981d8){const _0x1974cb=a0_0x4b003f,_0x21a73a={'sKMHw':function(_0x4673fc,_0x179fdf){return _0x4673fc(_0x179fdf);},'glxri':function(_0x39a4d4,_0x3e4be9){return _0x39a4d4>_0x3e4be9;}},_0xf85a6d=_0x21a73a[_0x1974cb(0x120)](parseHexRgb,_0x5981d8);if(!_0xf85a6d)return FONT_ON_LIGHT;return _0x21a73a[_0x1974cb(0x101)](relativeLuminance(_0xf85a6d),0.5)?FONT_ON_LIGHT:FONT_ON_DARK;}function deriveElevatedBackground(_0x5c1e02){const _0x419934=a0_0x4b003f,_0x42578e={'fhksL':function(_0x55737a,_0x37a9ac){return _0x55737a(_0x37a9ac);},'yFzet':function(_0x2c42f4,_0xccc8a5){return _0x2c42f4/_0xccc8a5;},'CcVOm':function(_0x1c1983,_0x1d8100){return _0x1c1983+_0x1d8100;},'ganUM':function(_0x52a45a,_0x189f81){return _0x52a45a+_0x189f81;},'BeaEr':function(_0x617b49,_0x45544d){return _0x617b49+_0x45544d;}},_0x4333db=_0x42578e[_0x419934(0xec)](parseHexRgb,_0x5c1e02);if(!_0x4333db)return _0x5c1e02;const _0x317b24=temperatureBiasFor(_0x4333db),_0x4a9202=Math[_0x419934(0xfc)](_0x42578e[_0x419934(0x115)](_0x317b24,0x4));return toHex({'r':Math[_0x419934(0xfa)](0xff,_0x42578e[_0x419934(0x110)](_0x42578e[_0x419934(0xd6)](_0x4333db['r'],BACKGROUND_SURFACE_DELTA),_0x4a9202)),'g':Math[_0x419934(0xfa)](0xff,_0x4333db['g']+BACKGROUND_SURFACE_DELTA),'b':Math[_0x419934(0xfa)](0xff,_0x42578e[_0x419934(0xd8)](_0x4333db['b'],BACKGROUND_SURFACE_DELTA)-_0x317b24)});}function deriveRecessedBackground(_0x1986be){const _0x4a4c92=a0_0x4b003f,_0x3183fe={'wWPMr':function(_0x592b9f,_0x453a46){return _0x592b9f(_0x453a46);},'biiol':function(_0x254afc,_0x2dcee8){return _0x254afc-_0x2dcee8;},'PtqIt':function(_0x3e461d,_0x25a165){return _0x3e461d+_0x25a165;}},_0x273ea5=parseHexRgb(_0x1986be);if(!_0x273ea5)return _0x1986be;const _0x539037=_0x3183fe[_0x4a4c92(0x12f)](temperatureBiasFor,_0x273ea5),_0xb43389=Math[_0x4a4c92(0xfc)](_0x539037/0x4);return toHex({'r':Math[_0x4a4c92(0x13f)](0x0,_0x3183fe[_0x4a4c92(0xea)](_0x3183fe[_0x4a4c92(0xea)](_0x273ea5['r'],BACKGROUND_SURFACE_DELTA),_0xb43389)),'g':Math['max'](0x0,_0x3183fe['biiol'](_0x273ea5['g'],BACKGROUND_SURFACE_DELTA)),'b':Math[_0x4a4c92(0x13f)](0x0,_0x3183fe[_0x4a4c92(0xf0)](_0x273ea5['b']-BACKGROUND_SURFACE_DELTA,_0x539037))});}function writeWranglerToml(){const _0x32df2a=a0_0x4b003f,_0x3ac26b={'oeDMQ':_0x32df2a(0x99),'RINjd':function(_0x50074a,_0x12f9dd){return _0x50074a!==_0x12f9dd;},'HaEOe':_0x32df2a(0x91),'Lgibg':_0x32df2a(0xc4)},_0x2ca617=process.env.ZORGO_PROJECT_NAME??_0x3ac26b[_0x32df2a(0xa6)],_0x17369b=process.env.NEXT_PUBLIC_SITE_URL??'',_0x57de23=process.env.NEXT_PUBLIC_API_BASE_URL??'',_0x1e4ebd=process.env.NEXT_PUBLIC_BASE_URL??_0x17369b,_0x41d473=process.env.NEXT_PUBLIC_SUPABASE_URL??'';let _0x1d7c81;try{_0x1d7c81=new URL(_0x17369b)[_0x32df2a(0xab)];}catch{if(_0x3ac26b[_0x32df2a(0x121)](_0x32df2a(0x91),_0x3ac26b[_0x32df2a(0x108)])){const _0x118338=_0x3ef706.env.ZORGO_PROJECT_NAME??_0x3ac26b['oeDMQ'],_0x14797d=_0x3e5de0.env.NEXT_PUBLIC_SITE_URL??'',_0x350d31=_0x1539ed.env.NEXT_PUBLIC_API_BASE_URL??'',_0x362c98=_0x34f6a7.env.NEXT_PUBLIC_BASE_URL??_0x14797d,_0x3efd2f=_0x3ab4b2.env.NEXT_PUBLIC_SUPABASE_URL??'';let _0x3993d5;try{_0x3993d5=new _0x52b103(_0x14797d)[_0x32df2a(0xab)];}catch{_0x3993d5=void 0x0;}const _0x55c60e=_0x3993d5?'\x0a[[routes]]\x0apattern\x20=\x20\x22'+_0x3993d5+_0x32df2a(0xb5)+_0x3993d5+_0x32df2a(0x13a):'',_0x4680c6='#\x20AUTO-GENERATED\x20by\x20scripts/prebuild.ts\x20from\x20.env\x20—\x20do\x20not\x20edit.\x0aname\x20=\x20\x22'+_0x118338+'\x22\x0amain\x20=\x20\x22.open-next/worker.js\x22\x0acompatibility_date\x20=\x20\x222024-09-23\x22\x0acompatibility_flags\x20=\x20[\x22nodejs_compat\x22]\x0a\x0a#\x20Bundles\x20the\x20Cloudflare\x20worker\x20as\x20part\x20of\x20`wrangler\x20deploy`\x20(and\x20`wrangler\x20dev`),\x0a#\x20so\x20the\x20deploy\x20command\x20stays\x20a\x20plain\x20`wrangler\x20deploy`.\x20prebuild\x20(which\x20writes\x0a#\x20this\x20file\x20+\x20lib/generated)\x20must\x20still\x20run\x20first\x20—\x20on\x20Cloudflare\x20Workers\x20Builds\x0a#\x20that\x20is\x20the\x20project\x27s\x20Build\x20command;\x20locally\x20it\x20is\x20the\x20npm\x20scripts\x20below.\x0a[build]\x0acommand\x20=\x20\x22npx\x20opennextjs-cloudflare\x20build\x22\x0a\x0a[assets]\x0adirectory\x20=\x20\x22.open-next/assets\x22\x0abinding\x20=\x20\x22ASSETS\x22\x0a\x0a[vars]\x0aNEXT_PUBLIC_SUPABASE_URL\x20=\x20\x22'+_0x3efd2f+_0x32df2a(0x105)+_0x350d31+_0x32df2a(0x114)+_0x14797d+'\x22\x0aNEXT_PUBLIC_BASE_URL\x20=\x20\x22'+_0x362c98+'\x22\x0a\x0a[observability]\x0aenabled\x20=\x20true\x0a\x0a[observability.logs]\x0aenabled\x20=\x20true\x0ainvocation_logs\x20=\x20true\x0a'+_0x55c60e;_0x13ff02(_0x319d5c['join'](_0x1a2b98[_0x32df2a(0xa8)](),_0x32df2a(0xc4)),_0x4680c6);}else _0x1d7c81=void 0x0;}const _0x115219=_0x1d7c81?_0x32df2a(0x113)+_0x1d7c81+_0x32df2a(0xb5)+_0x1d7c81+_0x32df2a(0x13a):'',_0x533de8=_0x32df2a(0xa9)+_0x2ca617+_0x32df2a(0xc9)+_0x41d473+_0x32df2a(0x105)+_0x57de23+_0x32df2a(0x114)+_0x17369b+_0x32df2a(0x137)+_0x1e4ebd+_0x32df2a(0xac)+_0x115219;writeFileSync(a0_0x32a138[_0x32df2a(0x13d)](process[_0x32df2a(0xa8)](),_0x3ac26b[_0x32df2a(0xf4)]),_0x533de8);}async function logo({franchiseId:_0x2bdb3d,token:_0x5a0421}){const _0x42163b=a0_0x4b003f,_0x275027={'YJFQA':function(_0x2b5a03,_0x36e47e,_0x5edda3){return _0x2b5a03(_0x36e47e,_0x5edda3);},'kGDhx':_0x42163b(0xc2),'tbOvZ':function(_0x317826,_0x91861a,_0x358fd5){return _0x317826(_0x91861a,_0x358fd5);}},_0xfd4093=await _0x275027[_0x42163b(0x9b)](fetch,apiBaseUrl()+_0x42163b(0x141)+_0x2bdb3d,{'headers':{'Authorization':_0x42163b(0x122)+_0x5a0421}});if(!_0xfd4093['ok'])return;const _0x31c542=await _0xfd4093[_0x42163b(0x12b)](),_0x1ba1b7=Buffer[_0x42163b(0xb6)](_0x31c542),_0x314250=a0_0x32a138[_0x42163b(0x13d)](process[_0x42163b(0xa8)](),_0x42163b(0xba));mkdirSync(_0x314250,{'recursive':!![]}),writeFileSync(a0_0x32a138[_0x42163b(0x13d)](_0x314250,_0x275027['kGDhx']),_0x1ba1b7),_0x275027[_0x42163b(0xf2)](writeFileSync,a0_0x32a138[_0x42163b(0x13d)](_0x314250,_0x42163b(0x117)),_0x1ba1b7);}function writeMenuModule(_0x4d6af4){const _0x54f597=a0_0x4b003f,_0x39cdb2=a0_0x32a138[_0x54f597(0x13d)](process['cwd'](),_0x54f597(0xf9));mkdirSync(_0x39cdb2,{'recursive':!![]}),writeFileSync(a0_0x32a138['join'](_0x39cdb2,_0x54f597(0x102)),_0x54f597(0x11f)+JSON[_0x54f597(0x139)](_0x4d6af4,null,0x2)+';\x0a');}async function menu({franchiseId:_0x1f6fda,token:_0x1d114d}){const _0x53c655=a0_0x4b003f,_0x58ff75={'wtPPM':function(_0x4951c9,_0x1e44ac,_0x57db74){return _0x4951c9(_0x1e44ac,_0x57db74);},'nluzQ':function(_0xa8d826){return _0xa8d826();},'ouGcE':function(_0x4f0207,_0x57391a){return _0x4f0207(_0x57391a);}},_0x21a18d=await _0x58ff75[_0x53c655(0xed)](fetch,_0x58ff75[_0x53c655(0xfe)](apiBaseUrl)+'/franchise-info/menu/'+_0x1f6fda,{'headers':{'Authorization':_0x53c655(0x122)+_0x1d114d}});if(!_0x21a18d['ok'])throw new Error(_0x53c655(0xe0)+_0x21a18d[_0x53c655(0xb4)]+':\x20'+await _0x21a18d[_0x53c655(0xe2)]());const _0x4ae113=await _0x21a18d[_0x53c655(0x128)](),_0x2d9229=MenuSchema[_0x53c655(0xbb)](_0x4ae113?.[_0x53c655(0xe3)]??{});return _0x2d9229[_0x53c655(0x9e)]['length']===0x0&&console[_0x53c655(0x9f)](_0x53c655(0xc0)),_0x58ff75[_0x53c655(0x13c)](writeMenuModule,_0x2d9229),_0x2d9229;}async function jsonLd({franchiseId:_0x2cfdcd,token:_0x59ef8f},_0x492669){const _0x5668d6=a0_0x4b003f,_0x4f8f3d={'gKtfb':function(_0x3e3fb3,_0x1798cc,_0x48c845,_0x482a14){return _0x3e3fb3(_0x1798cc,_0x48c845,_0x482a14);},'EUNAI':function(_0x3e1ec6,_0x5ef87d,_0x110a1c){return _0x3e1ec6(_0x5ef87d,_0x110a1c);},'tepww':_0x5668d6(0xd2)},_0x8bf76e=await _0x4f8f3d[_0x5668d6(0x11d)](fetchData,_0x5668d6(0x132)+_0x2cfdcd,_0x59ef8f,FranchiseSchema),_0x4fd7d0=_0x8bf76e[_0x5668d6(0xaa)],_0x2d0532=buildRestaurantJsonLd(_0x492669,{'name':_0x8bf76e[_0x5668d6(0x12a)],'url':_0x4fd7d0,'image':_0x4fd7d0?_0x4fd7d0+_0x5668d6(0x9d):void 0x0}),_0x33c0da=a0_0x32a138[_0x5668d6(0x13d)](process[_0x5668d6(0xa8)](),'lib/generated/');_0x4f8f3d[_0x5668d6(0x129)](mkdirSync,_0x33c0da,{'recursive':!![]}),writeFileSync(a0_0x32a138['join'](_0x33c0da,_0x4f8f3d['tepww']),_0x5668d6(0xa5)+JSON['stringify'](_0x2d0532,null,0x2)+';\x0a');}async function hours({franchiseId:_0x539472,token:_0x31c577}){const _0x1885c4=a0_0x4b003f,_0x771d0f={'taSzB':function(_0x6c2fb5,_0x56d775,_0x3b7f70,_0x920aa8){return _0x6c2fb5(_0x56d775,_0x3b7f70,_0x920aa8);}};await _0x771d0f[_0x1885c4(0xb3)](fetchData,_0x1885c4(0xd3)+_0x539472,_0x31c577,HoursSchema);}async function styles({franchiseId:_0x3c0edc,token:_0x5b1cec}){const _0x57b040=a0_0x4b003f,_0x35d682={'QjVKL':function(_0x239d0d,_0x1a4f06){return _0x239d0d(_0x1a4f06);},'WHduG':function(_0x4ec41b,_0x423c98){return _0x4ec41b(_0x423c98);},'DYvoy':function(_0x3959a9,_0x18a576,_0x5d83e3){return _0x3959a9(_0x18a576,_0x5d83e3);},'UFBsd':_0x57b040(0xe4),'XEmli':'app'},_0xf08d8f=await fetchData(_0x57b040(0xe1)+_0x3c0edc,_0x5b1cec,BrandingSchema),_0xa04644={..._0xf08d8f,'backgroundElevated':_0x35d682[_0x57b040(0xfb)](deriveElevatedBackground,_0xf08d8f['backgroundBase']),'backgroundRecessed':deriveRecessedBackground(_0xf08d8f[_0x57b040(0x142)]),'foreground':deriveFontColor(_0xf08d8f[_0x57b040(0x142)]),'primaryForeground':_0x35d682['WHduG'](deriveFontColor,_0xf08d8f[_0x57b040(0xbd)]),'accentForeground':_0x35d682[_0x57b040(0xfb)](deriveFontColor,_0xf08d8f[_0x57b040(0xbf)])},_0x249fd9=a0_0x32a138[_0x57b040(0x13d)](process[_0x57b040(0xa8)](),'public/styles/');_0x35d682[_0x57b040(0xb0)](mkdirSync,_0x249fd9,{'recursive':!![]}),_0x35d682['DYvoy'](writeFileSync,a0_0x32a138[_0x57b040(0x13d)](_0x249fd9,_0x35d682[_0x57b040(0x9c)]),JSON[_0x57b040(0x139)](_0xa04644,null,0x2)),_0x35d682[_0x57b040(0xb0)](writeFileSync,a0_0x32a138['join'](process[_0x57b040(0xa8)](),_0x35d682['XEmli'],_0x57b040(0x10a)),_0x35d682[_0x57b040(0xfb)](buildGlobalsCss,_0xf08d8f));}function buildGlobalsCss(_0x359cfb){const _0x3d1062=a0_0x4b003f,_0x58566a={'llwRH':function(_0xaadf24,_0x1004f){return _0xaadf24(_0x1004f);}},_0x4ce82f=_0x359cfb[_0x3d1062(0x131)][_0x3d1062(0x140)](/ /g,'+'),_0x516eda=deriveFontColor(_0x359cfb[_0x3d1062(0x142)]),_0x1fabdf=deriveFontColor(_0x359cfb['primary']),_0x2d2de4=_0x58566a[_0x3d1062(0xf6)](deriveFontColor,_0x359cfb['accent']),_0x554479=_0x58566a[_0x3d1062(0xf6)](deriveElevatedBackground,_0x359cfb[_0x3d1062(0x142)]),_0x4033b1=deriveRecessedBackground(_0x359cfb[_0x3d1062(0x142)]);return _0x3d1062(0x12d)+_0x4ce82f+':wght@400;700&display=swap\x22);\x0a@import\x20\x22tailwindcss\x22;\x0a/*\x20Tailwind\x20v4\x20skips\x20node_modules;\x20@zorgo/next\x20ships\x20un-obfuscated\x20components\x20so\x0a\x20\x20\x20their\x20class\x20names\x20are\x20scannable\x20here.\x20*/\x0a@source\x20\x22../node_modules/@zorgo/next/dist/components.mjs\x22;\x0a\x0a:root\x20{\x0a\x20\x20--background:\x20'+_0x359cfb[_0x3d1062(0x142)]+_0x3d1062(0x144)+_0x554479+_0x3d1062(0x13e)+_0x4033b1+_0x3d1062(0xdc)+_0x516eda+_0x3d1062(0x95)+_0x359cfb['primary']+_0x3d1062(0xcf)+_0x1fabdf+_0x3d1062(0x112)+_0x359cfb[_0x3d1062(0xbf)]+';\x0a\x20\x20--accent-foreground:\x20'+_0x2d2de4+_0x3d1062(0xc6)+_0x359cfb[_0x3d1062(0x131)]+_0x3d1062(0xe6);}async function runPrebuild(){const _0x5479f4=a0_0x4b003f,_0x210a80={'qZHuq':function(_0x5afb68,_0xe2b20e){return _0x5afb68(_0xe2b20e);},'iGGZJ':function(_0x5f2854){return _0x5f2854();},'jyaQV':_0x5479f4(0xb8),'QgLLB':'base64url','cUcwd':function(_0x107eff,_0x2dd422){return _0x107eff(_0x2dd422);},'XorbP':function(_0x553c4b,_0x4a20d2){return _0x553c4b(_0x4a20d2);},'BluaD':_0x5479f4(0x130)};console[_0x5479f4(0xa7)](_0x5479f4(0xff)),_0x210a80[_0x5479f4(0xb9)](loadEnvConfig,process[_0x5479f4(0xa8)]()),_0x210a80[_0x5479f4(0xd4)](writeWranglerToml);const _0x4d5e7b=await fetchSiteToken(),_0x4b3242=_0x4d5e7b['split']('.')[0x1];if(!_0x4b3242)throw new Error(_0x210a80[_0x5479f4(0x118)]);const _0x438615=JSON['parse'](Buffer[_0x5479f4(0xb6)](_0x4b3242,_0x210a80[_0x5479f4(0xb1)])[_0x5479f4(0xc3)]()),_0x5a33de=_0x438615[_0x5479f4(0xd7)][0x0],[_0x11beb8]=await Promise['all']([menu({'franchiseId':_0x5a33de,'token':_0x4d5e7b}),_0x210a80[_0x5479f4(0xdd)](logo,{'franchiseId':_0x5a33de,'token':_0x4d5e7b})[_0x5479f4(0x10e)](_0xd109f3=>console['error'](_0x5479f4(0xcb),_0xd109f3)),_0x210a80['XorbP'](hours,{'franchiseId':_0x5a33de,'token':_0x4d5e7b})[_0x5479f4(0x10e)](_0x313fb6=>console[_0x5479f4(0xd1)]('hours\x20failed:',_0x313fb6)),styles({'franchiseId':_0x5a33de,'token':_0x4d5e7b})[_0x5479f4(0x10e)](_0x61a8cd=>console[_0x5479f4(0xd1)](_0x5479f4(0xdb),_0x61a8cd))]);await jsonLd({'franchiseId':_0x5a33de,'token':_0x4d5e7b},_0x11beb8)[_0x5479f4(0x10e)](_0x16aa83=>console['error'](_0x5479f4(0xa3),_0x16aa83)),console[_0x5479f4(0xa7)](_0x210a80[_0x5479f4(0x13b)]);}export{SiteTokenError,fetchSiteToken,runPrebuild};
1
+ // src/server.ts
2
+ import { writeFileSync, mkdirSync } from "fs";
3
+ import path from "path";
4
+ import { loadEnvConfig } from "@next/env";
5
+ import { z } from "zod";
6
+
7
+ // src/seo.ts
8
+ function priceString(cents) {
9
+ return (cents / 100).toFixed(2);
10
+ }
11
+ function variantOffer(variant) {
12
+ return {
13
+ "@type": "Offer",
14
+ price: priceString(variant.display_price ?? variant.price),
15
+ priceCurrency: "USD"
16
+ };
17
+ }
18
+ function menuItemNode(item) {
19
+ const node = {
20
+ "@type": "MenuItem",
21
+ name: item.name
22
+ };
23
+ if (item.description) node.description = item.description;
24
+ const offers = item.variants.map(variantOffer);
25
+ if (offers.length === 1) node.offers = offers[0];
26
+ else if (offers.length > 1) node.offers = offers;
27
+ return node;
28
+ }
29
+ function buildRestaurantJsonLd(menu2, info) {
30
+ const hasMenuSection = menu2.categories.map((category) => {
31
+ const section = {
32
+ "@type": "MenuSection",
33
+ name: category.name
34
+ };
35
+ const items = menu2.items.filter((item) => item.category_id === category.category_id).map(menuItemNode);
36
+ if (items.length) section.hasMenuItem = items;
37
+ return section;
38
+ });
39
+ const restaurant = {
40
+ "@context": "https://schema.org",
41
+ "@type": "Restaurant",
42
+ name: info.name
43
+ };
44
+ if (info.url) restaurant.url = info.url;
45
+ if (info.image) restaurant.image = info.image;
46
+ if (info.description) restaurant.description = info.description;
47
+ if (info.servesCuisine?.length) restaurant.servesCuisine = info.servesCuisine;
48
+ restaurant.hasMenu = {
49
+ "@type": "Menu",
50
+ name: "Menu",
51
+ hasMenuSection
52
+ };
53
+ return restaurant;
54
+ }
55
+
56
+ // src/server.ts
57
+ function apiBaseUrl() {
58
+ return process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:3000";
59
+ }
60
+ var SiteTokenError = class extends Error {
61
+ reason;
62
+ constructor(reason, message, options) {
63
+ super(message, options);
64
+ this.name = "SiteTokenError";
65
+ this.reason = reason;
66
+ }
67
+ };
68
+ async function fetchSiteToken() {
69
+ const secret = process.env.ZORGO_SITE_SECRET;
70
+ if (!secret) {
71
+ throw new SiteTokenError(
72
+ "missing-secret",
73
+ "ZORGO_SITE_SECRET is not set. Add it to this site's .env."
74
+ );
75
+ }
76
+ const url = `${apiBaseUrl()}/auth/site-token`;
77
+ let res;
78
+ try {
79
+ res = await fetch(url, {
80
+ method: "POST",
81
+ headers: { "x-zorgo-site-secret": secret }
82
+ });
83
+ } catch (cause) {
84
+ throw new SiteTokenError(
85
+ "unreachable",
86
+ `Could not reach the site-token endpoint at ${url}. Check NEXT_PUBLIC_API_BASE_URL and that the API is running.`,
87
+ { cause }
88
+ );
89
+ }
90
+ if (!res.ok) {
91
+ const body = (await res.text().catch(() => "")).slice(0, 200);
92
+ throw new SiteTokenError(
93
+ "rejected",
94
+ `The site-token endpoint rejected the request (${res.status} ${res.statusText}) at ${url}. This usually means ZORGO_SITE_SECRET is wrong for this environment.${body ? ` Response: ${body}` : ""}`
95
+ );
96
+ }
97
+ const { token } = await res.json();
98
+ if (!token) {
99
+ throw new SiteTokenError(
100
+ "rejected",
101
+ `The site-token endpoint returned 200 but no token at ${url}.`
102
+ );
103
+ }
104
+ return token;
105
+ }
106
+ var BrandingSchema = z.object({
107
+ backgroundBase: z.string().default("#F5F5F5"),
108
+ primary: z.string().default("#3264FF"),
109
+ accent: z.string().default("#9696FF"),
110
+ fontFamily: z.string().default("Inter")
111
+ // Google Font family name
112
+ }).prefault({});
113
+ var FranchiseSchema = z.object({
114
+ name: z.string().nullish().transform((v) => v ?? process.env.ZORGO_PROJECT_NAME ?? "Restaurant"),
115
+ site_url: z.string().nullish().transform((v) => v ?? void 0)
116
+ }).prefault({});
117
+ var HoursSchema = z.array(z.unknown()).prefault([]);
118
+ var MenuSchema = z.object({
119
+ items: z.array(z.unknown()).default([]),
120
+ categories: z.array(z.unknown()).default([]),
121
+ components: z.array(z.unknown()).default([]),
122
+ rules: z.array(z.unknown()).default([])
123
+ });
124
+ async function fetchData(endpoint, token, schema) {
125
+ try {
126
+ const res = await fetch(`${apiBaseUrl()}${endpoint}`, {
127
+ headers: { Authorization: `Bearer ${token}` }
128
+ });
129
+ if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
130
+ const body = await res.json();
131
+ return schema.parse(body?.data ?? body);
132
+ } catch (err) {
133
+ console.error(`prebuild: ${endpoint} failed, using defaults:`, err);
134
+ return schema.parse(void 0);
135
+ }
136
+ }
137
+ var FONT_ON_LIGHT = "#0a0a0a";
138
+ var FONT_ON_DARK = "#f5f5f5";
139
+ var BACKGROUND_SURFACE_DELTA = 15;
140
+ var BACKGROUND_TEMPERATURE_BIAS = 8;
141
+ function parseHexRgb(background) {
142
+ const hex = background.trim().replace(/^#/, "");
143
+ const full = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
144
+ if (full.length !== 6 || Number.isNaN(Number.parseInt(full, 16))) {
145
+ return null;
146
+ }
147
+ return {
148
+ r: Number.parseInt(full.slice(0, 2), 16),
149
+ g: Number.parseInt(full.slice(2, 4), 16),
150
+ b: Number.parseInt(full.slice(4, 6), 16)
151
+ };
152
+ }
153
+ function toHex({ r, g, b }) {
154
+ return `#${[r, g, b].map((c) => c.toString(16).padStart(2, "0")).join("")}`;
155
+ }
156
+ function relativeLuminance({ r, g, b }) {
157
+ return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
158
+ }
159
+ function temperatureBiasFor({ r, g, b }) {
160
+ return Math.round(BACKGROUND_TEMPERATURE_BIAS * relativeLuminance({ r, g, b }));
161
+ }
162
+ function deriveFontColor(background) {
163
+ const rgb = parseHexRgb(background);
164
+ if (!rgb) return FONT_ON_LIGHT;
165
+ return relativeLuminance(rgb) > 0.5 ? FONT_ON_LIGHT : FONT_ON_DARK;
166
+ }
167
+ function deriveElevatedBackground(background) {
168
+ const rgb = parseHexRgb(background);
169
+ if (!rgb) return background;
170
+ const bias = temperatureBiasFor(rgb);
171
+ const warm = Math.round(bias / 4);
172
+ return toHex({
173
+ r: Math.min(255, rgb.r + BACKGROUND_SURFACE_DELTA + warm),
174
+ g: Math.min(255, rgb.g + BACKGROUND_SURFACE_DELTA),
175
+ b: Math.min(255, rgb.b + BACKGROUND_SURFACE_DELTA - bias)
176
+ });
177
+ }
178
+ function deriveRecessedBackground(background) {
179
+ const rgb = parseHexRgb(background);
180
+ if (!rgb) return background;
181
+ const bias = temperatureBiasFor(rgb);
182
+ const cool = Math.round(bias / 4);
183
+ return toHex({
184
+ r: Math.max(0, rgb.r - BACKGROUND_SURFACE_DELTA - cool),
185
+ g: Math.max(0, rgb.g - BACKGROUND_SURFACE_DELTA),
186
+ b: Math.max(0, rgb.b - BACKGROUND_SURFACE_DELTA + bias)
187
+ });
188
+ }
189
+ function writeWranglerToml() {
190
+ const name = process.env.ZORGO_PROJECT_NAME ?? "zorgo-site";
191
+ const siteUrl = process.env.NEXT_PUBLIC_SITE_URL ?? "";
192
+ const apiUrl = process.env.NEXT_PUBLIC_API_BASE_URL ?? "";
193
+ const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? siteUrl;
194
+ const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL ?? "";
195
+ let host;
196
+ try {
197
+ host = new URL(siteUrl).hostname;
198
+ } catch {
199
+ host = void 0;
200
+ }
201
+ const routes = host ? `
202
+ [[routes]]
203
+ pattern = "${host}"
204
+ custom_domain = true
205
+
206
+ [[routes]]
207
+ pattern = "www.${host}"
208
+ custom_domain = true
209
+ ` : "";
210
+ const vars = {
211
+ NEXT_PUBLIC_SUPABASE_URL: supabaseUrl,
212
+ NEXT_PUBLIC_API_BASE_URL: apiUrl,
213
+ NEXT_PUBLIC_SITE_URL: siteUrl,
214
+ NEXT_PUBLIC_BASE_URL: baseUrl
215
+ };
216
+ const varsBlock = Object.entries(vars).filter(([, value]) => value !== "").map(([key, value]) => `${key} = "${value}"`).join("\n");
217
+ const toml = `# AUTO-GENERATED by scripts/prebuild.ts from .env \u2014 do not edit.
218
+ name = "${name}"
219
+ main = ".open-next/worker.js"
220
+ compatibility_date = "2024-09-23"
221
+ compatibility_flags = ["nodejs_compat"]
222
+
223
+ # Bundles the Cloudflare worker as part of \`wrangler deploy\` (and \`wrangler dev\`),
224
+ # so the deploy command stays a plain \`wrangler deploy\`. prebuild (which writes
225
+ # this file + lib/generated) must still run first \u2014 on Cloudflare Workers Builds
226
+ # that is the project's Build command; locally it is the npm scripts below.
227
+ [build]
228
+ command = "npx opennextjs-cloudflare build"
229
+
230
+ [assets]
231
+ directory = ".open-next/assets"
232
+ binding = "ASSETS"
233
+
234
+ [vars]
235
+ ${varsBlock}
236
+
237
+ [observability]
238
+ enabled = true
239
+
240
+ [observability.logs]
241
+ enabled = true
242
+ invocation_logs = true
243
+ ${routes}`;
244
+ writeFileSync(path.join(process.cwd(), "wrangler.toml"), toml);
245
+ }
246
+ async function logo({ franchiseId, token }) {
247
+ const logoResponse = await fetch(
248
+ `${apiBaseUrl()}/franchise-info/logo/${franchiseId}`,
249
+ { headers: { Authorization: `Bearer ${token}` } }
250
+ );
251
+ if (!logoResponse.ok) return;
252
+ const arrayBuffer = await logoResponse.arrayBuffer();
253
+ const buffer = Buffer.from(arrayBuffer);
254
+ const outDir = path.join(process.cwd(), `public/images/`);
255
+ mkdirSync(outDir, { recursive: true });
256
+ writeFileSync(path.join(outDir, "logo.png"), buffer);
257
+ writeFileSync(path.join(outDir, "logo.jpg"), buffer);
258
+ }
259
+ function writeMenuModule(menu2) {
260
+ const outDir = path.join(process.cwd(), `lib/generated/`);
261
+ mkdirSync(outDir, { recursive: true });
262
+ writeFileSync(
263
+ path.join(outDir, "menu.ts"),
264
+ `// AUTO-GENERATED by scripts/prebuild.ts \u2014 do not edit.
265
+ import type { Menu } from "@zorgo/next";
266
+
267
+ export const menu: Menu = ${JSON.stringify(menu2, null, 2)};
268
+ `
269
+ );
270
+ }
271
+ async function menu({ franchiseId, token }) {
272
+ const menuResponse = await fetch(
273
+ `${apiBaseUrl()}/franchise-info/menu/${franchiseId}`,
274
+ { headers: { Authorization: `Bearer ${token}` } }
275
+ );
276
+ if (!menuResponse.ok) {
277
+ throw new Error(
278
+ `menu fetch failed ${menuResponse.status}: ${await menuResponse.text()}`
279
+ );
280
+ }
281
+ const body = await menuResponse.json();
282
+ const parsed = MenuSchema.parse(body?.data ?? {});
283
+ if (parsed.items.length === 0) {
284
+ console.warn(
285
+ "prebuild: franchise has no menu items yet \u2014 generating an empty menu. Add items in the dashboard and rebuild to populate the storefront."
286
+ );
287
+ }
288
+ writeMenuModule(parsed);
289
+ return parsed;
290
+ }
291
+ async function jsonLd({ franchiseId, token }, menuData) {
292
+ const franchise = await fetchData(
293
+ `/franchise-info/franchise/${franchiseId}`,
294
+ token,
295
+ FranchiseSchema
296
+ );
297
+ const url = franchise.site_url;
298
+ const data = buildRestaurantJsonLd(menuData, {
299
+ name: franchise.name,
300
+ url,
301
+ image: url ? `${url}/images/logo.png` : void 0
302
+ });
303
+ const outDir = path.join(process.cwd(), `lib/generated/`);
304
+ mkdirSync(outDir, { recursive: true });
305
+ writeFileSync(
306
+ path.join(outDir, "jsonld.ts"),
307
+ `// AUTO-GENERATED by scripts/prebuild.ts \u2014 do not edit.
308
+ export const restaurantJsonLd = ${JSON.stringify(data, null, 2)};
309
+ `
310
+ );
311
+ }
312
+ async function hours({ franchiseId, token }) {
313
+ await fetchData(`/franchise-info/hours/${franchiseId}`, token, HoursSchema);
314
+ }
315
+ async function styles({ franchiseId, token }) {
316
+ const brand = await fetchData(
317
+ `/franchise-info/styles/${franchiseId}`,
318
+ token,
319
+ BrandingSchema
320
+ );
321
+ const branding = {
322
+ ...brand,
323
+ backgroundElevated: deriveElevatedBackground(brand.backgroundBase),
324
+ backgroundRecessed: deriveRecessedBackground(brand.backgroundBase),
325
+ foreground: deriveFontColor(brand.backgroundBase),
326
+ primaryForeground: deriveFontColor(brand.primary),
327
+ accentForeground: deriveFontColor(brand.accent)
328
+ };
329
+ const stylesDir = path.join(process.cwd(), `public/styles/`);
330
+ mkdirSync(stylesDir, { recursive: true });
331
+ writeFileSync(
332
+ path.join(stylesDir, "styles.json"),
333
+ JSON.stringify(branding, null, 2)
334
+ );
335
+ writeFileSync(
336
+ path.join(process.cwd(), "app", "globals.css"),
337
+ buildGlobalsCss(brand)
338
+ );
339
+ }
340
+ function buildGlobalsCss(branding) {
341
+ const fontFamilyParam = branding.fontFamily.replace(/ /g, "+");
342
+ const foreground = deriveFontColor(branding.backgroundBase);
343
+ const primaryForeground = deriveFontColor(branding.primary);
344
+ const accentForeground = deriveFontColor(branding.accent);
345
+ const backgroundElevated = deriveElevatedBackground(branding.backgroundBase);
346
+ const backgroundRecessed = deriveRecessedBackground(branding.backgroundBase);
347
+ return `
348
+ @import url("https://fonts.googleapis.com/css2?family=${fontFamilyParam}:wght@400;700&display=swap");
349
+ @import "tailwindcss";
350
+ /* Tailwind v4 skips node_modules; @zorgo/next ships un-obfuscated components so
351
+ their class names are scannable here. */
352
+ @source "../node_modules/@zorgo/next/dist/components.mjs";
353
+
354
+ :root {
355
+ --background: ${branding.backgroundBase};
356
+ --background-elevated: ${backgroundElevated};
357
+ --background-recessed: ${backgroundRecessed};
358
+ --foreground: ${foreground};
359
+ --primary: ${branding.primary};
360
+ --primary-foreground: ${primaryForeground};
361
+ --accent: ${branding.accent};
362
+ --accent-foreground: ${accentForeground};
363
+ --font-sans: "${branding.fontFamily}", sans-serif;
364
+ }
365
+
366
+ @theme inline {
367
+ --color-background: var(--background);
368
+ --color-background-elevated: var(--background-elevated);
369
+ --color-background-recessed: var(--background-recessed);
370
+ --color-foreground: var(--foreground);
371
+ --color-primary: var(--primary);
372
+ --color-primary-foreground: var(--primary-foreground);
373
+ --color-accent: var(--accent);
374
+ --color-accent-foreground: var(--accent-foreground);
375
+ --font-sans: var(--font-sans);
376
+ }
377
+
378
+ @layer base {
379
+ button,
380
+ [type="button"],
381
+ [type="submit"],
382
+ [type="reset"] {
383
+ cursor: pointer;
384
+ }
385
+
386
+ button:disabled,
387
+ [type="button"]:disabled,
388
+ [type="submit"]:disabled,
389
+ [type="reset"]:disabled {
390
+ cursor: not-allowed;
391
+ }
392
+ }
393
+ `;
394
+ }
395
+ async function runPrebuild() {
396
+ console.log("running prebuild script...");
397
+ loadEnvConfig(process.cwd());
398
+ writeWranglerToml();
399
+ const token = await fetchSiteToken();
400
+ const encodedPayload = token.split(".")[1];
401
+ if (!encodedPayload) {
402
+ throw new Error("site token is not a well-formed JWT (no payload segment)");
403
+ }
404
+ const payload = JSON.parse(Buffer.from(encodedPayload, "base64url").toString());
405
+ const franchiseId = payload.franchise_ids[0];
406
+ const [menuData] = await Promise.all([
407
+ menu({ franchiseId, token }),
408
+ logo({ franchiseId, token }).catch((err) => console.error("logo failed:", err)),
409
+ hours({ franchiseId, token }).catch((err) => console.error("hours failed:", err)),
410
+ styles({ franchiseId, token }).catch((err) => console.error("styles failed:", err))
411
+ ]);
412
+ await jsonLd({ franchiseId, token }, menuData).catch(
413
+ (err) => console.error("jsonLd failed:", err)
414
+ );
415
+ console.log("prebuild script completed");
416
+ }
417
+ export {
418
+ SiteTokenError,
419
+ fetchSiteToken,
420
+ runPrebuild
421
+ };
422
+ //# sourceMappingURL=server.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server.ts","../src/seo.ts"],"sourcesContent":["// Server-only entry (@zorgo/next/server). Node/Server-Component safe: no React,\n// no \"use client\", no client hooks — so scripts/prebuild.ts and the\n// app/api/zorgo-token route can import the token-exchange and build pipeline\n// from the package instead of scaffolding their own copies. Shipping these here\n// means a package update fixes every site, rather than each site freezing a\n// forked copy at scaffold time.\nimport { writeFileSync, mkdirSync } from \"fs\";\nimport path from \"path\";\nimport { loadEnvConfig } from \"@next/env\";\nimport { z } from \"zod\";\nimport type { Menu } from \"@zorgo/universal/utils/menuUtils\";\nimport { buildRestaurantJsonLd } from \"./seo\";\n\n// localhost fallback keeps a stray dev run from silently hitting production.\n// Read at call time, never at module load: prebuild imports this file before it\n// calls loadEnvConfig(), and ES imports are evaluated first — a module-level\n// read would freeze to the fallback before .env is loaded.\nfunction apiBaseUrl(): string {\n\treturn process.env.NEXT_PUBLIC_API_BASE_URL ?? \"http://localhost:3000\";\n}\n\n/** Why a site token could not be obtained — lets callers report precisely. */\nexport type SiteTokenFailure = \"missing-secret\" | \"rejected\" | \"unreachable\";\n\nexport class SiteTokenError extends Error {\n\treadonly reason: SiteTokenFailure;\n\tconstructor(reason: SiteTokenFailure, message: string, options?: { cause?: unknown }) {\n\t\tsuper(message, options);\n\t\tthis.name = \"SiteTokenError\";\n\t\tthis.reason = reason;\n\t}\n}\n\n/**\n * Exchange ZORGO_SITE_SECRET for a short-lived site token.\n *\n * Throws a {@link SiteTokenError} that distinguishes the three failure modes\n * (secret not set / endpoint rejected the secret / endpoint unreachable) rather\n * than collapsing them into one misleading \"missing secret\" message.\n */\nexport async function fetchSiteToken(): Promise<string> {\n\tconst secret = process.env.ZORGO_SITE_SECRET;\n\tif (!secret) {\n\t\tthrow new SiteTokenError(\n\t\t\t\"missing-secret\",\n\t\t\t\"ZORGO_SITE_SECRET is not set. Add it to this site's .env.\",\n\t\t);\n\t}\n\n\tconst url = `${apiBaseUrl()}/auth/site-token`;\n\tlet res: Response;\n\ttry {\n\t\tres = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"x-zorgo-site-secret\": secret },\n\t\t});\n\t} catch (cause) {\n\t\tthrow new SiteTokenError(\n\t\t\t\"unreachable\",\n\t\t\t`Could not reach the site-token endpoint at ${url}. Check NEXT_PUBLIC_API_BASE_URL and that the API is running.`,\n\t\t\t{ cause },\n\t\t);\n\t}\n\n\tif (!res.ok) {\n\t\tconst body = (await res.text().catch(() => \"\")).slice(0, 200);\n\t\tthrow new SiteTokenError(\n\t\t\t\"rejected\",\n\t\t\t`The site-token endpoint rejected the request (${res.status} ${res.statusText}) at ${url}. ` +\n\t\t\t\t`This usually means ZORGO_SITE_SECRET is wrong for this environment.${body ? ` Response: ${body}` : \"\"}`,\n\t\t);\n\t}\n\n\tconst { token } = (await res.json()) as { token?: string };\n\tif (!token) {\n\t\tthrow new SiteTokenError(\n\t\t\t\"rejected\",\n\t\t\t`The site-token endpoint returned 200 but no token at ${url}.`,\n\t\t);\n\t}\n\treturn token;\n}\n\n// ---------------------------------------------------------------------------\n// Prebuild pipeline\n// ---------------------------------------------------------------------------\n// Everything below runs at build time in a scaffolded site's cwd, fetching\n// franchise data and writing the generated modules/assets the site imports.\n\ninterface FetchArgs {\n\tfranchiseId: number;\n\ttoken: string;\n}\n\nconst BrandingSchema = z\n\t.object({\n\t\tbackgroundBase: z.string().default(\"#F5F5F5\"),\n\t\tprimary: z.string().default(\"#3264FF\"),\n\t\taccent: z.string().default(\"#9696FF\"),\n\t\tfontFamily: z.string().default(\"Inter\"), // Google Font family name\n\t})\n\t.prefault({});\ntype Branding = z.infer<typeof BrandingSchema>;\n\n// A freshly-created franchise commonly has null columns (no site_url set yet,\n// name not filled in). Coerce null|undefined to sensible values instead of\n// letting z.string() throw on null and blow up JSON-LD generation.\nconst FranchiseSchema = z\n\t.object({\n\t\tname: z\n\t\t\t.string()\n\t\t\t.nullish()\n\t\t\t.transform((v) => v ?? process.env.ZORGO_PROJECT_NAME ?? \"Restaurant\"),\n\t\tsite_url: z\n\t\t\t.string()\n\t\t\t.nullish()\n\t\t\t.transform((v) => v ?? undefined),\n\t})\n\t.prefault({});\n\nconst HoursSchema = z.array(z.unknown()).prefault([]);\n\nconst MenuSchema = z.object({\n\titems: z.array(z.unknown()).default([]),\n\tcategories: z.array(z.unknown()).default([]),\n\tcomponents: z.array(z.unknown()).default([]),\n\trules: z.array(z.unknown()).default([]),\n});\n\nasync function fetchData<T>(\n\tendpoint: string,\n\ttoken: string,\n\tschema: z.ZodType<T>,\n): Promise<T> {\n\ttry {\n\t\tconst res = await fetch(`${apiBaseUrl()}${endpoint}`, {\n\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t});\n\t\tif (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);\n\t\tconst body = await res.json();\n\t\treturn schema.parse(body?.data ?? body);\n\t} catch (err) {\n\t\tconsole.error(`prebuild: ${endpoint} failed, using defaults:`, err);\n\t\treturn schema.parse(undefined);\n\t}\n}\n\n// style stuff\nconst FONT_ON_LIGHT = \"#0a0a0a\";\nconst FONT_ON_DARK = \"#f5f5f5\";\n/** Neutral channel delta toward white (elevated) / black (recessed). */\nconst BACKGROUND_SURFACE_DELTA = 15;\n/**\n * Max warm/cool bias via R↔B trade (full strength on light bases).\n * Scaled down by luminance so darker colors shift less.\n */\nconst BACKGROUND_TEMPERATURE_BIAS = 8;\n\nfunction parseHexRgb(background: string): { r: number; g: number; b: number } | null {\n\tconst hex = background.trim().replace(/^#/, \"\");\n\tconst full =\n\t\thex.length === 3\n\t\t\t? hex\n\t\t\t\t\t.split(\"\")\n\t\t\t\t\t.map((c) => c + c)\n\t\t\t\t\t.join(\"\")\n\t\t\t: hex;\n\tif (full.length !== 6 || Number.isNaN(Number.parseInt(full, 16))) {\n\t\treturn null;\n\t}\n\treturn {\n\t\tr: Number.parseInt(full.slice(0, 2), 16),\n\t\tg: Number.parseInt(full.slice(2, 4), 16),\n\t\tb: Number.parseInt(full.slice(4, 6), 16),\n\t};\n}\n\nfunction toHex({ r, g, b }: { r: number; g: number; b: number }): string {\n\treturn `#${[r, g, b].map((c) => c.toString(16).padStart(2, \"0\")).join(\"\")}`;\n}\n\nfunction relativeLuminance({ r, g, b }: { r: number; g: number; b: number }): number {\n\treturn (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n}\n\n/** Temperature bias scaled by luminance; max on light bases, near-zero on dark. */\nfunction temperatureBiasFor({ r, g, b }: { r: number; g: number; b: number }): number {\n\treturn Math.round(BACKGROUND_TEMPERATURE_BIAS * relativeLuminance({ r, g, b }));\n}\n\n/** Off-black on light backgrounds, off-white on dark. */\nfunction deriveFontColor(background: string): string {\n\tconst rgb = parseHexRgb(background);\n\tif (!rgb) return FONT_ON_LIGHT;\n\treturn relativeLuminance(rgb) > 0.5 ? FONT_ON_LIGHT : FONT_ON_DARK;\n}\n\n/** Lighter, slightly warmer surface (cards, raised panels) from backgroundBase. */\nfunction deriveElevatedBackground(background: string): string {\n\tconst rgb = parseHexRgb(background);\n\tif (!rgb) return background;\n\tconst bias = temperatureBiasFor(rgb);\n\tconst warm = Math.round(bias / 4);\n\treturn toHex({\n\t\tr: Math.min(255, rgb.r + BACKGROUND_SURFACE_DELTA + warm),\n\t\tg: Math.min(255, rgb.g + BACKGROUND_SURFACE_DELTA),\n\t\tb: Math.min(255, rgb.b + BACKGROUND_SURFACE_DELTA - bias),\n\t});\n}\n\n/** Darker, slightly cooler surface (wells, inset areas) from backgroundBase. */\nfunction deriveRecessedBackground(background: string): string {\n\tconst rgb = parseHexRgb(background);\n\tif (!rgb) return background;\n\tconst bias = temperatureBiasFor(rgb);\n\tconst cool = Math.round(bias / 4);\n\treturn toHex({\n\t\tr: Math.max(0, rgb.r - BACKGROUND_SURFACE_DELTA - cool),\n\t\tg: Math.max(0, rgb.g - BACKGROUND_SURFACE_DELTA),\n\t\tb: Math.max(0, rgb.b - BACKGROUND_SURFACE_DELTA + bias),\n\t});\n}\n\nfunction writeWranglerToml() {\n\tconst name = process.env.ZORGO_PROJECT_NAME ?? \"zorgo-site\";\n\tconst siteUrl = process.env.NEXT_PUBLIC_SITE_URL ?? \"\";\n\tconst apiUrl = process.env.NEXT_PUBLIC_API_BASE_URL ?? \"\";\n\tconst baseUrl = process.env.NEXT_PUBLIC_BASE_URL ?? siteUrl;\n\tconst supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL ?? \"\";\n\n\t// custom_domain routes need a bare hostname; skip them if the site URL isn't\n\t// a parseable absolute URL (e.g. a local/placeholder value).\n\tlet host: string | undefined;\n\ttry {\n\t\thost = new URL(siteUrl).hostname;\n\t} catch {\n\t\thost = undefined;\n\t}\n\tconst routes = host\n\t\t? `\n[[routes]]\npattern = \"${host}\"\ncustom_domain = true\n\n[[routes]]\npattern = \"www.${host}\"\ncustom_domain = true\n`\n\t\t: \"\";\n\n\t// Omit empty values: opennextjs-cloudflare injects [vars] into the build env, so\n\t// an empty NEXT_PUBLIC_SITE_URL (a site piloted before its URL is set) would land\n\t// as \"\" — a defined-but-empty value that slips past the `?? localhost` fallbacks in\n\t// layout/robots/sitemap and makes new URL(\"\") throw, failing the build/deploy.\n\t// Leaving the var out keeps it `undefined` so those fallbacks fire.\n\tconst vars: Record<string, string> = {\n\t\tNEXT_PUBLIC_SUPABASE_URL: supabaseUrl,\n\t\tNEXT_PUBLIC_API_BASE_URL: apiUrl,\n\t\tNEXT_PUBLIC_SITE_URL: siteUrl,\n\t\tNEXT_PUBLIC_BASE_URL: baseUrl,\n\t};\n\tconst varsBlock = Object.entries(vars)\n\t\t.filter(([, value]) => value !== \"\")\n\t\t.map(([key, value]) => `${key} = \"${value}\"`)\n\t\t.join(\"\\n\");\n\n\tconst toml = `# AUTO-GENERATED by scripts/prebuild.ts from .env — do not edit.\nname = \"${name}\"\nmain = \".open-next/worker.js\"\ncompatibility_date = \"2024-09-23\"\ncompatibility_flags = [\"nodejs_compat\"]\n\n# Bundles the Cloudflare worker as part of \\`wrangler deploy\\` (and \\`wrangler dev\\`),\n# so the deploy command stays a plain \\`wrangler deploy\\`. prebuild (which writes\n# this file + lib/generated) must still run first — on Cloudflare Workers Builds\n# that is the project's Build command; locally it is the npm scripts below.\n[build]\ncommand = \"npx opennextjs-cloudflare build\"\n\n[assets]\ndirectory = \".open-next/assets\"\nbinding = \"ASSETS\"\n\n[vars]\n${varsBlock}\n\n[observability]\nenabled = true\n\n[observability.logs]\nenabled = true\ninvocation_logs = true\n${routes}`;\n\n\twriteFileSync(path.join(process.cwd(), \"wrangler.toml\"), toml);\n}\n\nasync function logo({ franchiseId, token }: FetchArgs) {\n\tconst logoResponse = await fetch(\n\t\t`${apiBaseUrl()}/franchise-info/logo/${franchiseId}`,\n\t\t{ headers: { Authorization: `Bearer ${token}` } },\n\t);\n\n\t// 404 (no logo) returns a JSON body — don't persist it as logo.png, or the\n\t// icon/OG image would render an error blob instead of falling back.\n\tif (!logoResponse.ok) return;\n\n\tconst arrayBuffer = await logoResponse.arrayBuffer();\n\tconst buffer = Buffer.from(arrayBuffer);\n\n\tconst outDir = path.join(process.cwd(), `public/images/`);\n\tmkdirSync(outDir, { recursive: true });\n\twriteFileSync(path.join(outDir, \"logo.png\"), buffer);\n\twriteFileSync(path.join(outDir, \"logo.jpg\"), buffer);\n}\n\nfunction writeMenuModule(menu: Menu) {\n\tconst outDir = path.join(process.cwd(), `lib/generated/`);\n\tmkdirSync(outDir, { recursive: true });\n\t// typed module so consumers get Menu-checked imports instead of an\n\t// untyped runtime fetch of menu.json.\n\twriteFileSync(\n\t\tpath.join(outDir, \"menu.ts\"),\n\t\t`// AUTO-GENERATED by scripts/prebuild.ts — do not edit.\\n` +\n\t\t\t`import type { Menu } from \"@zorgo/next\";\\n\\n` +\n\t\t\t`export const menu: Menu = ${JSON.stringify(menu, null, 2)};\\n`,\n\t);\n}\n\nasync function menu({ franchiseId, token }: FetchArgs): Promise<Menu> {\n\tconst menuResponse = await fetch(\n\t\t`${apiBaseUrl()}/franchise-info/menu/${franchiseId}`,\n\t\t{ headers: { Authorization: `Bearer ${token}` } },\n\t);\n\n\t// A non-ok response is a real failure (auth, server error) — fail loudly.\n\tif (!menuResponse.ok) {\n\t\tthrow new Error(\n\t\t\t`menu fetch failed ${menuResponse.status}: ${await menuResponse.text()}`,\n\t\t);\n\t}\n\n\tconst body = await menuResponse.json();\n\tconst parsed = MenuSchema.parse(body?.data ?? {}) as Menu;\n\n\t// An empty menu is expected for a freshly-initialized franchise that hasn't\n\t// added items yet. Ship a valid empty menu.ts and keep building — the\n\t// storefront renders its empty state instead of failing the whole build.\n\tif (parsed.items.length === 0) {\n\t\tconsole.warn(\n\t\t\t\"prebuild: franchise has no menu items yet — generating an empty menu. \" +\n\t\t\t\t\"Add items in the dashboard and rebuild to populate the storefront.\",\n\t\t);\n\t}\n\n\twriteMenuModule(parsed);\n\treturn parsed;\n}\n\n// franchise row (name, site_url) -> Restaurant JSON-LD, written as a typed\n// module the layout imports and drops into <head>.\nasync function jsonLd({ franchiseId, token }: FetchArgs, menuData: Menu) {\n\tconst franchise = await fetchData(\n\t\t`/franchise-info/franchise/${franchiseId}`,\n\t\ttoken,\n\t\tFranchiseSchema,\n\t);\n\tconst url = franchise.site_url;\n\n\tconst data = buildRestaurantJsonLd(menuData, {\n\t\tname: franchise.name,\n\t\turl,\n\t\timage: url ? `${url}/images/logo.png` : undefined,\n\t});\n\n\tconst outDir = path.join(process.cwd(), `lib/generated/`);\n\tmkdirSync(outDir, { recursive: true });\n\twriteFileSync(\n\t\tpath.join(outDir, \"jsonld.ts\"),\n\t\t`// AUTO-GENERATED by scripts/prebuild.ts — do not edit.\\n` +\n\t\t\t`export const restaurantJsonLd = ${JSON.stringify(data, null, 2)};\\n`,\n\t);\n}\n\nasync function hours({ franchiseId, token }: FetchArgs) {\n\tawait fetchData(`/franchise-info/hours/${franchiseId}`, token, HoursSchema);\n}\n\nasync function styles({ franchiseId, token }: FetchArgs) {\n\tconst brand = await fetchData(\n\t\t`/franchise-info/styles/${franchiseId}`,\n\t\ttoken,\n\t\tBrandingSchema,\n\t);\n\n\t// Same derived palette globals.css uses, persisted as JSON so the build-time\n\t// icon/OG/manifest routes stay on brand (they readFileSync this).\n\tconst branding = {\n\t\t...brand,\n\t\tbackgroundElevated: deriveElevatedBackground(brand.backgroundBase),\n\t\tbackgroundRecessed: deriveRecessedBackground(brand.backgroundBase),\n\t\tforeground: deriveFontColor(brand.backgroundBase),\n\t\tprimaryForeground: deriveFontColor(brand.primary),\n\t\taccentForeground: deriveFontColor(brand.accent),\n\t};\n\n\tconst stylesDir = path.join(process.cwd(), `public/styles/`);\n\tmkdirSync(stylesDir, { recursive: true });\n\twriteFileSync(\n\t\tpath.join(stylesDir, \"styles.json\"),\n\t\tJSON.stringify(branding, null, 2),\n\t);\n\n\twriteFileSync(\n\t\tpath.join(process.cwd(), \"app\", \"globals.css\"),\n\t\tbuildGlobalsCss(brand),\n\t);\n}\n\nfunction buildGlobalsCss(branding: Branding): string {\n\tconst fontFamilyParam = branding.fontFamily.replace(/ /g, \"+\");\n\tconst foreground = deriveFontColor(branding.backgroundBase);\n\tconst primaryForeground = deriveFontColor(branding.primary);\n\tconst accentForeground = deriveFontColor(branding.accent);\n\tconst backgroundElevated = deriveElevatedBackground(branding.backgroundBase);\n\tconst backgroundRecessed = deriveRecessedBackground(branding.backgroundBase);\n\n\treturn `\n@import url(\"https://fonts.googleapis.com/css2?family=${fontFamilyParam}:wght@400;700&display=swap\");\n@import \"tailwindcss\";\n/* Tailwind v4 skips node_modules; @zorgo/next ships un-obfuscated components so\n their class names are scannable here. */\n@source \"../node_modules/@zorgo/next/dist/components.mjs\";\n\n:root {\n --background: ${branding.backgroundBase};\n --background-elevated: ${backgroundElevated};\n --background-recessed: ${backgroundRecessed};\n --foreground: ${foreground};\n --primary: ${branding.primary};\n --primary-foreground: ${primaryForeground};\n --accent: ${branding.accent};\n --accent-foreground: ${accentForeground};\n --font-sans: \"${branding.fontFamily}\", sans-serif;\n}\n\n@theme inline {\n --color-background: var(--background);\n --color-background-elevated: var(--background-elevated);\n --color-background-recessed: var(--background-recessed);\n --color-foreground: var(--foreground);\n --color-primary: var(--primary);\n --color-primary-foreground: var(--primary-foreground);\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n --font-sans: var(--font-sans);\n}\n\n@layer base {\n button,\n [type=\"button\"],\n [type=\"submit\"],\n [type=\"reset\"] {\n cursor: pointer;\n }\n\n button:disabled,\n [type=\"button\"]:disabled,\n [type=\"submit\"]:disabled,\n [type=\"reset\"]:disabled {\n cursor: not-allowed;\n }\n}\n`;\n}\n\n/**\n * Full prebuild pipeline for a scaffolded site. Loads the site's .env, exchanges\n * the site secret for a token, then fetches franchise data and writes the\n * generated modules/assets (wrangler.toml, menu.ts, jsonld.ts, styles, logo).\n * Called from the site's thin scripts/prebuild.ts wrapper.\n */\nexport async function runPrebuild(): Promise<void> {\n\tconsole.log(\"running prebuild script...\");\n\n\t// Load .env here so the wrapper stays a one-liner and can't reintroduce the\n\t// import-order bug (env must be loaded before any env read below).\n\tloadEnvConfig(process.cwd());\n\n\t// regenerate deploy config from .env before any network work\n\twriteWranglerToml();\n\n\tconst token = await fetchSiteToken();\n\n\tconst encodedPayload = token.split(\".\")[1];\n\tif (!encodedPayload) {\n\t\tthrow new Error(\"site token is not a well-formed JWT (no payload segment)\");\n\t}\n\tconst payload = JSON.parse(Buffer.from(encodedPayload, \"base64url\").toString());\n\tconst franchiseId = payload.franchise_ids[0];\n\n\t// menu + franchise feed the JSON-LD; a menu *fetch* failure breaks the build\n\t// loudly, but an empty menu (new franchise) is tolerated inside menu().\n\tconst [menuData] = await Promise.all([\n\t\tmenu({ franchiseId, token }),\n\t\tlogo({ franchiseId, token }).catch((err) => console.error(\"logo failed:\", err)),\n\t\thours({ franchiseId, token }).catch((err) => console.error(\"hours failed:\", err)),\n\t\tstyles({ franchiseId, token }).catch((err) => console.error(\"styles failed:\", err)),\n\t]);\n\n\tawait jsonLd({ franchiseId, token }, menuData).catch((err) =>\n\t\tconsole.error(\"jsonLd failed:\", err),\n\t);\n\n\tconsole.log(\"prebuild script completed\");\n}\n","import type { Menu } from \"@zorgo/universal/utils/menuUtils\";\nimport type { ItemVariant, MenuItem } from \"@zorgo/universal/interfaces\";\n\n/** Franchise-level facts for the Restaurant node. Everything but `name` is\n * optional so the schema degrades gracefully when a field is missing. */\nexport interface RestaurantInfo {\n\tname: string;\n\turl?: string;\n\timage?: string;\n\tdescription?: string;\n\tservesCuisine?: string[];\n}\n\n// cents -> \"5.49\" (schema.org Offer.price is a string in major currency units)\nfunction priceString(cents: number): string {\n\treturn (cents / 100).toFixed(2);\n}\n\nfunction variantOffer(variant: ItemVariant) {\n\treturn {\n\t\t\"@type\": \"Offer\",\n\t\tprice: priceString(variant.display_price ?? variant.price),\n\t\tpriceCurrency: \"USD\",\n\t};\n}\n\nfunction menuItemNode(item: MenuItem) {\n\tconst node: Record<string, unknown> = {\n\t\t\"@type\": \"MenuItem\",\n\t\tname: item.name,\n\t};\n\tif (item.description) node.description = item.description;\n\t// one Offer for a single price, an array when the item has size/variant prices\n\tconst offers = item.variants.map(variantOffer);\n\tif (offers.length === 1) node.offers = offers[0];\n\telse if (offers.length > 1) node.offers = offers;\n\treturn node;\n}\n\n/**\n * Builds a standalone schema.org JSON-LD object for a single menu item, for\n * embedding in that item's `/menu/[slug]` page `<head>`. Reuses `menuItemNode`\n * (the same node shape used inside the Restaurant menu) and adds the\n * `@context` a top-level node needs. Pure — safe to run at build time.\n */\nexport function buildMenuItemJsonLd(item: MenuItem) {\n\treturn { \"@context\": \"https://schema.org\", ...menuItemNode(item) };\n}\n\n/**\n * Builds a schema.org Restaurant JSON-LD object from a prebuilt Menu and\n * franchise info. Categories become MenuSections; the items in each become\n * MenuItems. Pure — same inputs, same output — so it can run at prebuild time\n * and be embedded straight into the site's <head>.\n */\nexport function buildRestaurantJsonLd(menu: Menu, info: RestaurantInfo) {\n\tconst hasMenuSection = menu.categories.map((category) => {\n\t\tconst section: Record<string, unknown> = {\n\t\t\t\"@type\": \"MenuSection\",\n\t\t\tname: category.name,\n\t\t};\n\t\tconst items = menu.items\n\t\t\t.filter((item) => item.category_id === category.category_id)\n\t\t\t.map(menuItemNode);\n\t\tif (items.length) section.hasMenuItem = items;\n\t\treturn section;\n\t});\n\n\tconst restaurant: Record<string, unknown> = {\n\t\t\"@context\": \"https://schema.org\",\n\t\t\"@type\": \"Restaurant\",\n\t\tname: info.name,\n\t};\n\tif (info.url) restaurant.url = info.url;\n\tif (info.image) restaurant.image = info.image;\n\tif (info.description) restaurant.description = info.description;\n\tif (info.servesCuisine?.length) restaurant.servesCuisine = info.servesCuisine;\n\trestaurant.hasMenu = {\n\t\t\"@type\": \"Menu\",\n\t\tname: \"Menu\",\n\t\thasMenuSection,\n\t};\n\n\treturn restaurant;\n}\n"],"mappings":"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","names":["menu","menu"]}
@@ -8,8 +8,10 @@ import { Header, Footer, ModalHost } from "./components";
8
8
  import { CookieConsent } from "@zorgo/next/components";
9
9
  import { restaurantJsonLd } from "../lib/generated/jsonld";
10
10
  export const metadata: Metadata = {
11
- // resolves relative URLs (canonicals, the auto-injected opengraph-image) to absolute
12
- metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000"),
11
+ // resolves relative URLs (canonicals, the auto-injected opengraph-image) to absolute.
12
+ // || (not ??) so an empty NEXT_PUBLIC_SITE_URL — a site piloted before its URL is
13
+ // set — falls back too; new URL("") throws and would break the build/deploy.
14
+ metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3000"),
13
15
  title: {
14
16
  default: ${JSON.stringify(opts.projectName)},
15
17
  template: ${JSON.stringify(`%s | ${opts.projectName}`)},
@@ -1,7 +1,9 @@
1
1
  import type { MetadataRoute } from "next";
2
2
 
3
3
  export default function robots(): MetadataRoute.Robots {
4
- const baseUrl = process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000";
4
+ // || (not ??) so an empty NEXT_PUBLIC_SITE_URL (site piloted before its URL is
5
+ // set) falls back instead of producing a bare "/sitemap.xml".
6
+ const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3000";
5
7
  return {
6
8
  rules: { userAgent: "*", allow: "/", disallow: "/api" },
7
9
  sitemap: `${baseUrl}/sitemap.xml`,
@@ -2,7 +2,9 @@ import type { MetadataRoute } from "next";
2
2
  import { menuItemSlug } from "@zorgo/next/slugs";
3
3
  import { menu } from "../lib/generated/menu";
4
4
 
5
- const BASE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000";
5
+ // || (not ??) so an empty NEXT_PUBLIC_SITE_URL (site piloted before its URL is
6
+ // set) falls back instead of producing relative, unqualified sitemap URLs.
7
+ const BASE_URL = process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3000";
6
8
 
7
9
  // Indexable static pages. Add a route here when you add a page you want crawled.
8
10
  // Deliberately excludes /checkout (transactional, not indexable).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zorgo/next",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "bin": {