next-blog-ai
Version:
AI-powered blog generation and content delivery for Next.js and other frameworks
1 lines • 48.6 kB
Source Map (JSON)
{"version":3,"sources":["../src/core/utils.ts","../src/core/styles.ts","../src/core/client.ts","../src/frameworks/next.ts"],"names":[],"mappings":";AAGO,SAAS,aAAa,KAAqB;AAChD,SAAO,IAAI,QAAQ,aAAa,CAAC,GAAG,WAAW,OAAO,YAAY,CAAC;AACrE;AAKO,SAAS,cAAiB,KAAa;AAC5C,MAAI,QAAQ,QAAQ,QAAQ,QAAW;AACrC,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAI,CAAC,SAAS,cAAc,IAAI,CAAC;AAAA,EAC9C;AAEA,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,SAA8B,CAAC;AAErC,eAAW,OAAO,KAAK;AACrB,UAAI,OAAO,UAAU,eAAe,KAAK,KAAK,GAAG,GAAG;AAClD,cAAM,WAAW,aAAa,GAAG;AACjC,eAAO,QAAQ,IAAI,cAAc,IAAI,GAAG,CAAC;AAAA,MAC3C;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAuBO,SAAS,gBACd,UACA,QACQ;AACR,QAAM,eAAe,OAAO,KAAK,MAAM,EACpC,KAAK,EACL,IAAI,CAAC,QAAQ,GAAG,GAAG,IAAI,OAAO,GAAG,CAAC,EAAE,EACpC,KAAK,GAAG;AAEX,SAAO,GAAG,QAAQ,IAAI,YAAY;AACpC;AAKO,SAAS,cAAc,MAAc,QAAwB;AAElE,MAAI,CAAC;AAAM,WAAO;AAGlB,MAAI,KAAK,SAAS,SAAS,GAAG;AAE5B,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,EAAc,MAAM;AAAA,IACtB;AAAA,EACF;AAGA,SAAO,UAAU,MAAM,WAAW,IAAI;AACxC;;;ACnFO,IAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmP5B,IAAM,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC1NxC,IAAM,kBAAkB;AAMxB,SAAS,YAAoB;AAG3B,MACE,OAAO,YAAY,eACnB,QAAQ,OACR,QAAQ,IAAI,mCAAmC,QAC/C;AAEA,WAAO,QAAQ,IAAI,wBAAwB;AAAA,EAC7C;AAGA,SAAO;AACT;AAKA,IAAM,oBAAoB;AAMnB,IAAM,cAAN,MAAM,YAAW;AAAA;AAAA;AAAA;AAAA,EA6BtB,YAAY,QAA0B;AAxFxC;AAyFI,QAAI,CAAC,OAAO,QAAQ;AAClB,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACvC;AAEA,SAAK,SAAS,OAAO;AACrB,SAAK,SAAS,UAAU;AACxB,SAAK,gBAAgB,OAAO,iBAAiB;AAC7C,SAAK,yBAAyB,OAAO,0BAA0B;AAC/D,SAAK,kBAAkB,OAAO,mBAAmB;AACjD,SAAK,QAAQ,oBAAI,IAAI;AACrB,SAAK,kBAAkB,oBAAI,IAAI;AAC/B,SAAK,eAAe;AAAA,MAClB,cAAa,YAAO,WAAP,mBAAe;AAAA,MAC5B,WAAU,YAAO,WAAP,mBAAe;AAAA,IAC3B;AACA,SAAK,sBAAsB,OAAO;AAGlC,SAAK,eAAe;AAAA,MAClB,GAAG,YAAW;AAAA,MACd,GAAG,OAAO;AAAA,IACZ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,iBACN,UACA,QACQ;AACR,UAAM,eAAe,OAAO,KAAK,MAAM,EACpC,KAAK,EACL,IAAI,CAAC,QAAQ,GAAG,GAAG,IAAI,OAAO,GAAG,CAAC,EAAE,EACpC,KAAK,GAAG;AAEX,WAAO,GAAG,QAAQ,IAAI,YAAY;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAgB,UAAkB,SAAkC;AAnI9E;AAoII,QAAI,mCAAS,aAAa;AACxB,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,KAAK,MAAM,IAAI,QAAQ;AAC1C,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,IACT;AAEA,UAAM,OAAM,wCAAS,QAAT,YAAgB,KAAK;AACjC,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,iBAAiB,WAAW,YAAY,MAAM;AAEpD,QAAI,MAAM,gBAAgB;AACxB,WAAK,MAAM,OAAO,QAAQ;AAC1B,aAAO;AAAA,IACT;AAEA,WAAO,WAAW;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAgB,UAAkB,MAAe;AACvD,SAAK,MAAM,IAAI,UAAU;AAAA,MACvB;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,SAAyB;AAC7C,UAAM,EAAE,cAAc,eAAe,UAAU,OAAO,IAAI,KAAK;AAG/D,QAAI,QAAQ,eAAe,KAAK,IAAI,eAAe,OAAO;AAG1D,YAAQ,KAAK,IAAI,OAAO,QAAQ;AAGhC,QAAI,QAAQ;AACV,YAAM,eAAe;AACrB,YAAM,eAAe,IAAI,eAAe,KAAK,OAAO,IAAI,eAAe;AACvE,cAAQ,QAAQ;AAAA,IAClB;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,MAAM,IAA2B;AAC7C,WAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,YACZ,UACA,SAA8B,CAAC,GAC/B,UAII,CAAC,GACoB;AACzB,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,gBAAgB,EAAE,GAAG,QAAQ,SAAS,KAAK,OAAO;AAGxD,QAAI,WAAW;AACf,QAAI,WAAW,OAAO;AACpB,iBAAW,KAAK,iBAAiB,UAAU,aAAa;AACxD,YAAM,aAAa,KAAK,aAAgB,UAAU,QAAQ,KAAK;AAC/D,UAAI,YAAY;AACd,eAAO,EAAE,MAAM,WAAW;AAAA,MAC5B;AAAA,IACF;AAIA,QAAI,WAAW,OAAO;AACpB,YAAM,YAAY,gBAAgB,UAAU,aAAa;AACzD,YAAM,iBAAiB,KAAK,gBAAgB,IAAI,SAAS;AAEzD,UAAI,gBAAgB;AAElB,eAAO;AAAA,MACT;AAGA,YAAM,iBAAiB,KAAK;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAGA,WAAK,gBAAgB,IAAI,WAAW,cAAc;AAGlD,qBAAe,QAAQ,MAAM;AAC3B,aAAK,gBAAgB,OAAO,SAAS;AAAA,MACvC,CAAC;AAED,aAAO;AAAA,IACT;AAGA,WAAO,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eACZ,UACA,QACA,eACA,SACA,UACyB;AA3Q7B;AA6QI,QAAI,UAAU;AACd,UAAM,aAAa,KAAK,aAAa;AAErC,WAAO,MAAM;AACX,UAAI;AACF,cAAM,MAAM,IAAI,IAAI,GAAG,KAAK,MAAM,IAAI,QAAQ,EAAE;AAGhD,YAAI,WAAW,OAAO;AACpB,iBAAO,QAAQ,aAAa,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AACtD,gBAAI,UAAU,UAAa,UAAU,MAAM;AACzC,kBAAI,aAAa,OAAO,KAAK,OAAO,KAAK,CAAC;AAAA,YAC5C;AAAA,UACF,CAAC;AAAA,QACH;AAGA,cAAM,eAAe;AAAA,UACnB,GAAG,KAAK;AAAA,UACR,IAAG,aAAQ,UAAR,mBAAe;AAAA,QACpB;AAEA,cAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;AAAA,UAC3C;AAAA,UACA,SAAS;AAAA,YACP,gBAAgB;AAAA,UAClB;AAAA,UACA,MACE,WAAW,QACP,KAAK,UAAU,EAAE,GAAG,QAAQ,MAAM,SAAS,KAAK,OAAO,CAAC,IACxD;AAAA;AAAA,UAEN,GAAG;AAAA,QACL,CAAC;AAGD,cAAM,oBACJ,SAAS,UAAU,OACnB,SAAS,WAAW;AAAA,QACpB,SAAS,WAAW;AAEtB,YAAI,CAAC,SAAS,IAAI;AAChB,gBAAM,YAAY,MAAM,SACrB,KAAK,EACL,MAAM,OAAO,EAAE,OAAO,gBAAgB,EAAE;AAC3C,gBAAM,QAAuB;AAAA,YAC3B,SAAS,UAAU,SAAS;AAAA,YAC5B,QAAQ,SAAS;AAAA,YACjB,MAAM,UAAU,QAAQ,QAAQ,SAAS,MAAM;AAAA,UACjD;AAGA,cAAI,qBAAqB,UAAU,YAAY;AAC7C;AACA,kBAAM,QAAQ,KAAK,cAAc,OAAO;AACxC,kBAAM,KAAK,MAAM,KAAK;AACtB;AAAA,UACF;AAEA,iBAAO,EAAE,MAAM;AAAA,QACjB;AAGA,cAAM,UAAU,MAAM,SAAS,KAAK;AACpC,cAAM,iBAAiB,cAAiB,OAAO;AAG/C,YACE,aAAa,UACb,kBACA,OAAO,mBAAmB,UAC1B;AACA,gBAAM,WAAW;AACjB,cAAI,SAAS,WAAW,UAAU,aAAa,UAAU;AAEvD,kBAAM,SACJ,KAAK,aAAa,YAAY;AAGhC,kBAAM,gBACJ,cAAc,WAAW,KAAK;AAGhC,kBAAM,eACJ,kBAAkB,SAAS,cAAc;AAC3C,qBAAS,UAAU,SAAS,QAAQ;AAAA,cAClC;AAAA,cACA,4BAA4B,YAAY;AAAA,YAC1C;AAEA,qBAAS,UAAU,cAAc,SAAS,SAAS,MAAM;AAAA,UAC3D;AAAA,QACF,WACE,aAAa,UACb,kBACA,OAAO,mBAAmB,UAC1B;AACA,gBAAM,WAAW;AACjB,cAAI,SAAS,WAAW,UAAU,aAAa,UAAU;AAEvD,kBAAM,SAAS,KAAK,aAAa,eAAe;AAChD,qBAAS,UAAU,cAAc,SAAS,SAAS,MAAM;AAGzD,gBACE,cAAc,YACd,OAAO,SAAS,aAAa,UAC7B;AACA,uBAAS,WAAW,cAAc,SAAS,UAAU,MAAM;AAAA,YAC7D;AAGA,gBACE,iBAAiB,YACjB,OAAO,SAAS,gBAAgB,UAChC;AACA,uBAAS,cAAc;AAAA,gBACrB,SAAS;AAAA,gBACT;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAGA,YAAI,WAAW,SAAS,UAAU;AAChC,eAAK,aAAa,UAAU,cAAc;AAAA,QAC5C;AAEA,eAAO,EAAE,MAAM,eAAe;AAAA,MAChC,SAAS,KAAK;AAEZ,YAAI,UAAU,YAAY;AACxB;AACA,gBAAM,QAAQ,KAAK,cAAc,OAAO;AACxC,gBAAM,KAAK,MAAM,KAAK;AACtB;AAAA,QACF;AAEA,cAAM,QAAuB;AAAA,UAC3B,SACE,eAAe,QAAQ,IAAI,UAAU;AAAA,UACvC,QAAQ;AAAA,UACR,MAAM;AAAA,QACR;AACA,eAAO,EAAE,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aACJ,UAA2B,CAAC,GACY;AACxC,UAAM,SAAS;AAAA,MACb,MAAM,QAAQ,QAAQ;AAAA,MACtB,UAAU,QAAQ,WAAW;AAAA,MAC7B,QAAQ,QAAQ,UAAU,KAAK;AAAA,MAC/B,SAAS,QAAQ,WAAW,KAAK;AAAA,IACnC;AAEA,WAAO,KAAK,YAA8B,QAAQ,QAAQ;AAAA,MACxD,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YACJ,MACA,UAA2B,CAAC,GACY;AACxC,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,QACL,OAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS;AAAA,MACb;AAAA,MACA,QAAQ,QAAQ,UAAU,KAAK;AAAA,IACjC;AAEA,WAAO,KAAK,YAA8B,QAAQ,QAAQ;AAAA,MACxD,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cACJ,MACuC;AACvC,QAAI,CAAC,KAAK,QAAQ;AAChB,aAAO;AAAA,QACL,OAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO;AAAA,QACL,OAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,SAAS;AACjB,aAAO;AAAA,QACL,OAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAEA,WAAO,KAAK;AAAA,MACV;AAAA,MACA,CAAC;AAAA,MACD;AAAA,QACE,QAAQ;AAAA,QACR,MAAM;AAAA,UACJ,SAAS,KAAK;AAAA,UACd,aAAa,KAAK;AAAA,UAClB,cAAc,KAAK;AAAA,UACnB,SAAS,KAAK;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eACJ,MACA,UAAsB,CAAC,GACY;AACnC,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,QACL,OAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS;AAAA,MACb;AAAA,MACA,UAAU;AAAA,IACZ;AAEA,WAAO,KAAK,YAAyB,YAAY,QAAQ;AAAA,MACvD,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eACJ,UAA8B,CAAC,GACY;AAC3C,UAAM,SAAS;AAAA,MACb,MAAM,QAAQ,QAAQ;AAAA,MACtB,UAAU,QAAQ,WAAW;AAAA,MAC7B,UAAU;AAAA,IACZ;AAEA,WAAO,KAAK,YAAiC,YAAY,QAAQ;AAAA,MAC/D,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBACJ,UAA4B,CAAC,GACY;AACzC,UAAM,SAAS,CAAC;AAEhB,WAAO,KAAK,YAA+B,SAAS,QAAQ;AAAA,MAC1D,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,UAAkB,QAAmC;AAClE,UAAM,WAAW,KAAK,iBAAiB,UAAU,MAAM;AACvD,SAAK,MAAM,OAAO,QAAQ;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,QAA2D;AACnE,QAAI,OAAO,aAAa;AACtB,WAAK,aAAa,cAAc,OAAO;AAAA,IACzC;AAEA,QAAI,OAAO,UAAU;AACnB,WAAK,aAAa,WAAW,OAAO;AAAA,IACtC;AAAA,EACF;AACF;AAAA;AAAA;AAAA;AA1hBa,YAkBa,wBAAgD;AAAA,EACtE,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,eAAe;AAAA,EACf,UAAU;AAAA,EACV,QAAQ;AACV;AAxBK,IAAM,aAAN;AA+hBA,SAAS,iBAAiB,QAAsC;AAErE,QAAM,qBAAqB;AAAA,IACzB,GAAG;AAAA,IACH,qBAAqB,OAAO,uBAAuB;AAAA,MACjD,OAAO;AAAA,MACP,MAAM;AAAA,QACJ,YAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAEA,SAAO,IAAI,WAAW,kBAAkB;AAC1C;;;ACjhBA,SAAS,oBACP,SAC0B;AAC1B,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAGA,SAAO;AAAA,IACL,KAAK,QAAQ;AAAA,IACb,aAAa,QAAQ,WAAW,QAAQ,eAAe;AAAA;AAAA,IAEvD,cAAc;AAAA,MACZ,OACE,QAAQ,WAAW,QAAQ,eAAe,IACrC,aACA;AAAA,MACP,MAAM;AAAA,QACJ,YAAY,QAAQ;AAAA,MACtB;AAAA,IACF;AAAA,IACA,MAAM;AAAA,EACR;AACF;AAKO,SAAS,cACd,IACA;AACA,SAAO,SACL,WACG,MACsB;AAEzB,UAAM,UAAU,KAAK,KAAK,SAAS,CAAC;AACpC,QAAI,WAAW,OAAO,YAAY,YAAY,UAAU,SAAS;AAE/D,YAAM,EAAE,MAAM,GAAG,KAAK,IAAI;AAG1B,YAAM,UAAU;AAAA,QACd,GAAG;AAAA,QACH,OAAO,oBAAoB,IAAI;AAAA,MACjC;AAGA,WAAK,KAAK,SAAS,CAAC,IAAI;AAAA,IAC1B;AAEA,WAAO,GAAG,QAAQ,GAAG,IAAI;AAAA,EAC3B;AACF;AAKA,eAAsB,0BACpB,QACA,UAA+B,CAAC,GACQ;AACxC,QAAM,eAAe,oBAAoB,QAAQ,IAAI;AAGrD,QAAM,EAAE,MAAM,GAAG,YAAY,IAAI;AAEjC,SAAO,OAAO,aAAa;AAAA,IACzB,GAAG;AAAA,IACH,OAAO;AAAA,EACT,CAAC;AACH;AAKA,eAAsB,yBACpB,QACA,MACA,UAA+B,CAAC,GACQ;AACxC,QAAM,eAAe,oBAAoB,QAAQ,IAAI;AAGrD,QAAM,EAAE,MAAM,GAAG,YAAY,IAAI;AAEjC,SAAO,OAAO,YAAY,MAAM;AAAA,IAC9B,GAAG;AAAA,IACH,OAAO;AAAA,EACT,CAAC;AACH;AAKA,eAAsB,4BACpB,QACA,MACA,UAA0B,CAAC,GACQ;AACnC,QAAM,eAAe,oBAAoB,QAAQ,IAAI;AAGrD,QAAM,EAAE,MAAM,GAAG,YAAY,IAAI;AAEjC,SAAO,OAAO,eAAe,MAAM;AAAA,IACjC,GAAG;AAAA,IACH,OAAO;AAAA,EACT,CAAC;AACH;AAKA,eAAsB,4BACpB,QACA,UAAkC,CAAC,GACQ;AAC3C,QAAM,eAAe,oBAAoB,QAAQ,IAAI;AAGrD,QAAM,EAAE,MAAM,GAAG,YAAY,IAAI;AAEjC,SAAO,OAAO,eAAe;AAAA,IAC3B,GAAG;AAAA,IACH,OAAO;AAAA,EACT,CAAC;AACH;AAKA,eAAsB,6BACpB,QACA,UAAgC,CAAC,GACQ;AACzC,QAAM,eAAe,oBAAoB,QAAQ,IAAI;AAGrD,QAAM,EAAE,MAAM,GAAG,YAAY,IAAI;AAEjC,SAAO,OAAO,gBAAgB;AAAA,IAC5B,GAAG;AAAA,IACH,OAAO;AAAA,EACT,CAAC;AACH;AAGO,SAAS,0BACd,QACA,sBAAwC,EAAE,YAAY,EAAE,GAoBxD;AAGA,QAAM,SAAS,IAAI,WAAW,EAAE,OAAO,CAAC;AAGxC,QAAM,oBAAoB,CAAC,YAA+B;AACxD,QAAI,CAAC;AAAqB,aAAO;AACjC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,cAAc,CAAC,UAAU,CAAC,MAAM;AAE9B,YAAM,eAAe;AAAA,QACnB,GAAG;AAAA,QACH,MAAM,QAAQ,QAAQ,kBAAkB,QAAQ,IAAI;AAAA,MACtD;AACA,aAAO,0BAA0B,QAAQ,YAAY;AAAA,IACvD;AAAA,IACA,aAAa,CAAC,MAAM,UAAU,CAAC,MAAM;AACnC,YAAM,eAAe;AAAA,QACnB,GAAG;AAAA,QACH,MAAM,QAAQ,QAAQ,kBAAkB,QAAQ,IAAI;AAAA,MACtD;AACA,aAAO,yBAAyB,QAAQ,MAAM,YAAY;AAAA,IAC5D;AAAA,IACA,gBAAgB,CAAC,MAAM,UAAU,CAAC,MAAM;AACtC,YAAM,eAAe;AAAA,QACnB,GAAG;AAAA,QACH,MAAM,QAAQ,QAAQ,kBAAkB,QAAQ,IAAI;AAAA,MACtD;AACA,aAAO,4BAA4B,QAAQ,MAAM,YAAY;AAAA,IAC/D;AAAA,IACA,gBAAgB,CAAC,UAAU,CAAC,MAAM;AAChC,YAAM,eAAe;AAAA,QACnB,GAAG;AAAA,QACH,MAAM,QAAQ,QAAQ,kBAAkB,QAAQ,IAAI;AAAA,MACtD;AACA,aAAO,4BAA4B,QAAQ,YAAY;AAAA,IACzD;AAAA,IACA,iBAAiB,CAAC,UAAU,CAAC,MAAM;AACjC,YAAM,eAAe;AAAA,QACnB,GAAG;AAAA,QACH,MAAM,QAAQ,QAAQ,kBAAkB,QAAQ,IAAI;AAAA,MACtD;AACA,aAAO,6BAA6B,QAAQ,YAAY;AAAA,IAC1D;AAAA,EACF;AACF","sourcesContent":["/**\n * Converts a snake_case string to camelCase\n */\nexport function snakeToCamel(str: string): string {\n return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n}\n\n/**\n * Deep transforms object keys from snake_case to camelCase\n */\nexport function normalizeKeys<T>(obj: any): T {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => normalizeKeys(item)) as unknown as T;\n }\n\n if (typeof obj === 'object') {\n const newObj: Record<string, any> = {};\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n const camelKey = snakeToCamel(key);\n newObj[camelKey] = normalizeKeys(obj[key]);\n }\n }\n\n return newObj as T;\n }\n\n return obj as T;\n}\n\n/**\n * Check if we're in a browser environment\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\n/**\n * Check if we're in a Node.js environment\n */\nexport function isNode(): boolean {\n return (\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null\n );\n}\n\n/**\n * Create a unique ID for deduplication\n */\nexport function createRequestId(\n endpoint: string,\n params: Record<string, any>\n): string {\n const sortedParams = Object.keys(params)\n .sort()\n .map((key) => `${key}=${params[key]}`)\n .join('&');\n\n return `${endpoint}?${sortedParams}`;\n}\n\n/**\n * Add HTML styles for content rendering\n */\nexport function addHtmlStyles(html: string, styles: string): string {\n // If HTML is empty, return it as is\n if (!html) return html;\n\n // Check if there's already a <style> tag\n if (html.includes('<style>')) {\n // Replace existing style tag with combined styles\n return html.replace(\n /<style>([\\s\\S]*?)<\\/style>/,\n `<style>$1\\n${styles}</style>`\n );\n }\n\n // If no style tag exists, add it at the beginning\n return `<style>${styles}</style>${html}`;\n}\n","/**\n * Default CSS styles for blog content\n */\nexport const DEFAULT_BLOG_STYLES = `\n/* Base styles */\n.next-blog-ai-content {\n line-height: 1.6;\n color: inherit;\n max-width: 100%;\n margin: 0 auto;\n}\n\n/* Headings */\n.next-blog-ai-content h1,\n.next-blog-ai-content h2,\n.next-blog-ai-content h3,\n.next-blog-ai-content h4,\n.next-blog-ai-content h5,\n.next-blog-ai-content h6 {\n margin-top: 2rem;\n margin-bottom: 1rem;\n font-weight: 600;\n line-height: 1.25;\n color: inherit;\n}\n\n.next-blog-ai-content h1 {\n font-size: 2.25rem;\n}\n\n.next-blog-ai-content h2 {\n font-size: 1.75rem;\n border-bottom: 1px solid #eee;\n padding-bottom: 0.3rem;\n}\n\n.next-blog-ai-content h3 {\n font-size: 1.5rem;\n}\n\n.next-blog-ai-content h4 {\n font-size: 1.25rem;\n}\n\n.next-blog-ai-content h5, .next-blog-ai-content h6 {\n font-size: 1rem;\n}\n\n/* Paragraphs and text */\n.next-blog-ai-content p {\n margin-top: 0;\n margin-bottom: 1.5rem;\n}\n\n.next-blog-ai-content strong {\n font-weight: 600;\n}\n\n.next-blog-ai-content em {\n font-style: italic;\n}\n\n/* Lists */\n.next-blog-ai-content ul,\n.next-blog-ai-content ol {\n margin-top: 0;\n margin-bottom: 1.5rem;\n padding-left: 2rem;\n}\n\n.next-blog-ai-content li {\n margin-bottom: 0.5rem;\n}\n\n.next-blog-ai-content li > ul,\n.next-blog-ai-content li > ol {\n margin-top: 0.5rem;\n margin-bottom: 0.5rem;\n}\n\n/* Links */\n.next-blog-ai-content a {\n color: #0070f3;\n text-decoration: none;\n}\n\n.next-blog-ai-content a:hover {\n text-decoration: underline;\n}\n\n/* Blockquotes */\n.next-blog-ai-content blockquote {\n margin: 1.5rem 0;\n padding: 0.5rem 1rem;\n border-left: 4px solid #ddd;\n color: #666;\n background-color: #f9f9f9;\n}\n\n.next-blog-ai-content blockquote > :first-child {\n margin-top: 0;\n}\n\n.next-blog-ai-content blockquote > :last-child {\n margin-bottom: 0;\n}\n\n/* Code blocks */\n.next-blog-ai-content pre {\n margin: 1.5rem 0;\n padding: 1rem;\n overflow: auto;\n background-color: #f6f8fa;\n border-radius: 3px;\n font-size: 0.875rem;\n}\n\n.next-blog-ai-content code {\n font-size: 0.875rem;\n padding: 0.2em 0.4em;\n background-color: rgba(27, 31, 35, 0.05);\n border-radius: 3px;\n}\n\n.next-blog-ai-content pre code {\n padding: 0;\n background-color: transparent;\n}\n\n/* Tables */\n.next-blog-ai-content table {\n width: 100%;\n border-collapse: collapse;\n margin: 1.5rem 0;\n}\n\n.next-blog-ai-content table th,\n.next-blog-ai-content table td {\n padding: 0.5rem 1rem;\n border: 1px solid #e1e4e8;\n}\n\n.next-blog-ai-content table th {\n background-color: #f6f8fa;\n font-weight: 600;\n text-align: left;\n}\n\n.next-blog-ai-content table tr:nth-child(even) {\n background-color: #f7f7f7;\n}\n\n/* Images */\n.next-blog-ai-content img {\n max-width: 100%;\n height: auto;\n display: block;\n margin: 1.5rem auto;\n}\n\n.next-blog-ai-content figure {\n margin: 1.5rem auto;\n text-align: center;\n}\n\n.next-blog-ai-content figcaption {\n font-size: 0.875rem;\n color: #666;\n margin-top: 0.5rem;\n}\n\n/* Comments */\n.next-blog-ai-comments {\n margin-top: 3rem;\n border-top: 1px solid #eee;\n padding-top: 2rem;\n}\n\n.next-blog-ai-comment {\n margin-bottom: 2rem;\n padding: 1rem;\n background-color: #f9f9f9;\n border-radius: 4px;\n}\n\n.next-blog-ai-comment-header {\n display: flex;\n justify-content: space-between;\n margin-bottom: 0.5rem;\n}\n\n.next-blog-ai-comment-author {\n font-weight: 600;\n}\n\n.next-blog-ai-comment-date {\n color: #666;\n font-size: 0.875rem;\n}\n\n.next-blog-ai-comment-content {\n line-height: 1.5;\n}\n\n/* Comment form */\n.next-blog-ai-comment-form {\n margin-top: 2rem;\n}\n\n.next-blog-ai-comment-form label {\n display: block;\n margin-bottom: 0.5rem;\n font-weight: 600;\n}\n\n.next-blog-ai-comment-form input,\n.next-blog-ai-comment-form textarea {\n width: 100%;\n padding: 0.5rem;\n margin-bottom: 1rem;\n border: 1px solid #ddd;\n border-radius: 4px;\n}\n\n.next-blog-ai-comment-form textarea {\n min-height: 6rem;\n}\n\n.next-blog-ai-comment-form button {\n background-color: #0070f3;\n color: white;\n border: none;\n padding: 0.5rem 1rem;\n border-radius: 4px;\n cursor: pointer;\n font-weight: 500;\n}\n\n.next-blog-ai-comment-form button:hover {\n background-color: #0060df;\n}\n`;\n\n/**\n * Default CSS styles for blog list\n */\nexport const DEFAULT_BLOG_LIST_STYLES = `\n/* Blog post list - Grid View (Default) */\n.next-blog-ai-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 2rem;\n margin: 2rem 0;\n}\n\n@media (max-width: 768px) {\n .next-blog-ai-list {\n grid-template-columns: 1fr;\n }\n}\n\n/* Post content padding for grid view */\n.next-blog-ai-post-content {\n padding: 1.5rem;\n display: flex;\n flex-direction: column;\n}\n\n/* List View Styles */\n.next-blog-ai-list.list-view {\n display: block;\n}\n\n.next-blog-ai-list.list-view .next-blog-ai-post-card {\n display: flex;\n flex-direction: row;\n margin-bottom: 2rem;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n}\n\n.next-blog-ai-list.list-view .next-blog-ai-post-card:hover {\n transform: translateY(-4px);\n box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);\n}\n\n.next-blog-ai-list.list-view .next-blog-ai-post-image {\n width: 250px;\n min-width: 250px;\n height: 180px;\n padding-bottom: 0;\n position: relative;\n background-color: #f0f0f0;\n}\n\n.next-blog-ai-list.list-view .next-blog-ai-post-image img {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.next-blog-ai-list.list-view .next-blog-ai-post-content {\n flex: 1;\n padding: 1.5rem;\n display: flex;\n flex-direction: column;\n}\n\n/* Make sure grid view items display correctly */\n.next-blog-ai-list:not(.list-view) .next-blog-ai-post-card {\n display: flex;\n flex-direction: column;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n}\n\n/* Responsive adjustments for list view */\n@media (max-width: 768px) {\n .next-blog-ai-list.list-view .next-blog-ai-post-card {\n flex-direction: column;\n }\n \n .next-blog-ai-list.list-view .next-blog-ai-post-image {\n width: 100%;\n height: 0;\n padding-bottom: 56.25%; /* 16:9 aspect ratio */\n }\n}\n\n.next-blog-ai-post-card {\n display: flex;\n flex-direction: column;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n}\n\n.next-blog-ai-post-title {\n font-size: 1.25rem;\n font-weight: 600;\n margin-top: 0;\n margin-bottom: 0.5rem;\n color: #111;\n}\n\n.next-blog-ai-post-title a {\n color: inherit;\n text-decoration: none;\n}\n\n.next-blog-ai-post-title a:hover {\n color: #0070f3;\n}\n\n.next-blog-ai-post-meta {\n font-size: 0.875rem;\n color: #666;\n margin-bottom: 1rem;\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.next-blog-ai-post-excerpt {\n margin-bottom: 1.5rem;\n flex-grow: 1;\n}\n\n.next-blog-ai-post-footer {\n margin-top: auto;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.next-blog-ai-read-more {\n color: #0070f3;\n text-decoration: none;\n font-weight: 500;\n font-size: 0.875rem;\n}\n\n.next-blog-ai-read-more:hover {\n text-decoration: underline;\n}\n\n.next-blog-ai-comments-count {\n font-size: 0.875rem;\n color: #666;\n}\n\n/* Pagination */\n.next-blog-ai-pagination {\n display: flex;\n justify-content: center;\n margin: 3rem 0;\n gap: 0.5rem;\n}\n\n.next-blog-ai-pagination-item {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 2.5rem;\n height: 2.5rem;\n padding: 0 0.75rem;\n border-radius: 4px;\n background-color: #f0f0f0;\n color: #333;\n text-decoration: none;\n font-weight: 500;\n}\n\n.next-blog-ai-pagination-item:hover {\n background-color: #e0e0e0;\n}\n\n.next-blog-ai-pagination-item.active {\n background-color: #0070f3;\n color: white;\n}\n\n.next-blog-ai-pagination-item.disabled {\n color: #999;\n pointer-events: none;\n}\n`;\n","import {\n ApiResponse,\n BlogListOptions,\n BlogListResponse,\n BlogListSEOOptions,\n BlogListSEOResponse,\n BlogPostOptions,\n BlogPostResponse,\n CacheOptions,\n CommentData,\n CommentResponse,\n ContentFormat,\n ErrorResponse,\n NextBlogAIConfig,\n RetryOptions,\n SEOOptions,\n SEOResponse,\n BlogSlugsOptions,\n BlogSlugsResponse,\n BlogListDisplayFormat,\n} from './types';\nimport { normalizeKeys, createRequestId, addHtmlStyles } from './utils';\nimport { DEFAULT_BLOG_STYLES, DEFAULT_BLOG_LIST_STYLES } from './styles';\n\n/**\n * Default API URL\n * @private\n */\nconst DEFAULT_API_URL = 'https://next-blog-ai.com/api/blog';\n\n/**\n * Get the API URL based on the environment\n * @private\n */\nfunction getApiUrl(): string {\n // Only use development URL if an explicit environment variable is set\n // This should only be used by the package developers internally\n if (\n typeof process !== 'undefined' &&\n process.env &&\n process.env.NEXT_BLOG_AI_LOCAL_DEVELOPMENT === 'true'\n ) {\n // Allow configuring the development URL via env var\n return process.env.NEXT_BLOG_AI_DEV_URL || 'http://localhost:3000/api/blog';\n }\n\n // For all other cases, including when users are developing with our package\n return DEFAULT_API_URL;\n}\n\n/**\n * Default cache TTL (0 = no caching)\n */\nconst DEFAULT_CACHE_TTL = 0;\n\n/**\n * NextBlogAI Client\n * Main class for interacting with the Next-Blog-AI API\n */\nexport class NextBlogAI {\n private apiKey: string;\n private apiUrl: string;\n private defaultFormat: ContentFormat;\n private defaultBlogListDisplay: BlogListDisplayFormat;\n private defaultCacheTTL: number;\n private cache: Map<string, { data: any; timestamp: number }>;\n private retryOptions: Required<RetryOptions>;\n private pendingRequests: Map<string, Promise<ApiResponse<any>>>;\n private customStyles: {\n blogContent?: string;\n blogList?: string;\n };\n private defaultFetchOptions?: Record<string, any>;\n\n /**\n * Default retry options\n */\n private static readonly DEFAULT_RETRY_OPTIONS: Required<RetryOptions> = {\n maxRetries: 3,\n initialDelay: 300,\n backoffFactor: 2,\n maxDelay: 10000,\n jitter: true,\n };\n\n /**\n * Create a new instance of NextBlogAI client\n */\n constructor(config: NextBlogAIConfig) {\n if (!config.apiKey) {\n throw new Error('API key is required');\n }\n\n this.apiKey = config.apiKey;\n this.apiUrl = getApiUrl();\n this.defaultFormat = config.defaultFormat || 'html';\n this.defaultBlogListDisplay = config.defaultBlogListDisplay || 'grid';\n this.defaultCacheTTL = config.defaultCacheTTL || DEFAULT_CACHE_TTL;\n this.cache = new Map();\n this.pendingRequests = new Map();\n this.customStyles = {\n blogContent: config.styles?.blogContent,\n blogList: config.styles?.blogList,\n };\n this.defaultFetchOptions = config.defaultFetchOptions;\n\n // Initialize retry options with defaults\n this.retryOptions = {\n ...NextBlogAI.DEFAULT_RETRY_OPTIONS,\n ...config.retry,\n };\n }\n\n /**\n * Generate a cache key from the request parameters\n */\n private generateCacheKey(\n endpoint: string,\n params: Record<string, any>\n ): string {\n const sortedParams = Object.keys(params)\n .sort()\n .map((key) => `${key}=${params[key]}`)\n .join('&');\n\n return `${endpoint}?${sortedParams}`;\n }\n\n /**\n * Get data from cache if available and not expired\n */\n private getFromCache<T>(cacheKey: string, options?: CacheOptions): T | null {\n if (options?.bypassCache) {\n return null;\n }\n\n const cachedData = this.cache.get(cacheKey);\n if (!cachedData) {\n return null;\n }\n\n const ttl = options?.ttl ?? this.defaultCacheTTL;\n const now = Date.now();\n const expirationTime = cachedData.timestamp + ttl * 1000;\n\n if (now > expirationTime) {\n this.cache.delete(cacheKey);\n return null;\n }\n\n return cachedData.data;\n }\n\n /**\n * Store data in cache\n */\n private storeInCache<T>(cacheKey: string, data: T): void {\n this.cache.set(cacheKey, {\n data,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Calculate retry delay with exponential backoff and optional jitter\n */\n private getRetryDelay(attempt: number): number {\n const { initialDelay, backoffFactor, maxDelay, jitter } = this.retryOptions;\n\n // Calculate exponential backoff\n let delay = initialDelay * Math.pow(backoffFactor, attempt);\n\n // Apply maximum delay cap\n delay = Math.min(delay, maxDelay);\n\n // Add jitter if enabled (±25% randomization)\n if (jitter) {\n const jitterFactor = 0.25;\n const randomFactor = 1 - jitterFactor + Math.random() * jitterFactor * 2;\n delay = delay * randomFactor;\n }\n\n return delay;\n }\n\n /**\n * Sleep for specified milliseconds\n */\n private async sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Make API request with proper error handling and retry mechanism\n */\n private async makeRequest<T>(\n endpoint: string,\n params: Record<string, any> = {},\n options: {\n method?: string;\n body?: any;\n cache?: CacheOptions;\n } = {}\n ): Promise<ApiResponse<T>> {\n const method = options.method || 'GET';\n const requestParams = { ...params, api_key: this.apiKey };\n\n // Generate cache key and check cache for GET requests\n let cacheKey = '';\n if (method === 'GET') {\n cacheKey = this.generateCacheKey(endpoint, requestParams);\n const cachedData = this.getFromCache<T>(cacheKey, options.cache);\n if (cachedData) {\n return { data: cachedData };\n }\n }\n\n // For GET requests, check if there's already a pending request for this exact data\n // This helps deduplicate concurrent requests to the same endpoint with the same params\n if (method === 'GET') {\n const requestId = createRequestId(endpoint, requestParams);\n const pendingRequest = this.pendingRequests.get(requestId);\n\n if (pendingRequest) {\n // Return the existing promise to avoid duplicate requests\n return pendingRequest as Promise<ApiResponse<T>>;\n }\n\n // Create a new request promise\n const requestPromise = this.executeRequest<T>(\n endpoint,\n method,\n requestParams,\n options,\n cacheKey\n );\n\n // Store the promise in the pendingRequests map\n this.pendingRequests.set(requestId, requestPromise);\n\n // Clean up after request completes\n requestPromise.finally(() => {\n this.pendingRequests.delete(requestId);\n });\n\n return requestPromise;\n }\n\n // For non-GET requests, just execute directly without deduplication\n return this.executeRequest<T>(\n endpoint,\n method,\n requestParams,\n options,\n cacheKey\n );\n }\n\n /**\n * Execute the actual API request with retries\n */\n private async executeRequest<T>(\n endpoint: string,\n method: string,\n requestParams: Record<string, any>,\n options: { body?: any; cache?: CacheOptions },\n cacheKey: string\n ): Promise<ApiResponse<T>> {\n // Setup for retries\n let attempt = 0;\n const maxRetries = this.retryOptions.maxRetries;\n\n while (true) {\n try {\n const url = new URL(`${this.apiUrl}/${endpoint}`);\n\n // Add query parameters for GET requests\n if (method === 'GET') {\n Object.entries(requestParams).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n url.searchParams.append(key, String(value));\n }\n });\n }\n\n // Combine default fetch options with request-specific fetch options\n const fetchOptions = {\n ...this.defaultFetchOptions,\n ...options.cache?.fetchOptions,\n };\n\n const response = await fetch(url.toString(), {\n method,\n headers: {\n 'Content-Type': 'application/json',\n },\n body:\n method !== 'GET'\n ? JSON.stringify({ ...options.body, api_key: this.apiKey })\n : undefined,\n // Apply framework-specific fetch options if present\n ...fetchOptions,\n });\n\n // Check if response is retriable (5xx errors or specific 4xx errors)\n const isRetriableStatus =\n response.status >= 500 ||\n response.status === 429 || // Too Many Requests\n response.status === 408; // Request Timeout\n\n if (!response.ok) {\n const errorData = await response\n .json()\n .catch(() => ({ error: 'Unknown error' }));\n const error: ErrorResponse = {\n message: errorData.error || 'An unknown error occurred',\n status: response.status,\n code: errorData.code || `HTTP_${response.status}`,\n };\n\n // If the error is retriable and we haven't exceeded max retries\n if (isRetriableStatus && attempt < maxRetries) {\n attempt++;\n const delay = this.getRetryDelay(attempt);\n await this.sleep(delay);\n continue; // Try again\n }\n\n return { error };\n }\n\n // Parse and normalize the response data\n const rawData = await response.json();\n const normalizedData = normalizeKeys<T>(rawData);\n\n // Enhance HTML content with styles if needed\n if (\n endpoint === 'list' &&\n normalizedData &&\n typeof normalizedData === 'object'\n ) {\n const listData = normalizedData as any;\n if (listData.format === 'html' && 'content' in listData) {\n // Add custom styles to the HTML content\n const styles =\n this.customStyles.blogList || DEFAULT_BLOG_LIST_STYLES;\n\n // Apply display format class to HTML content\n const displayFormat =\n requestParams.display || this.defaultBlogListDisplay;\n\n // Add the display class to the container\n const displayClass =\n displayFormat === 'list' ? 'list-view' : 'grid-view';\n listData.content = listData.content.replace(\n 'class=\"next-blog-ai-list\"',\n `class=\"next-blog-ai-list ${displayClass}\"`\n );\n\n listData.content = addHtmlStyles(listData.content, styles);\n }\n } else if (\n endpoint === 'post' &&\n normalizedData &&\n typeof normalizedData === 'object'\n ) {\n const postData = normalizedData as any;\n if (postData.format === 'html' && 'content' in postData) {\n // Add custom styles to the HTML content\n const styles = this.customStyles.blogContent || DEFAULT_BLOG_STYLES;\n postData.content = addHtmlStyles(postData.content, styles);\n\n // Also style the comments if present\n if (\n 'comments' in postData &&\n typeof postData.comments === 'string'\n ) {\n postData.comments = addHtmlStyles(postData.comments, styles);\n }\n\n // And the comment form\n if (\n 'commentForm' in postData &&\n typeof postData.commentForm === 'string'\n ) {\n postData.commentForm = addHtmlStyles(\n postData.commentForm,\n styles\n );\n }\n }\n }\n\n // Cache the result for GET requests\n if (method === 'GET' && cacheKey) {\n this.storeInCache(cacheKey, normalizedData);\n }\n\n return { data: normalizedData };\n } catch (err) {\n // Network errors are retriable\n if (attempt < maxRetries) {\n attempt++;\n const delay = this.getRetryDelay(attempt);\n await this.sleep(delay);\n continue; // Try again\n }\n\n const error: ErrorResponse = {\n message:\n err instanceof Error ? err.message : 'Network error occurred',\n status: 0,\n code: 'NETWORK_ERROR',\n };\n return { error };\n }\n }\n }\n\n /**\n * Get a list of blog posts\n */\n async getBlogPosts(\n options: BlogListOptions = {}\n ): Promise<ApiResponse<BlogListResponse>> {\n const params = {\n page: options.page || 1,\n per_page: options.perPage || 10,\n format: options.format || this.defaultFormat,\n display: options.display || this.defaultBlogListDisplay,\n };\n\n return this.makeRequest<BlogListResponse>('list', params, {\n cache: options.cache,\n });\n }\n\n /**\n * Get a single blog post by slug\n */\n async getBlogPost(\n slug: string,\n options: BlogPostOptions = {}\n ): Promise<ApiResponse<BlogPostResponse>> {\n if (!slug) {\n return {\n error: {\n message: 'Slug is required',\n status: 400,\n },\n };\n }\n\n const params = {\n slug,\n format: options.format || this.defaultFormat,\n };\n\n return this.makeRequest<BlogPostResponse>('post', params, {\n cache: options.cache,\n });\n }\n\n /**\n * Submit a comment on a blog post\n */\n async submitComment(\n data: CommentData\n ): Promise<ApiResponse<CommentResponse>> {\n if (!data.postId) {\n return {\n error: {\n message: 'Post ID is required',\n status: 400,\n },\n };\n }\n\n if (!data.authorName) {\n return {\n error: {\n message: 'Author name is required',\n status: 400,\n },\n };\n }\n\n if (!data.content) {\n return {\n error: {\n message: 'Comment content is required',\n status: 400,\n },\n };\n }\n\n return this.makeRequest<CommentResponse>(\n 'comment',\n {},\n {\n method: 'POST',\n body: {\n post_id: data.postId,\n author_name: data.authorName,\n author_email: data.authorEmail,\n content: data.content,\n },\n }\n );\n }\n\n /**\n * Get only SEO metadata for a blog post by slug\n * Optimized version that doesn't fetch the full content\n */\n async getBlogPostSEO(\n slug: string,\n options: SEOOptions = {}\n ): Promise<ApiResponse<SEOResponse>> {\n if (!slug) {\n return {\n error: {\n message: 'Slug is required',\n status: 400,\n },\n };\n }\n\n const params = {\n slug,\n seo_only: true,\n };\n\n return this.makeRequest<SEOResponse>('post/seo', params, {\n cache: options.cache,\n });\n }\n\n /**\n * Get only SEO metadata for blog list\n * Optimized version that doesn't fetch the full content\n */\n async getBlogListSEO(\n options: BlogListSEOOptions = {}\n ): Promise<ApiResponse<BlogListSEOResponse>> {\n const params = {\n page: options.page || 1,\n per_page: options.perPage || 10,\n seo_only: true,\n };\n\n return this.makeRequest<BlogListSEOResponse>('list/seo', params, {\n cache: options.cache,\n });\n }\n\n /**\n * Get all blog post slugs\n * Useful for static site generation in frameworks like Next.js\n */\n async getAllBlogSlugs(\n options: BlogSlugsOptions = {}\n ): Promise<ApiResponse<BlogSlugsResponse>> {\n const params = {};\n\n return this.makeRequest<BlogSlugsResponse>('slugs', params, {\n cache: options.cache,\n });\n }\n\n /**\n * Clear the entire cache\n */\n clearCache(): void {\n this.cache.clear();\n }\n\n /**\n * Clear a specific item from the cache\n */\n clearCacheItem(endpoint: string, params: Record<string, any>): void {\n const cacheKey = this.generateCacheKey(endpoint, params);\n this.cache.delete(cacheKey);\n }\n\n /**\n * Set custom styles for HTML content\n */\n setStyles(styles: { blogContent?: string; blogList?: string }): void {\n if (styles.blogContent) {\n this.customStyles.blogContent = styles.blogContent;\n }\n\n if (styles.blogList) {\n this.customStyles.blogList = styles.blogList;\n }\n }\n}\n\n/**\n * Factory function to create a new NextBlogAI instance\n */\nexport function createNextBlogAI(config: NextBlogAIConfig): NextBlogAI {\n // Apply default fetch options for Next.js if not specified\n const configWithDefaults = {\n ...config,\n defaultFetchOptions: config.defaultFetchOptions || {\n cache: 'no-store' as RequestCache,\n next: {\n revalidate: 0,\n },\n },\n };\n\n return new NextBlogAI(configWithDefaults);\n}\n","import { NextBlogAI, createNextBlogAI } from '../core/client';\nimport {\n ApiResponse,\n BlogListOptions,\n BlogListResponse,\n BlogListSEOOptions,\n BlogListSEOResponse,\n BlogPostOptions,\n BlogPostResponse,\n CacheOptions,\n SEOOptions,\n SEOResponse,\n BlogSlugsOptions,\n BlogSlugsResponse,\n} from '../core/types';\n\n/**\n * Next.js specific caching options\n */\nexport interface NextCacheOptions {\n /**\n * Next.js revalidation time in seconds\n * When set to 0, cache will be bypassed completely (equivalent to dynamic: true)\n */\n revalidate?: number;\n\n /**\n * Force dynamic rendering without caching\n */\n dynamic?: boolean;\n}\n\n/**\n * Blog list options with Next.js specific caching\n */\nexport interface NextBlogListOptions extends Omit<BlogListOptions, 'cache'> {\n /**\n * Next.js specific caching options\n */\n next?: NextCacheOptions;\n}\n\n/**\n * Blog post options with Next.js specific caching\n */\nexport interface NextBlogPostOptions extends Omit<BlogPostOptions, 'cache'> {\n /**\n * Next.js specific caching options\n */\n next?: NextCacheOptions;\n}\n\n/**\n * SEO options with Next.js specific caching\n */\nexport interface NextSEOOptions extends Omit<SEOOptions, 'cache'> {\n /**\n * Next.js specific caching options\n */\n next?: NextCacheOptions;\n}\n\n/**\n * Blog list SEO options with Next.js specific caching\n */\nexport interface NextBlogListSEOOptions\n extends Omit<BlogListSEOOptions, 'cache'> {\n /**\n * Next.js specific caching options\n */\n next?: NextCacheOptions;\n}\n\n/**\n * Blog slugs options with Next.js specific caching\n */\nexport interface NextBlogSlugsOptions extends Omit<BlogSlugsOptions, 'cache'> {\n /**\n * Next.js specific caching options\n */\n next?: NextCacheOptions;\n}\n\n/**\n * Map Next.js caching options to NextBlogAI cache options\n */\nfunction mapNextCacheOptions(\n options?: NextCacheOptions\n): CacheOptions | undefined {\n if (!options) {\n return undefined;\n }\n\n // Create cache options with Next.js specific fetch directives\n return {\n ttl: options.revalidate,\n bypassCache: options.dynamic || options.revalidate === 0,\n // Include the framework-specific fetch options\n fetchOptions: {\n cache:\n options.dynamic || options.revalidate === 0\n ? ('no-store' as RequestCache)\n : ('force-cache' as RequestCache),\n next: {\n revalidate: options.revalidate,\n },\n },\n next: options,\n };\n}\n\n/**\n * Higher-order function that wraps a NextBlogAI method with Next.js caching\n */\nexport function withNextCache<T, O extends object>(\n fn: (client: NextBlogAI, ...args: any[]) => Promise<ApiResponse<T>>\n) {\n return function (\n client: NextBlogAI,\n ...args: any[]\n ): Promise<ApiResponse<T>> {\n // Map Next.js options to NextBlogAI cache options\n const lastArg = args[args.length - 1];\n if (lastArg && typeof lastArg === 'object' && 'next' in lastArg) {\n // Clone the options and remove 'next'\n const { next, ...rest } = lastArg;\n\n // Map Next.js cache options to normal cache options\n const options = {\n ...rest,\n cache: mapNextCacheOptions(next),\n };\n\n // Replace the last argument\n args[args.length - 1] = options;\n }\n\n return fn(client, ...args);\n };\n}\n\n/**\n * Get blog posts with Next.js caching\n */\nexport async function getBlogPostsWithNextCache(\n client: NextBlogAI,\n options: NextBlogListOptions = {}\n): Promise<ApiResponse<BlogListResponse>> {\n const cacheOptions = mapNextCacheOptions(options.next);\n\n // Remove the next property to avoid conflicts\n const { next, ...restOptions } = options;\n\n return client.getBlogPosts({\n ...restOptions,\n cache: cacheOptions,\n });\n}\n\n/**\n * Get a blog post with Next.js caching\n */\nexport async function getBlogPostWithNextCache(\n client: NextBlogAI,\n slug: string,\n options: NextBlogPostOptions = {}\n): Promise<ApiResponse<BlogPostResponse>> {\n const cacheOptions = mapNextCacheOptions(options.next);\n\n // Remove the next property to avoid conflicts\n const { next, ...restOptions } = options;\n\n return client.getBlogPost(slug, {\n ...restOptions,\n cache: cacheOptions,\n });\n}\n\n/**\n * Get blog post SEO metadata with Next.js caching\n */\nexport async function getBlogPostSEOWithNextCache(\n client: NextBlogAI,\n slug: string,\n options: NextSEOOptions = {}\n): Promise<ApiResponse<SEOResponse>> {\n const cacheOptions = mapNextCacheOptions(options.next);\n\n // Remove the next property to avoid conflicts\n const { next, ...restOptions } = options;\n\n return client.getBlogPostSEO(slug, {\n ...restOptions,\n cache: cacheOptions,\n });\n}\n\n/**\n * Get blog list SEO metadata with Next.js caching\n */\nexport async function getBlogListSEOWithNextCache(\n client: NextBlogAI,\n options: NextBlogListSEOOptions = {}\n): Promise<ApiResponse<BlogListSEOResponse>> {\n const cacheOptions = mapNextCacheOptions(options.next);\n\n // Remove the next property to avoid conflicts\n const { next, ...restOptions } = options;\n\n return client.getBlogListSEO({\n ...restOptions,\n cache: cacheOptions,\n });\n}\n\n/**\n * Get all blog slugs with Next.js caching\n */\nexport async function getAllBlogSlugsWithNextCache(\n client: NextBlogAI,\n options: NextBlogSlugsOptions = {}\n): Promise<ApiResponse<BlogSlugsResponse>> {\n const cacheOptions = mapNextCacheOptions(options.next);\n\n // Remove the next property to avoid conflicts\n const { next, ...restOptions } = options;\n\n return client.getAllBlogSlugs({\n ...restOptions,\n cache: cacheOptions,\n });\n}\n\n// Export a convenience function for Next.js projects\nexport function createNextBlogAIForNextJs(\n apiKey: string,\n defaultCacheOptions: NextCacheOptions = { revalidate: 0 }\n): {\n client: NextBlogAI;\n getBlogPosts: (\n options?: NextBlogListOptions\n ) => Promise<ApiResponse<BlogListResponse>>;\n getBlogPost: (\n slug: string,\n options?: NextBlogPostOptions\n ) => Promise<ApiResponse<BlogPostResponse>>;\n getBlogPostSEO: (\n slug: string,\n options?: NextSEOOptions\n ) => Promise<ApiResponse<SEOResponse>>;\n getBlogListSEO: (\n options?: NextBlogListSEOOptions\n ) => Promise<ApiResponse<BlogListSEOResponse>>;\n getAllBlogSlugs: (\n options?: NextBlogSlugsOptions\n ) => Promise<ApiResponse<BlogSlugsResponse>>;\n} {\n // Create the client - no need to pass fetch options here\n // as they will be included in each request's cache options\n const client = new NextBlogAI({ apiKey });\n\n // Helper to merge default cache options with user-provided options\n const mergeWithDefaults = (options?: NextCacheOptions) => {\n if (!defaultCacheOptions) return options;\n return {\n ...defaultCacheOptions,\n ...options,\n };\n };\n\n return {\n client,\n getBlogPosts: (options = {}) => {\n // Apply default cache options if user didn't specify their own\n const finalOptions = {\n ...options,\n next: options.next || mergeWithDefaults(options.next),\n };\n return getBlogPostsWithNextCache(client, finalOptions);\n },\n getBlogPost: (slug, options = {}) => {\n const finalOptions = {\n ...options,\n next: options.next || mergeWithDefaults(options.next),\n };\n return getBlogPostWithNextCache(client, slug, finalOptions);\n },\n getBlogPostSEO: (slug, options = {}) => {\n const finalOptions = {\n ...options,\n next: options.next || mergeWithDefaults(options.next),\n };\n return getBlogPostSEOWithNextCache(client, slug, finalOptions);\n },\n getBlogListSEO: (options = {}) => {\n const finalOptions = {\n ...options,\n next: options.next || mergeWithDefaults(options.next),\n };\n return getBlogListSEOWithNextCache(client, finalOptions);\n },\n getAllBlogSlugs: (options = {}) => {\n const finalOptions = {\n ...options,\n next: options.next || mergeWithDefaults(options.next),\n };\n return getAllBlogSlugsWithNextCache(client, finalOptions);\n },\n };\n}\n"]}