shamela 1.3.1 → 1.3.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/index.d.ts CHANGED
@@ -398,28 +398,6 @@ declare const configure: (config: ConfigureOptions) => void;
398
398
  * Clears runtime configuration overrides and restores the default logger.
399
399
  */
400
400
  declare const resetConfig: () => void;
401
- /**
402
- * Creates a default configuration for Node.js environments.
403
- * Automatically sets the correct sqlJsWasmUrl path for bundled environments.
404
- *
405
- * This helper is optional - the library will auto-detect the WASM file location
406
- * in most cases. Use this if you want explicit control or are experiencing issues.
407
- *
408
- * @param config - Your API configuration
409
- * @returns Complete configuration with sqlJsWasmUrl set for Node.js
410
- *
411
- * @example
412
- * ```typescript
413
- * import { configure, createNodeConfig } from 'shamela';
414
- *
415
- * configure(createNodeConfig({
416
- * apiKey: process.env.SHAMELA_API_KEY,
417
- * booksEndpoint: process.env.SHAMELA_BOOKS_ENDPOINT,
418
- * masterPatchEndpoint: process.env.SHAMELA_MASTER_ENDPOINT,
419
- * }));
420
- * ```
421
- */
422
- declare const createNodeConfig: (config: Omit<ShamelaConfig, "sqlJsWasmUrl">) => ShamelaConfig;
423
401
  //#endregion
424
402
  //#region src/content.d.ts
425
403
  type Line = {
@@ -438,5 +416,5 @@ declare const splitPageBodyFromFooter: (content: string, footnoteMarker?: string
438
416
  declare const removeArabicNumericPageMarkers: (text: string) => string;
439
417
  declare const removeTagsExceptSpan: (content: string) => string;
440
418
  //#endregion
441
- export { Author, Book, BookData, Category, type ConfigureOptions, DownloadBookOptions, DownloadMasterOptions, GetBookMetadataOptions, GetBookMetadataResponsePayload, GetMasterMetadataResponsePayload, Line, type Logger, MasterData, OutputOptions, Page, ShamelaConfig, ShamelaConfigKey, Title, configure, createNodeConfig, downloadBook, downloadMasterDatabase, getBook, getBookMetadata, getCoverUrl, getMaster, getMasterMetadata, parseContentRobust, removeArabicNumericPageMarkers, removeTagsExceptSpan, resetConfig, sanitizePageContent, splitPageBodyFromFooter };
419
+ export { Author, Book, BookData, Category, type ConfigureOptions, DownloadBookOptions, DownloadMasterOptions, GetBookMetadataOptions, GetBookMetadataResponsePayload, GetMasterMetadataResponsePayload, Line, type Logger, MasterData, OutputOptions, Page, ShamelaConfig, ShamelaConfigKey, Title, configure, downloadBook, downloadMasterDatabase, getBook, getBookMetadata, getCoverUrl, getMaster, getMasterMetadata, parseContentRobust, removeArabicNumericPageMarkers, removeTagsExceptSpan, resetConfig, sanitizePageContent, splitPageBodyFromFooter };
442
420
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import e from"sql.js";import{unzipSync as t}from"fflate";var n=(e=>typeof require<`u`?require:typeof Proxy<`u`?new Proxy(e,{get:(e,t)=>(typeof require<`u`?require:e)[t]}):e)(function(e){if(typeof require<`u`)return require.apply(this,arguments);throw Error('Calling `require` for "'+e+"\" in an environment that doesn't expose the `require` function.")});const r=Object.freeze({debug:()=>{},error:()=>{},info:()=>{},warn:()=>{}});let i=r;const a=e=>{if(!e){i=r;return}let t=[`debug`,`error`,`info`,`warn`].find(t=>typeof e[t]!=`function`);if(t)throw Error(`Logger must implement debug, error, info, and warn methods. Missing: ${String(t)}`);i=e},o=()=>i,s=()=>{i=r};var c=new Proxy({},{get:(e,t)=>{let n=o(),r=n[t];return typeof r==`function`?(...e)=>r.apply(n,e):r}});let l={};const u={apiKey:`SHAMELA_API_KEY`,booksEndpoint:`SHAMELA_API_BOOKS_ENDPOINT`,masterPatchEndpoint:`SHAMELA_API_MASTER_PATCH_ENDPOINT`,sqlJsWasmUrl:`SHAMELA_SQLJS_WASM_URL`},ee=typeof process<`u`&&!!process?.env,d=e=>{let t=l[e];if(t!==void 0)return t;let n=u[e];if(ee)return process.env[n]},te=e=>{let{logger:t,...n}=e;`logger`in e&&a(t),l={...l,...n}},f=e=>e===`fetchImplementation`?l.fetchImplementation:d(e),p=()=>({apiKey:d(`apiKey`),booksEndpoint:d(`booksEndpoint`),fetchImplementation:l.fetchImplementation,masterPatchEndpoint:d(`masterPatchEndpoint`),sqlJsWasmUrl:d(`sqlJsWasmUrl`)}),m=e=>{if(e===`fetchImplementation`)throw Error(`fetchImplementation must be provided via configure().`);let t=f(e);if(!t)throw Error(`${u[e]} environment variable not set`);return t},ne=()=>{l={},s()},re=e=>{let{join:t}=n(`node:path`);return{...e,sqlJsWasmUrl:t(process.cwd(),`node_modules`,`sql.js`,`dist`,`sql-wasm.wasm`)}};let h=function(e){return e.Authors=`author`,e.Books=`book`,e.Categories=`category`,e.Page=`page`,e.Title=`title`,e}({});const g=(e,t)=>e.query(`PRAGMA table_info(${t})`).all(),_=(e,t)=>!!e.query(`SELECT name FROM sqlite_master WHERE type='table' AND name = ?1`).get(t),v=(e,t)=>_(e,t)?e.query(`SELECT * FROM ${t}`).all():[],y=e=>String(e.is_deleted)===`1`,b=(e,t,n)=>{let r={};for(let i of n){if(i===`id`){r.id=(t??e)?.id??null;continue}if(t&&i in t){let e=t[i];if(e!==`#`&&e!=null){r[i]=e;continue}}if(e&&i in e){r[i]=e[i];continue}r[i]=null}return r},ie=(e,t,n)=>{let r=new Set,i=new Map;for(let t of e)r.add(String(t.id));for(let e of t)i.set(String(e.id),e);let a=[];for(let t of e){let e=i.get(String(t.id));e&&y(e)||a.push(b(t,e,n))}for(let e of t){let t=String(e.id);r.has(t)||y(e)||a.push(b(void 0,e,n))}return a},ae=(e,t,n,r)=>{if(r.length===0)return;let i=n.map(()=>`?`).join(`,`),a=e.prepare(`INSERT INTO ${t} (${n.join(`,`)}) VALUES (${i})`);r.forEach(e=>{let t=n.map(t=>t in e?e[t]:null);a.run(...t)}),a.finalize()},oe=(e,t,n)=>{let r=t.query(`SELECT sql FROM sqlite_master WHERE type='table' AND name = ?1`).get(n);return r?.sql?(e.run(`DROP TABLE IF EXISTS ${n}`),e.run(r.sql),!0):(c.warn(`${n} table definition missing in source database`),!1)},x=(e,t,n,r)=>{if(!_(t,r)){c.warn(`${r} table missing in source database`);return}if(!oe(e,t,r))return;let i=g(t,r),a=n&&_(n,r)?g(n,r):[],o=i.map(e=>e.name);for(let t of a)if(!o.includes(t.name)){let n=t.type&&t.type.length>0?t.type:`TEXT`;e.run(`ALTER TABLE ${r} ADD COLUMN ${t.name} ${n}`),o.push(t.name)}ae(e,r,o,ie(v(t,r),n?v(n,r):[],o))},se=(e,t,n)=>{e.transaction(()=>{x(e,t,n,h.Page),x(e,t,n,h.Title)})()},ce=(e,t)=>{e.transaction(()=>{x(e,t,null,h.Page),x(e,t,null,h.Title)})()},S=e=>{e.run(`CREATE TABLE ${h.Page} (
1
+ import e from"sql.js";import{unzipSync as t}from"fflate";var n=(e=>typeof require<`u`?require:typeof Proxy<`u`?new Proxy(e,{get:(e,t)=>(typeof require<`u`?require:e)[t]}):e)(function(e){if(typeof require<`u`)return require.apply(this,arguments);throw Error('Calling `require` for "'+e+"\" in an environment that doesn't expose the `require` function.")});const r=Object.freeze({debug:()=>{},error:()=>{},info:()=>{},warn:()=>{}});let i=r;const a=e=>{if(!e){i=r;return}let t=[`debug`,`error`,`info`,`warn`].find(t=>typeof e[t]!=`function`);if(t)throw Error(`Logger must implement debug, error, info, and warn methods. Missing: ${String(t)}`);i=e},o=()=>i,s=()=>{i=r};var c=new Proxy({},{get:(e,t)=>{let n=o(),r=n[t];return typeof r==`function`?(...e)=>r.apply(n,e):r}});let l={};const u={apiKey:`SHAMELA_API_KEY`,booksEndpoint:`SHAMELA_API_BOOKS_ENDPOINT`,masterPatchEndpoint:`SHAMELA_API_MASTER_PATCH_ENDPOINT`,sqlJsWasmUrl:`SHAMELA_SQLJS_WASM_URL`},ee=typeof process<`u`&&!!process?.env,d=e=>{let t=l[e];if(t!==void 0)return t;let n=u[e];if(ee)return process.env[n]},te=e=>{let{logger:t,...n}=e;`logger`in e&&a(t),l={...l,...n}},f=e=>e===`fetchImplementation`?l.fetchImplementation:d(e),p=()=>({apiKey:d(`apiKey`),booksEndpoint:d(`booksEndpoint`),fetchImplementation:l.fetchImplementation,masterPatchEndpoint:d(`masterPatchEndpoint`),sqlJsWasmUrl:d(`sqlJsWasmUrl`)}),m=e=>{if(e===`fetchImplementation`)throw Error(`fetchImplementation must be provided via configure().`);let t=f(e);if(!t)throw Error(`${u[e]} environment variable not set`);return t},ne=()=>{l={},s()};let h=function(e){return e.Authors=`author`,e.Books=`book`,e.Categories=`category`,e.Page=`page`,e.Title=`title`,e}({});const g=(e,t)=>e.query(`PRAGMA table_info(${t})`).all(),_=(e,t)=>!!e.query(`SELECT name FROM sqlite_master WHERE type='table' AND name = ?1`).get(t),v=(e,t)=>_(e,t)?e.query(`SELECT * FROM ${t}`).all():[],y=e=>String(e.is_deleted)===`1`,b=(e,t,n)=>{let r={};for(let i of n){if(i===`id`){r.id=(t??e)?.id??null;continue}if(t&&i in t){let e=t[i];if(e!==`#`&&e!=null){r[i]=e;continue}}if(e&&i in e){r[i]=e[i];continue}r[i]=null}return r},re=(e,t,n)=>{let r=new Set,i=new Map;for(let t of e)r.add(String(t.id));for(let e of t)i.set(String(e.id),e);let a=[];for(let t of e){let e=i.get(String(t.id));e&&y(e)||a.push(b(t,e,n))}for(let e of t){let t=String(e.id);r.has(t)||y(e)||a.push(b(void 0,e,n))}return a},ie=(e,t,n,r)=>{if(r.length===0)return;let i=n.map(()=>`?`).join(`,`),a=e.prepare(`INSERT INTO ${t} (${n.join(`,`)}) VALUES (${i})`);r.forEach(e=>{let t=n.map(t=>t in e?e[t]:null);a.run(...t)}),a.finalize()},ae=(e,t,n)=>{let r=t.query(`SELECT sql FROM sqlite_master WHERE type='table' AND name = ?1`).get(n);return r?.sql?(e.run(`DROP TABLE IF EXISTS ${n}`),e.run(r.sql),!0):(c.warn(`${n} table definition missing in source database`),!1)},x=(e,t,n,r)=>{if(!_(t,r)){c.warn(`${r} table missing in source database`);return}if(!ae(e,t,r))return;let i=g(t,r),a=n&&_(n,r)?g(n,r):[],o=i.map(e=>e.name);for(let t of a)if(!o.includes(t.name)){let n=t.type&&t.type.length>0?t.type:`TEXT`;e.run(`ALTER TABLE ${r} ADD COLUMN ${t.name} ${n}`),o.push(t.name)}ie(e,r,o,re(v(t,r),n?v(n,r):[],o))},oe=(e,t,n)=>{e.transaction(()=>{x(e,t,n,h.Page),x(e,t,n,h.Title)})()},se=(e,t)=>{e.transaction(()=>{x(e,t,null,h.Page),x(e,t,null,h.Title)})()},ce=e=>{e.run(`CREATE TABLE ${h.Page} (
2
2
  id INTEGER,
3
3
  content TEXT,
4
4
  part TEXT,
@@ -12,8 +12,8 @@ import e from"sql.js";import{unzipSync as t}from"fflate";var n=(e=>typeof requir
12
12
  page INTEGER,
13
13
  parent INTEGER,
14
14
  is_deleted TEXT
15
- )`)},C=e=>e.query(`SELECT * FROM ${h.Page}`).all(),le=e=>e.query(`SELECT * FROM ${h.Title}`).all(),w=e=>({pages:C(e),titles:le(e)}),T=e=>{try{return n(`node:fs`).existsSync(e)}catch{return!1}},ue=()=>{if(n!==void 0&&n.resolve!==void 0)try{let e=n.resolve(`sql.js`),t=n(`node:path`),r=t.dirname(e),i=t.join(r,`dist`,`sql-wasm.wasm`);if(T(i))return i}catch{}if(typeof process<`u`&&process.cwd)try{let e=n(`node:path`),t=process.cwd(),r=[e.join(t,`node_modules`,`sql.js`,`dist`,`sql-wasm.wasm`),e.join(t,`..`,`node_modules`,`sql.js`,`dist`,`sql-wasm.wasm`),e.join(t,`../..`,`node_modules`,`sql.js`,`dist`,`sql-wasm.wasm`),e.join(t,`.next`,`server`,`node_modules`,`sql.js`,`dist`,`sql-wasm.wasm`)];for(let e of r)if(T(e))return e}catch{}if(n!==void 0&&n.resolve!==void 0&&n.resolve.paths)try{let e=n(`node:path`),t=n.resolve.paths(`sql.js`)||[];for(let n of t){let t=e.join(n,`sql.js`,`dist`,`sql-wasm.wasm`);if(T(t))return t}}catch{}try{if(import.meta.url){let e=new URL(`../../node_modules/sql.js/dist/sql-wasm.wasm`,import.meta.url),t=decodeURIComponent(e.pathname),n=process.platform===`win32`&&t.startsWith(`/`)?t.slice(1):t;if(T(n))return n}}catch{}return null};var de=class{constructor(e){this.statement=e}run=(...e)=>{e.length>0&&this.statement.bind(e),this.statement.step(),this.statement.reset()};finalize=()=>{this.statement.free()}},E=class{constructor(e){this.db=e}run=(e,t=[])=>{this.db.run(e,t)};prepare=e=>new de(this.db.prepare(e));query=e=>({all:(...t)=>this.all(e,t),get:(...t)=>this.get(e,t)});transaction=e=>()=>{this.db.run(`BEGIN TRANSACTION`);try{e(),this.db.run(`COMMIT`)}catch(e){throw this.db.run(`ROLLBACK`),e}};close=()=>{this.db.close()};export=()=>this.db.export();all=(e,t)=>{let n=this.db.prepare(e);try{t.length>0&&n.bind(t);let e=[];for(;n.step();)e.push(n.getAsObject());return e}finally{n.free()}};get=(e,t)=>this.all(e,t)[0]};let D=null,O=null;const fe=typeof process<`u`&&!!process?.versions?.node,pe=()=>{if(!O){let e=f(`sqlJsWasmUrl`);if(e)O=e;else if(fe){let e=ue();if(e)O=e;else{let e=[`Unable to automatically locate sql-wasm.wasm file.`,`This can happen in bundled environments (Next.js, webpack, etc.).`,``,`Quick fix - add this to your code before using shamela:`,``,` import { configure, createNodeConfig } from "shamela";`,` configure(createNodeConfig({`,` apiKey: process.env.SHAMELA_API_KEY,`,` booksEndpoint: process.env.SHAMELA_BOOKS_ENDPOINT,`,` masterPatchEndpoint: process.env.SHAMELA_MASTER_ENDPOINT,`,` }));`,``,`Or manually specify the path:`,``,` import { configure } from "shamela";`,` import { join } from "node:path";`,` configure({`,` sqlJsWasmUrl: join(process.cwd(), "node_modules", "sql.js", "dist", "sql-wasm.wasm")`,` });`].join(`
16
- `);throw Error(e)}}else O=`https://cdn.jsdelivr.net/npm/sql.js@1.13.0/dist/sql-wasm.wasm`}return O},k=()=>(D||=e({locateFile:()=>pe()}),D),A=async()=>new E(new(await(k())).Database),j=async e=>new E(new(await(k())).Database(e)),me=(e,t,n)=>{let r=t.query(`SELECT sql FROM sqlite_master WHERE type='table' AND name = ?1`).get(n);if(!r?.sql)throw Error(`Missing table definition for ${n} in source database`);e.run(`DROP TABLE IF EXISTS ${n}`),e.run(r.sql)},he=async(e,t)=>{let n={author:h.Authors,book:h.Books,category:h.Categories},r={};for(let e of t){let t=n[(e.name.split(`/`).pop()?.split(`\\`).pop()??e.name).replace(/\.(sqlite|db)$/i,``).toLowerCase()];t&&(r[t]=await j(e.data))}try{let t=Object.entries(r);e.transaction(()=>{for(let[n,r]of t){me(e,r,n);let t=r.query(`PRAGMA table_info(${n})`).all().map(e=>e.name);if(t.length===0)continue;let i=r.query(`SELECT * FROM ${n}`).all();if(i.length===0)continue;let a=t.map(()=>`?`).join(`,`),o=t.map(e=>e===`order`?`"order"`:e),s=e.prepare(`INSERT INTO ${n} (${o.join(`,`)}) VALUES (${a})`);try{for(let e of i){let n=t.map(t=>t in e?e[t]:null);s.run(...n)}}finally{s.finalize()}}})()}finally{Object.values(r).forEach(e=>e?.close())}},M=(e,t,n)=>{e.run(`DROP VIEW IF EXISTS ${t}`),e.run(`CREATE VIEW ${t} AS SELECT * FROM ${n}`)},ge=e=>{e.run(`CREATE TABLE ${h.Authors} (
15
+ )`)},S=e=>e.query(`SELECT * FROM ${h.Page}`).all(),C=e=>e.query(`SELECT * FROM ${h.Title}`).all(),w=e=>({pages:S(e),titles:C(e)}),T=e=>{try{return n(`node:fs`).existsSync(e)}catch{return!1}},le=()=>{if(n!==void 0&&n.resolve!==void 0)try{let e=n.resolve(`sql.js`),t=n(`node:path`),r=t.dirname(e),i=t.join(r,`dist`,`sql-wasm.wasm`);if(T(i))return i}catch{}if(typeof process<`u`&&process.cwd)try{let e=n(`node:path`),t=process.cwd(),r=[e.join(t,`node_modules`,`sql.js`,`dist`,`sql-wasm.wasm`),e.join(t,`..`,`node_modules`,`sql.js`,`dist`,`sql-wasm.wasm`),e.join(t,`../..`,`node_modules`,`sql.js`,`dist`,`sql-wasm.wasm`),e.join(t,`.next`,`server`,`node_modules`,`sql.js`,`dist`,`sql-wasm.wasm`)];for(let e of r)if(T(e))return e}catch{}if(n!==void 0&&n.resolve!==void 0&&n.resolve.paths)try{let e=n(`node:path`),t=n.resolve.paths(`sql.js`)||[];for(let n of t){let t=e.join(n,`sql.js`,`dist`,`sql-wasm.wasm`);if(T(t))return t}}catch{}try{if(import.meta.url){let e=new URL(`../../node_modules/sql.js/dist/sql-wasm.wasm`,import.meta.url),t=decodeURIComponent(e.pathname),n=process.platform===`win32`&&t.startsWith(`/`)?t.slice(1):t;if(T(n))return n}}catch{}return null};var ue=class{constructor(e){this.statement=e}run=(...e)=>{e.length>0&&this.statement.bind(e),this.statement.step(),this.statement.reset()};finalize=()=>{this.statement.free()}},E=class{constructor(e){this.db=e}run=(e,t=[])=>{this.db.run(e,t)};prepare=e=>new ue(this.db.prepare(e));query=e=>({all:(...t)=>this.all(e,t),get:(...t)=>this.get(e,t)});transaction=e=>()=>{this.db.run(`BEGIN TRANSACTION`);try{e(),this.db.run(`COMMIT`)}catch(e){throw this.db.run(`ROLLBACK`),e}};close=()=>{this.db.close()};export=()=>this.db.export();all=(e,t)=>{let n=this.db.prepare(e);try{t.length>0&&n.bind(t);let e=[];for(;n.step();)e.push(n.getAsObject());return e}finally{n.free()}};get=(e,t)=>this.all(e,t)[0]};let D=null,O=null;const de=typeof process<`u`&&!!process?.versions?.node,fe=()=>{if(!O){let e=f(`sqlJsWasmUrl`);if(e)O=e;else if(de){let e=le();if(e)O=e;else{let e=[`Unable to automatically locate sql-wasm.wasm file.`,`This can happen in bundled environments (Next.js, webpack, etc.).`,``,`Quick fix - add this to your code before using shamela:`,``,` import { configure, createNodeConfig } from "shamela";`,` configure(createNodeConfig({`,` apiKey: process.env.SHAMELA_API_KEY,`,` booksEndpoint: process.env.SHAMELA_BOOKS_ENDPOINT,`,` masterPatchEndpoint: process.env.SHAMELA_MASTER_ENDPOINT,`,` }));`,``,`Or manually specify the path:`,``,` import { configure } from "shamela";`,` import { join } from "node:path";`,` configure({`,` sqlJsWasmUrl: join(process.cwd(), "node_modules", "sql.js", "dist", "sql-wasm.wasm")`,` });`].join(`
16
+ `);throw Error(e)}}else O=`https://cdn.jsdelivr.net/npm/sql.js@1.13.0/dist/sql-wasm.wasm`}return O},k=()=>(D||=e({locateFile:()=>fe()}),D),A=async()=>new E(new(await(k())).Database),j=async e=>new E(new(await(k())).Database(e)),pe=(e,t,n)=>{let r=t.query(`SELECT sql FROM sqlite_master WHERE type='table' AND name = ?1`).get(n);if(!r?.sql)throw Error(`Missing table definition for ${n} in source database`);e.run(`DROP TABLE IF EXISTS ${n}`),e.run(r.sql)},me=async(e,t)=>{let n={author:h.Authors,book:h.Books,category:h.Categories},r={};for(let e of t){let t=n[(e.name.split(`/`).pop()?.split(`\\`).pop()??e.name).replace(/\.(sqlite|db)$/i,``).toLowerCase()];t&&(r[t]=await j(e.data))}try{let t=Object.entries(r);e.transaction(()=>{for(let[n,r]of t){pe(e,r,n);let t=r.query(`PRAGMA table_info(${n})`).all().map(e=>e.name);if(t.length===0)continue;let i=r.query(`SELECT * FROM ${n}`).all();if(i.length===0)continue;let a=t.map(()=>`?`).join(`,`),o=t.map(e=>e===`order`?`"order"`:e),s=e.prepare(`INSERT INTO ${n} (${o.join(`,`)}) VALUES (${a})`);try{for(let e of i){let n=t.map(t=>t in e?e[t]:null);s.run(...n)}}finally{s.finalize()}}})()}finally{Object.values(r).forEach(e=>e?.close())}},M=(e,t,n)=>{e.run(`DROP VIEW IF EXISTS ${t}`),e.run(`CREATE VIEW ${t} AS SELECT * FROM ${n}`)},he=e=>{e.run(`CREATE TABLE ${h.Authors} (
17
17
  id INTEGER,
18
18
  is_deleted TEXT,
19
19
  name TEXT,
@@ -40,9 +40,9 @@ import e from"sql.js";import{unzipSync as t}from"fflate";var n=(e=>typeof requir
40
40
  is_deleted TEXT,
41
41
  "order" TEXT,
42
42
  name TEXT
43
- )`),M(e,`authors`,h.Authors),M(e,`books`,h.Books),M(e,`categories`,h.Categories)},_e=e=>e.query(`SELECT * FROM ${h.Authors}`).all(),N=e=>e.query(`SELECT * FROM ${h.Books}`).all(),P=e=>e.query(`SELECT * FROM ${h.Categories}`).all(),F=(e,t)=>({authors:_e(e),books:N(e),categories:P(e),version:t}),I=(e,t=[`api_key`,`token`,`password`,`secret`,`auth`])=>{let n=typeof e==`string`?new URL(e):new URL(e.toString());return t.forEach(e=>{let t=n.searchParams.get(e);if(t&&t.length>6){let r=`${t.slice(0,3)}***${t.slice(-3)}`;n.searchParams.set(e,r)}else t&&n.searchParams.set(e,`***`)}),n.toString()},ve=e=>({content:e.content,id:e.id,...e.number&&{number:e.number},...e.page&&{page:Number(e.page)},...e.part&&{part:e.part}}),ye=e=>{let t=Number(e.parent);return{content:e.content,id:e.id,page:Number(e.page),...t&&{parent:t}}},L={"<img[^>]*>>":``,舄:``,"﵀":`رَحِمَهُ ٱللَّٰهُ`,"﵁":`رضي الله عنه`,"﵂":`رَضِيَ ٱللَّٰهُ عَنْهَا`,"﵃":`رَضِيَ اللَّهُ عَنْهُمْ`,"﵄":`رَضِيَ ٱللَّٰهُ عَنْهُمَا`,"﵅":`رَضِيَ اللَّهُ عَنْهُنَّ`,"﵌":`صلى الله عليه وآله وسلم`,"﵏":`رَحِمَهُمُ ٱللَّٰهُ`},R=e=>{let t=new URL(e);return t.protocol=`https`,t.toString()},z=e=>/\.(sqlite|db)$/i.test(e.name),B=e=>e.find(z),V=e=>{let t=/\.([^.]+)$/.exec(e);return t?`.${t[1].toLowerCase()}`:``},H=(e,t,n=!0)=>{let r=new URL(e),i=new URLSearchParams;return Object.entries(t).forEach(([e,t])=>{i.append(e,t.toString())}),n&&i.append(`api_key`,m(`apiKey`)),r.search=i.toString(),r},U=async(e,t={})=>{let n=typeof e==`string`?e:e.toString(),r=await(t.fetchImpl??p().fetchImplementation??fetch)(n);if(!r.ok)throw Error(`Error making request: ${r.status} ${r.statusText}`);if((r.headers.get(`content-type`)??``).includes(`application/json`))return await r.json();let i=await r.arrayBuffer();return new Uint8Array(i)},be=typeof process<`u`&&!!process?.versions?.node,xe=async()=>{if(!be)throw Error(`File system operations are only supported in Node.js environments`);return import(`node:fs/promises`)},Se=async e=>{let[t,n]=await Promise.all([xe(),import(`node:path`)]),r=n.dirname(e);return await t.mkdir(r,{recursive:!0}),t},W=async e=>{let n=await U(e),r=n instanceof Uint8Array?n.length:n&&typeof n.byteLength==`number`?n.byteLength:0;return c.debug(`unzipFromUrl:bytes`,r),new Promise((e,r)=>{let i=n instanceof Uint8Array?n:new Uint8Array(n);try{let n=t(i),r=Object.entries(n).map(([e,t])=>({data:t,name:e}));c.debug(`unzipFromUrl:entries`,r.map(e=>e.name)),e(r)}catch(e){r(Error(`Error processing URL: ${e.message}`))}})},G=async(e,t)=>{if(e.writer){await e.writer(t);return}if(!e.path)throw Error(`Output options must include either a writer or a path`);let n=await Se(e.path);typeof t==`string`?await n.writeFile(e.path,t,`utf-8`):await n.writeFile(e.path,t)},Ce=[`author.sqlite`,`book.sqlite`,`category.sqlite`],K=()=>{let{apiKey:e,booksEndpoint:t,masterPatchEndpoint:n}=p(),r=[[`apiKey`,e],[`booksEndpoint`,t],[`masterPatchEndpoint`,n]].filter(([,e])=>!e).map(([e])=>e);if(r.length)throw Error(`${r.join(`, `)} environment variables not set`)},we=e=>{let t=new Set(e.map(e=>e.match(/[^\\/]+$/)?.[0]??e).map(e=>e.toLowerCase()));return Ce.every(e=>t.has(e.toLowerCase()))},q=async(e,t)=>{c.info(`Setting up book database for ${e}`);let n=t||await Y(e),r=n.minorReleaseUrl?W(n.minorReleaseUrl):Promise.resolve([]),[i,a]=await Promise.all([W(n.majorReleaseUrl),r]),o=B(i);if(!o)throw Error(`Unable to locate book database in archive`);let s=await A();try{c.info(`Creating tables`),S(s);let e=await j(o.data);try{let t=B(a);if(t){c.info(`Applying patches from ${t.name} to ${o.name}`);let n=await j(t.data);try{se(s,e,n)}finally{n.close()}}else c.info(`Copying table data from ${o.name}`),ce(s,e)}finally{e.close()}return{cleanup:async()=>{s.close()},client:s}}catch(e){throw s.close(),e}},J=async e=>{c.info(`Setting up master database`);let t=e||await X(0);c.info(`Downloading master database ${t.version} from: ${I(t.url)}`);let n=await W(R(t.url));if(c.debug?.(`sourceTables downloaded: ${n.map(e=>e.name).toString()}`),!we(n.map(e=>e.name)))throw c.error(`Some source tables were not found: ${n.map(e=>e.name).toString()}`),Error(`Expected tables not found!`);let r=await A();try{return c.info(`Creating master tables`),ge(r),c.info(`Copying data to master table`),await he(r,n.filter(z)),{cleanup:async()=>{r.close()},client:r,version:t.version}}catch(e){throw r.close(),e}},Y=async(e,t)=>{K();let n=H(`${m(`booksEndpoint`)}/${e}`,{major_release:(t?.majorVersion||0).toString(),minor_release:(t?.minorVersion||0).toString()});c.info(`Fetching shamela.ws book link: ${I(n)}`);try{let e=await U(n);return{majorRelease:e.major_release,majorReleaseUrl:R(e.major_release_url),...e.minor_release_url&&{minorReleaseUrl:R(e.minor_release_url)},...e.minor_release_url&&{minorRelease:e.minor_release}}}catch(e){throw Error(`Error fetching book metadata: ${e.message}`)}},Te=async(e,t)=>{if(c.info(`downloadBook ${e} ${JSON.stringify(t)}`),!t.outputFile.path)throw Error(`outputFile.path must be provided to determine output format`);let n=V(t.outputFile.path).toLowerCase(),{client:r,cleanup:i}=await q(e,t?.bookMetadata);try{if(n===`.json`){let e=await w(r);await G(t.outputFile,JSON.stringify(e,null,2))}else if(n===`.db`||n===`.sqlite`){let e=r.export();await G(t.outputFile,e)}else throw Error(`Unsupported output extension: ${n}`)}finally{await i()}return t.outputFile.path},X=async(e=0)=>{K();let t=H(m(`masterPatchEndpoint`),{version:e.toString()});c.info(`Fetching shamela.ws master database patch link: ${I(t)}`);try{let e=await U(t);return{url:e.patch_url,version:e.version}}catch(e){throw Error(`Error fetching master patch: ${e.message}`)}},Ee=e=>{let t=m(`masterPatchEndpoint`),{origin:n}=new URL(t);return`${n}/covers/${e}.jpg`},De=async e=>{if(c.info(`downloadMasterDatabase ${JSON.stringify(e)}`),!e.outputFile.path)throw Error(`outputFile.path must be provided to determine output format`);let t=V(e.outputFile.path),{client:n,cleanup:r,version:i}=await J(e.masterMetadata);try{if(t===`.json`){let t=F(n,i);await G(e.outputFile,JSON.stringify(t,null,2))}else if(t===`.db`||t===`.sqlite`)await G(e.outputFile,n.export());else throw Error(`Unsupported output extension: ${t}`)}finally{await r()}return e.outputFile.path},Oe=async e=>{c.info(`getBook ${e}`);let{client:t,cleanup:n}=await q(e);try{let e=await w(t);return{pages:e.pages.map(ve),titles:e.titles.map(ye)}}finally{await n()}},ke=async()=>{c.info(`getMaster`);let{client:e,cleanup:t,version:n}=await J();try{return F(e,n)}finally{await t()}},Ae=/^[)\]\u00BB"”'’.,?!:\u061B\u060C\u061F\u06D4\u2026]+$/,je=/[[({«“‘]$/,Me=e=>{let t=[];for(let n of e){let e=t[t.length-1];e?.id&&Ae.test(n.text)?e.text+=n.text:t.push(n)}return t},Ne=e=>{let t=e.replace(/\r\n/g,`
43
+ )`),M(e,`authors`,h.Authors),M(e,`books`,h.Books),M(e,`categories`,h.Categories)},ge=e=>e.query(`SELECT * FROM ${h.Authors}`).all(),_e=e=>e.query(`SELECT * FROM ${h.Books}`).all(),N=e=>e.query(`SELECT * FROM ${h.Categories}`).all(),P=(e,t)=>({authors:ge(e),books:_e(e),categories:N(e),version:t}),F=(e,t=[`api_key`,`token`,`password`,`secret`,`auth`])=>{let n=typeof e==`string`?new URL(e):new URL(e.toString());return t.forEach(e=>{let t=n.searchParams.get(e);if(t&&t.length>6){let r=`${t.slice(0,3)}***${t.slice(-3)}`;n.searchParams.set(e,r)}else t&&n.searchParams.set(e,`***`)}),n.toString()},I=e=>({content:e.content,id:e.id,...e.number&&{number:e.number},...e.page&&{page:Number(e.page)},...e.part&&{part:e.part}}),ve=e=>{let t=Number(e.parent);return{content:e.content,id:e.id,page:Number(e.page),...t&&{parent:t}}},L={"<img[^>]*>>":``,舄:``,"﵀":`رَحِمَهُ ٱللَّٰهُ`,"﵁":`رضي الله عنه`,"﵂":`رَضِيَ ٱللَّٰهُ عَنْهَا`,"﵃":`رَضِيَ اللَّهُ عَنْهُمْ`,"﵄":`رَضِيَ ٱللَّٰهُ عَنْهُمَا`,"﵅":`رَضِيَ اللَّهُ عَنْهُنَّ`,"﵌":`صلى الله عليه وآله وسلم`,"﵏":`رَحِمَهُمُ ٱللَّٰهُ`},R=e=>{let t=new URL(e);return t.protocol=`https`,t.toString()},z=e=>/\.(sqlite|db)$/i.test(e.name),B=e=>e.find(z),V=e=>{let t=/\.([^.]+)$/.exec(e);return t?`.${t[1].toLowerCase()}`:``},H=(e,t,n=!0)=>{let r=new URL(e),i=new URLSearchParams;return Object.entries(t).forEach(([e,t])=>{i.append(e,t.toString())}),n&&i.append(`api_key`,m(`apiKey`)),r.search=i.toString(),r},U=async(e,t={})=>{let n=typeof e==`string`?e:e.toString(),r=await(t.fetchImpl??p().fetchImplementation??fetch)(n);if(!r.ok)throw Error(`Error making request: ${r.status} ${r.statusText}`);if((r.headers.get(`content-type`)??``).includes(`application/json`))return await r.json();let i=await r.arrayBuffer();return new Uint8Array(i)},ye=typeof process<`u`&&!!process?.versions?.node,be=async()=>{if(!ye)throw Error(`File system operations are only supported in Node.js environments`);return import(`node:fs/promises`)},xe=async e=>{let[t,n]=await Promise.all([be(),import(`node:path`)]),r=n.dirname(e);return await t.mkdir(r,{recursive:!0}),t},W=async e=>{let n=await U(e),r=n instanceof Uint8Array?n.length:n&&typeof n.byteLength==`number`?n.byteLength:0;return c.debug(`unzipFromUrl:bytes`,r),new Promise((e,r)=>{let i=n instanceof Uint8Array?n:new Uint8Array(n);try{let n=t(i),r=Object.entries(n).map(([e,t])=>({data:t,name:e}));c.debug(`unzipFromUrl:entries`,r.map(e=>e.name)),e(r)}catch(e){r(Error(`Error processing URL: ${e.message}`))}})},G=async(e,t)=>{if(e.writer){await e.writer(t);return}if(!e.path)throw Error(`Output options must include either a writer or a path`);let n=await xe(e.path);typeof t==`string`?await n.writeFile(e.path,t,`utf-8`):await n.writeFile(e.path,t)},Se=[`author.sqlite`,`book.sqlite`,`category.sqlite`],K=()=>{let{apiKey:e,booksEndpoint:t,masterPatchEndpoint:n}=p(),r=[[`apiKey`,e],[`booksEndpoint`,t],[`masterPatchEndpoint`,n]].filter(([,e])=>!e).map(([e])=>e);if(r.length)throw Error(`${r.join(`, `)} environment variables not set`)},Ce=e=>{let t=new Set(e.map(e=>e.match(/[^\\/]+$/)?.[0]??e).map(e=>e.toLowerCase()));return Se.every(e=>t.has(e.toLowerCase()))},q=async(e,t)=>{c.info(`Setting up book database for ${e}`);let n=t||await Y(e),r=n.minorReleaseUrl?W(n.minorReleaseUrl):Promise.resolve([]),[i,a]=await Promise.all([W(n.majorReleaseUrl),r]),o=B(i);if(!o)throw Error(`Unable to locate book database in archive`);let s=await A();try{c.info(`Creating tables`),ce(s);let e=await j(o.data);try{let t=B(a);if(t){c.info(`Applying patches from ${t.name} to ${o.name}`);let n=await j(t.data);try{oe(s,e,n)}finally{n.close()}}else c.info(`Copying table data from ${o.name}`),se(s,e)}finally{e.close()}return{cleanup:async()=>{s.close()},client:s}}catch(e){throw s.close(),e}},J=async e=>{c.info(`Setting up master database`);let t=e||await X(0);c.info(`Downloading master database ${t.version} from: ${F(t.url)}`);let n=await W(R(t.url));if(c.debug?.(`sourceTables downloaded: ${n.map(e=>e.name).toString()}`),!Ce(n.map(e=>e.name)))throw c.error(`Some source tables were not found: ${n.map(e=>e.name).toString()}`),Error(`Expected tables not found!`);let r=await A();try{return c.info(`Creating master tables`),he(r),c.info(`Copying data to master table`),await me(r,n.filter(z)),{cleanup:async()=>{r.close()},client:r,version:t.version}}catch(e){throw r.close(),e}},Y=async(e,t)=>{K();let n=H(`${m(`booksEndpoint`)}/${e}`,{major_release:(t?.majorVersion||0).toString(),minor_release:(t?.minorVersion||0).toString()});c.info(`Fetching shamela.ws book link: ${F(n)}`);try{let e=await U(n);return{majorRelease:e.major_release,majorReleaseUrl:R(e.major_release_url),...e.minor_release_url&&{minorReleaseUrl:R(e.minor_release_url)},...e.minor_release_url&&{minorRelease:e.minor_release}}}catch(e){throw Error(`Error fetching book metadata: ${e.message}`)}},we=async(e,t)=>{if(c.info(`downloadBook ${e} ${JSON.stringify(t)}`),!t.outputFile.path)throw Error(`outputFile.path must be provided to determine output format`);let n=V(t.outputFile.path).toLowerCase(),{client:r,cleanup:i}=await q(e,t?.bookMetadata);try{if(n===`.json`){let e=await w(r);await G(t.outputFile,JSON.stringify(e,null,2))}else if(n===`.db`||n===`.sqlite`){let e=r.export();await G(t.outputFile,e)}else throw Error(`Unsupported output extension: ${n}`)}finally{await i()}return t.outputFile.path},X=async(e=0)=>{K();let t=H(m(`masterPatchEndpoint`),{version:e.toString()});c.info(`Fetching shamela.ws master database patch link: ${F(t)}`);try{let e=await U(t);return{url:e.patch_url,version:e.version}}catch(e){throw Error(`Error fetching master patch: ${e.message}`)}},Te=e=>{let t=m(`masterPatchEndpoint`),{origin:n}=new URL(t);return`${n}/covers/${e}.jpg`},Ee=async e=>{if(c.info(`downloadMasterDatabase ${JSON.stringify(e)}`),!e.outputFile.path)throw Error(`outputFile.path must be provided to determine output format`);let t=V(e.outputFile.path),{client:n,cleanup:r,version:i}=await J(e.masterMetadata);try{if(t===`.json`){let t=P(n,i);await G(e.outputFile,JSON.stringify(t,null,2))}else if(t===`.db`||t===`.sqlite`)await G(e.outputFile,n.export());else throw Error(`Unsupported output extension: ${t}`)}finally{await r()}return e.outputFile.path},De=async e=>{c.info(`getBook ${e}`);let{client:t,cleanup:n}=await q(e);try{let e=await w(t);return{pages:e.pages.map(I),titles:e.titles.map(ve)}}finally{await n()}},Oe=async()=>{c.info(`getMaster`);let{client:e,cleanup:t,version:n}=await J();try{return P(e,n)}finally{await t()}},ke=/^[)\]\u00BB"”'’.,?!:\u061B\u060C\u061F\u06D4\u2026]+$/,Z=/[[({«“‘]$/,Ae=e=>{let t=[];for(let n of e){let e=t[t.length-1];e?.id&&ke.test(n.text)?e.text+=n.text:t.push(n)}return t},je=e=>{let t=e.replace(/\r\n/g,`
44
44
  `).replace(/\r/g,`
45
45
  `);return/\n/.test(t)||(t=t.replace(/([.?!\u061F\u061B\u06D4\u2026]["“”'’»«)\]]?)\s+(?=[\u0600-\u06FF])/,`$1
46
46
  `)),t.split(`
47
- `).map(e=>e.replace(/^\*+/,``).trim()).filter(Boolean)},Z=e=>Ne(e).map(e=>({text:e})),Q=(e,t)=>{let n=RegExp(`${t}\\s*=\\s*("([^"]*)"|'([^']*)'|([^s>]+))`,`i`),r=e.match(n);if(r)return r[2]??r[3]??r[4]},Pe=e=>{let t=[],n=/<[^>]+>/g,r=0,i;for(i=n.exec(e);i;){i.index>r&&t.push({type:`text`,value:e.slice(r,i.index)});let a=i[0],o=/^<\//.test(a),s=a.match(/^<\/?\s*([a-zA-Z0-9:-]+)/),c=s?s[1].toLowerCase():``;if(o)t.push({name:c,type:`end`});else{let e={};e.id=Q(a,`id`),e[`data-type`]=Q(a,`data-type`),t.push({attributes:e,name:c,type:`start`})}r=n.lastIndex,i=n.exec(e)}return r<e.length&&t.push({type:`text`,value:e.slice(r)}),t},$=(e,t)=>{let n=e[e.length-1];return!t||!n||!n.id||!je.test(n.text)||/\n/.test(t)?!1:(n.text+=t.replace(/^\s+/,``),!0)},Fe=e=>{if(!/<span[^>]*>/i.test(e))return Z(e);let t=Pe(`<root>${e}</root>`),n=[],r=0,i=null,a=e=>{if(!e)return;if(r>0&&i){let t=r===1?e.replace(/^\s+/,``):e;i.text+=t;return}if($(n,e))return;let t=e.trim();t&&n.push(...Z(t))};for(let e of t)e.type===`text`?a(e.value):e.type===`start`&&e.name===`span`?e.attributes[`data-type`]===`title`&&(r===0&&(i={id:e.attributes.id?.replace(/^toc-/,``)??``,text:``},n.push(i)),r+=1):e.type===`end`&&e.name===`span`&&r>0&&(--r,r===0&&(i=null));return Me(n.map(e=>e.id?e:{...e,text:e.text.trim()}).map(e=>e.id?e:{...e,text:e.text})).filter(e=>e.text.length>0)},Ie=Object.entries(L).map(([e,t])=>({regex:new RegExp(e,`g`),replacement:t})),Le=e=>{if(e===L)return Ie;let t=[];for(let n in e)t.push({regex:new RegExp(n,`g`),replacement:e[n]});return t},Re=(e,t=L)=>{let n=Le(t),r=e;for(let e=0;e<n.length;e++){let{regex:t,replacement:i}=n[e];r=r.replace(t,i)}return r},ze=(e,t=`_________`)=>{let n=``,r=e.lastIndexOf(t);return r>=0&&(n=e.slice(r+t.length),e=e.slice(0,r)),[e,n]},Be=e=>e.replace(/\s?⦗[\u0660-\u0669]+⦘\s?/,` `),Ve=e=>(e=e.replace(/<a[^>]*>(.*?)<\/a>/g,`$1`),e=e.replace(/<hadeeth[^>]*>|<\/hadeeth>|<hadeeth-\d+>/g,``),e);export{te as configure,re as createNodeConfig,Te as downloadBook,De as downloadMasterDatabase,Oe as getBook,Y as getBookMetadata,Ee as getCoverUrl,ke as getMaster,X as getMasterMetadata,Fe as parseContentRobust,Be as removeArabicNumericPageMarkers,Ve as removeTagsExceptSpan,ne as resetConfig,Re as sanitizePageContent,ze as splitPageBodyFromFooter};
47
+ `).map(e=>e.replace(/^\*+/,``).trim()).filter(Boolean)},Q=e=>je(e).map(e=>({text:e})),$=(e,t)=>{let n=RegExp(`${t}\\s*=\\s*("([^"]*)"|'([^']*)'|([^s>]+))`,`i`),r=e.match(n);if(r)return r[2]??r[3]??r[4]},Me=e=>{let t=[],n=/<[^>]+>/g,r=0,i;for(i=n.exec(e);i;){i.index>r&&t.push({type:`text`,value:e.slice(r,i.index)});let a=i[0],o=/^<\//.test(a),s=a.match(/^<\/?\s*([a-zA-Z0-9:-]+)/),c=s?s[1].toLowerCase():``;if(o)t.push({name:c,type:`end`});else{let e={};e.id=$(a,`id`),e[`data-type`]=$(a,`data-type`),t.push({attributes:e,name:c,type:`start`})}r=n.lastIndex,i=n.exec(e)}return r<e.length&&t.push({type:`text`,value:e.slice(r)}),t},Ne=(e,t)=>{let n=e[e.length-1];return!t||!n||!n.id||!Z.test(n.text)||/\n/.test(t)?!1:(n.text+=t.replace(/^\s+/,``),!0)},Pe=e=>{if(!/<span[^>]*>/i.test(e))return Q(e);let t=Me(`<root>${e}</root>`),n=[],r=0,i=null,a=e=>{if(!e)return;if(r>0&&i){let t=r===1?e.replace(/^\s+/,``):e;i.text+=t;return}if(Ne(n,e))return;let t=e.trim();t&&n.push(...Q(t))};for(let e of t)e.type===`text`?a(e.value):e.type===`start`&&e.name===`span`?e.attributes[`data-type`]===`title`&&(r===0&&(i={id:e.attributes.id?.replace(/^toc-/,``)??``,text:``},n.push(i)),r+=1):e.type===`end`&&e.name===`span`&&r>0&&(--r,r===0&&(i=null));return Ae(n.map(e=>e.id?e:{...e,text:e.text.trim()}).map(e=>e.id?e:{...e,text:e.text})).filter(e=>e.text.length>0)},Fe=Object.entries(L).map(([e,t])=>({regex:new RegExp(e,`g`),replacement:t})),Ie=e=>{if(e===L)return Fe;let t=[];for(let n in e)t.push({regex:new RegExp(n,`g`),replacement:e[n]});return t},Le=(e,t=L)=>{let n=Ie(t),r=e;for(let e=0;e<n.length;e++){let{regex:t,replacement:i}=n[e];r=r.replace(t,i)}return r},Re=(e,t=`_________`)=>{let n=``,r=e.lastIndexOf(t);return r>=0&&(n=e.slice(r+t.length),e=e.slice(0,r)),[e,n]},ze=e=>e.replace(/\s?⦗[\u0660-\u0669]+⦘\s?/,` `),Be=e=>(e=e.replace(/<a[^>]*>(.*?)<\/a>/g,`$1`),e=e.replace(/<hadeeth[^>]*>|<\/hadeeth>|<hadeeth-\d+>/g,``),e);export{te as configure,we as downloadBook,Ee as downloadMasterDatabase,De as getBook,Y as getBookMetadata,Te as getCoverUrl,Oe as getMaster,X as getMasterMetadata,Pe as parseContentRobust,ze as removeArabicNumericPageMarkers,Be as removeTagsExceptSpan,ne as resetConfig,Le as sanitizePageContent,Re as splitPageBodyFromFooter};
48
48
  //# sourceMappingURL=index.js.map