shamela 1.0.1 → 1.0.3

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/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Shamela
2
2
 
3
- [![wakatime](https://wakatime.com/badge/user/a0b906ce-b8e7-4463-8bce-383238df6d4b/project/faef70ab-efdb-448b-ab83-0fc66c95888e.svg)](https://wakatime.com/badge/user/a0b906ce-b8e7-4463-8bce-383238df6d4b/project/faef70ab-efdb-448b-ab83-0fc66c95888e) [![E2E](https://github.com/ragaeeb/shamela/actions/workflows/e2e.yml/badge.svg)](https://github.com/ragaeeb/shamela/actions/workflows/e2e.yml) [![Node.js CI](https://github.com/ragaeeb/shamela/actions/workflows/build.yml/badge.svg)](https://github.com/ragaeeb/shamela/actions/workflows/build.yml) ![GitHub License](https://img.shields.io/github/license/ragaeeb/shamela) ![GitHub Release](https://img.shields.io/github/v/release/ragaeeb/shamela) [![codecov](https://codecov.io/gh/ragaeeb/shamela/graph/badge.svg?token=PK55V1R324)](https://codecov.io/gh/ragaeeb/shamela) [![Size](https://deno.bundlejs.com/badge?q=shamela@1.0.0&badge=detailed)](https://bundlejs.com/?q=shamela%401.0.0) ![typescript](https://badgen.net/badge/icon/typescript?icon=typescript&label&color=blue)
3
+ [![wakatime](https://wakatime.com/badge/user/a0b906ce-b8e7-4463-8bce-383238df6d4b/project/faef70ab-efdb-448b-ab83-0fc66c95888e.svg)](https://wakatime.com/badge/user/a0b906ce-b8e7-4463-8bce-383238df6d4b/project/faef70ab-efdb-448b-ab83-0fc66c95888e) [![E2E](https://github.com/ragaeeb/shamela/actions/workflows/e2e.yml/badge.svg)](https://github.com/ragaeeb/shamela/actions/workflows/e2e.yml) [![Node.js CI](https://github.com/ragaeeb/shamela/actions/workflows/build.yml/badge.svg)](https://github.com/ragaeeb/shamela/actions/workflows/build.yml) ![GitHub License](https://img.shields.io/github/license/ragaeeb/shamela) ![GitHub Release](https://img.shields.io/github/v/release/ragaeeb/shamela) [![codecov](https://codecov.io/gh/ragaeeb/shamela/graph/badge.svg?token=PK55V1R324)](https://codecov.io/gh/ragaeeb/shamela) [![Size](https://deno.bundlejs.com/badge?q=shamela@1.0.3)](https://bundlejs.com/?q=shamela%401.0.3) ![typescript](https://badgen.net/badge/icon/typescript?icon=typescript&label&color=blue) ![npm](https://img.shields.io/npm/v/shamela) ![npm](https://img.shields.io/npm/dm/shamela) ![GitHub issues](https://img.shields.io/github/issues/ragaeeb/shamela) ![GitHub stars](https://img.shields.io/github/stars/ragaeeb/shamela?style=social)
4
4
 
5
- A NodeJS library for accessing and downloading Maktabah Shamela v4 APIs. This library provides easy-to-use functions to interact with the Shamela API, download master and book databases, and retrieve book data programmatically.
5
+ A `NodeJS` library for accessing and downloading Maktabah Shamela v4 APIs. This library provides easy-to-use functions to interact with the Shamela API, download master and book databases, and retrieve book data programmatically.
6
6
 
7
7
  ## Table of Contents
8
8
 
package/dist/index.d.ts CHANGED
@@ -1,52 +1,102 @@
1
- type GetMasterMetadataResponsePayload = {
1
+ export type GetMasterMetadataResponsePayload = {
2
2
  url: string;
3
3
  version: number;
4
4
  };
5
- interface OutputOptions {
5
+ export interface OutputOptions {
6
6
  path: string;
7
7
  }
8
- type DownloadMasterOptions = {
8
+ export type DownloadMasterOptions = {
9
9
  masterMetadata?: GetMasterMetadataResponsePayload;
10
10
  outputFile: OutputOptions;
11
11
  };
12
- type GetBookMetadataOptions = {
12
+ export type GetBookMetadataOptions = {
13
13
  majorVersion: number;
14
14
  minorVersion: number;
15
15
  };
16
- type GetBookMetadataResponsePayload = {
16
+ export type GetBookMetadataResponsePayload = {
17
17
  majorRelease: number;
18
18
  majorReleaseUrl: string;
19
19
  minorRelease?: number;
20
20
  minorReleaseUrl?: string;
21
21
  };
22
- interface OutputBookOptions extends OutputOptions {
23
- removeHeaderTags?: boolean;
24
- }
25
- type DownloadBookOptions = {
22
+ export type DownloadBookOptions = {
26
23
  bookMetadata?: GetBookMetadataResponsePayload;
27
- outputFile: OutputBookOptions;
24
+ outputFile: OutputOptions;
25
+ };
26
+ export type Author = {
27
+ biography?: string;
28
+ death?: number;
29
+ id: number;
30
+ name: string;
31
+ };
32
+ type PDFFile = {
33
+ file: string;
34
+ id?: string;
35
+ };
36
+ export type PDFLinks = {
37
+ alias?: number;
38
+ cover?: number;
39
+ cover_alias?: number;
40
+ files?: PDFFile[];
41
+ root?: string;
42
+ size?: number;
43
+ };
44
+ export type Metadata = {
45
+ coauthor?: number[];
46
+ date: string;
47
+ group?: number;
48
+ hide_diacritic?: boolean;
49
+ min_ver?: number;
50
+ prefix?: string;
51
+ shorts: Record<string, string>;
52
+ sub_books: number[];
53
+ suffix?: string;
54
+ };
55
+ export type Book = {
56
+ author: number | number[];
57
+ bibliography: string;
58
+ category: number;
59
+ date?: number;
60
+ hint?: string;
61
+ id: number;
62
+ major: number;
63
+ metadata: Metadata;
64
+ minor?: number;
65
+ name: string;
66
+ pdfLinks?: PDFLinks;
67
+ printed: number;
68
+ type: number;
69
+ };
70
+ export type Category = {
71
+ id: number;
72
+ name: string;
73
+ };
74
+ export type MasterData = {
75
+ authors: Author[];
76
+ books: Book[];
77
+ categories: Category[];
28
78
  };
29
- type Page = {
79
+ export type Page = {
30
80
  content: string;
31
81
  id: number;
32
82
  number?: number;
33
83
  page?: number;
34
84
  part?: number;
35
85
  };
36
- type Title = {
86
+ export type Title = {
37
87
  content: string;
38
88
  id: number;
39
89
  page: number;
40
90
  parent?: number;
41
91
  };
42
- type BookData = {
92
+ export type BookData = {
43
93
  pages: Page[];
44
94
  titles?: Title[];
45
95
  };
46
- export const getMasterMetadata: (version?: number) => Promise<GetMasterMetadataResponsePayload>;
47
- export const downloadMasterDatabase: (options: DownloadMasterOptions) => Promise<string>;
48
96
  export const getBookMetadata: (id: number, options?: GetBookMetadataOptions) => Promise<GetBookMetadataResponsePayload>;
49
97
  export const downloadBook: (id: number, options: DownloadBookOptions) => Promise<string>;
98
+ export const getMasterMetadata: (version?: number) => Promise<GetMasterMetadataResponsePayload>;
99
+ export const downloadMasterDatabase: (options: DownloadMasterOptions) => Promise<string>;
50
100
  export const getBook: (id: number) => Promise<BookData>;
51
101
 
52
102
  //# sourceMappingURL=index.d.ts.map
package/dist/main.js CHANGED
@@ -32,6 +32,10 @@ const $2d2b29d79cbbfeda$var$logger = (0, $5oumB$pino)({
32
32
  var $2d2b29d79cbbfeda$export$2e2bcd8739ae039 = $2d2b29d79cbbfeda$var$logger;
33
33
 
34
34
 
35
+ const $b142353d92e15b6f$export$1d57574773c8bc58 = async (db, dbName)=>{
36
+ const { rows: tables } = await db.execute(`SELECT name FROM ${dbName}.sqlite_master WHERE type='table'`);
37
+ return tables;
38
+ };
35
39
  const $b142353d92e15b6f$export$3274d151f0598f1 = async (client, table)=>{
36
40
  const { rows: rows } = await client.execute(`SELECT * FROM ${table}`);
37
41
  return rows;
@@ -39,17 +43,7 @@ const $b142353d92e15b6f$export$3274d151f0598f1 = async (client, table)=>{
39
43
 
40
44
 
41
45
  const $e6f751831b705ed8$var$MAIN_DB_ALIAS = "main";
42
- const $e6f751831b705ed8$export$33bbb3ec7652e187 = (name, fields)=>`CREATE TABLE IF NOT EXISTS ${name} (${fields.join(", ")})`;
43
46
  const $e6f751831b705ed8$export$ee56083bb7df7ecc = (dbFile, alias)=>`ATTACH DATABASE '${dbFile}' AS ${alias}`;
44
- const $e6f751831b705ed8$export$7fec5208c714b262 = (alias)=>`DETACH DATABASE ${alias}`;
45
- const $e6f751831b705ed8$var$updatePageColumn = (columnName, aslAlias, patchAlias)=>`
46
- (SELECT CASE
47
- WHEN ${patchAlias}.page.${columnName} != '#' THEN ${patchAlias}.page.${columnName}
48
- ELSE ${aslAlias}.page.${columnName}
49
- END
50
- FROM ${patchAlias}.page
51
- WHERE ${aslAlias}.page.id = ${patchAlias}.page.id)
52
- `;
53
47
  const $e6f751831b705ed8$export$1f75c01d8a920a35 = (patchAlias, tableName, aslAlias = $e6f751831b705ed8$var$MAIN_DB_ALIAS)=>`
54
48
  UPDATE ${aslAlias}.${tableName}
55
49
  SET content = ${$e6f751831b705ed8$var$updatePageColumn("content", aslAlias, patchAlias)},
@@ -81,6 +75,16 @@ const $e6f751831b705ed8$export$a38d1618b943c74f = (patchAlias, tableName, aslAli
81
75
  WHERE ${aslAlias}.${tableName}.id = ${patchAlias}.${tableName}.id
82
76
  );
83
77
  `;
78
+ const $e6f751831b705ed8$export$33bbb3ec7652e187 = (name, fields)=>`CREATE TABLE IF NOT EXISTS ${name} (${fields.join(", ")})`;
79
+ const $e6f751831b705ed8$export$7fec5208c714b262 = (alias)=>`DETACH DATABASE ${alias}`;
80
+ const $e6f751831b705ed8$var$updatePageColumn = (columnName, aslAlias, patchAlias)=>`
81
+ (SELECT CASE
82
+ WHEN ${patchAlias}.page.${columnName} != '#' THEN ${patchAlias}.page.${columnName}
83
+ ELSE ${aslAlias}.page.${columnName}
84
+ END
85
+ FROM ${patchAlias}.page
86
+ WHERE ${aslAlias}.page.id = ${patchAlias}.page.id)
87
+ `;
84
88
  const $e6f751831b705ed8$export$3ef07b9580a45514 = (table, fieldToValue, isDeleted = false)=>{
85
89
  const combinedRecords = {
86
90
  ...fieldToValue,
@@ -107,6 +111,51 @@ var $167eb860ccdaab7d$export$a17a6870a08b950e;
107
111
 
108
112
  const $2a3b237385dd2cff$var$PATCH_DB_ALIAS = "patch";
109
113
  const $2a3b237385dd2cff$var$ASL_DB_ALIAS = "asl";
114
+ const $2a3b237385dd2cff$var$getPagesToCopy = (tables)=>{
115
+ const statements = [];
116
+ if (tables.find((t)=>t.name === (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page)) {
117
+ statements.push(`INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} SELECT id,content,part,page,number FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} WHERE id IN (SELECT id FROM ${$2a3b237385dd2cff$var$PATCH_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} WHERE is_deleted='0')`);
118
+ statements.push((0, $e6f751831b705ed8$export$1f75c01d8a920a35)($2a3b237385dd2cff$var$PATCH_DB_ALIAS, (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page));
119
+ } else statements.push(`INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} SELECT id,content,part,page,number FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} WHERE is_deleted='0'`);
120
+ return statements;
121
+ };
122
+ const $2a3b237385dd2cff$var$getTitlesToCopy = (tables)=>{
123
+ const statements = [];
124
+ if (tables.find((t)=>t.name === (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title)) {
125
+ statements.push(`INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title} SELECT id,content,page,parent FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title} WHERE id IN (SELECT id FROM ${$2a3b237385dd2cff$var$PATCH_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title} WHERE is_deleted='0')`);
126
+ statements.push((0, $e6f751831b705ed8$export$a38d1618b943c74f)($2a3b237385dd2cff$var$PATCH_DB_ALIAS, (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title));
127
+ } else statements.push(`INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title} SELECT id,content,page,parent FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title} WHERE is_deleted='0'`);
128
+ return statements;
129
+ };
130
+ const $2a3b237385dd2cff$export$a8b8e03e6bbe5473 = async (db, aslDB, patchDB)=>{
131
+ const statements = [
132
+ (0, $e6f751831b705ed8$export$ee56083bb7df7ecc)(aslDB, $2a3b237385dd2cff$var$ASL_DB_ALIAS)
133
+ ];
134
+ if (patchDB) await db.execute((0, $e6f751831b705ed8$export$ee56083bb7df7ecc)(patchDB, $2a3b237385dd2cff$var$PATCH_DB_ALIAS));
135
+ const tables = patchDB ? await (0, $b142353d92e15b6f$export$1d57574773c8bc58)(db, $2a3b237385dd2cff$var$PATCH_DB_ALIAS) : [];
136
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).debug({
137
+ tables: tables
138
+ }, `Applying patches for...`);
139
+ statements.push(...$2a3b237385dd2cff$var$getPagesToCopy(tables));
140
+ statements.push(...$2a3b237385dd2cff$var$getTitlesToCopy(tables));
141
+ await db.batch(statements);
142
+ const detachStatements = [];
143
+ detachStatements.push((0, $e6f751831b705ed8$export$7fec5208c714b262)($2a3b237385dd2cff$var$ASL_DB_ALIAS));
144
+ if (patchDB) detachStatements.push((0, $e6f751831b705ed8$export$7fec5208c714b262)($2a3b237385dd2cff$var$PATCH_DB_ALIAS));
145
+ return db.batch(detachStatements);
146
+ };
147
+ const $2a3b237385dd2cff$export$61101aa23c771e7c = async (db, aslDB)=>{
148
+ await db.execute((0, $e6f751831b705ed8$export$ee56083bb7df7ecc)(aslDB, $2a3b237385dd2cff$var$ASL_DB_ALIAS));
149
+ const tables = await (0, $b142353d92e15b6f$export$1d57574773c8bc58)(db, $2a3b237385dd2cff$var$ASL_DB_ALIAS);
150
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).debug({
151
+ tables: tables
152
+ }, `Applying patches for...`);
153
+ await db.batch([
154
+ `INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title} SELECT id,content,page,parent FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title}`,
155
+ `INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} SELECT id,content,part,page,number FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page}`
156
+ ]);
157
+ return db.execute((0, $e6f751831b705ed8$export$7fec5208c714b262)($2a3b237385dd2cff$var$ASL_DB_ALIAS));
158
+ };
110
159
  const $2a3b237385dd2cff$export$5d28a6b0dd65e4c4 = async (db)=>{
111
160
  return db.batch([
112
161
  `CREATE TABLE page (id INTEGER PRIMARY KEY, content TEXT, part INTEGER, page INTEGER, number INTEGER)`,
@@ -158,41 +207,6 @@ const $2a3b237385dd2cff$export$7a171f172be0782e = async (db)=>{
158
207
  titles: titles
159
208
  };
160
209
  };
161
- const $2a3b237385dd2cff$var$getPagesToCopy = (tables)=>{
162
- const statements = [];
163
- if (tables.find((t)=>t.name === (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page)) {
164
- statements.push(`INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} SELECT id,content,part,page,number FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} WHERE id IN (SELECT id FROM ${$2a3b237385dd2cff$var$PATCH_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} WHERE is_deleted='0')`);
165
- statements.push((0, $e6f751831b705ed8$export$1f75c01d8a920a35)($2a3b237385dd2cff$var$PATCH_DB_ALIAS, (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page));
166
- } else statements.push(`INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} SELECT id,content,part,page,number FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Page} WHERE is_deleted='0'`);
167
- return statements;
168
- };
169
- const $2a3b237385dd2cff$var$getTitlesToCopy = (tables)=>{
170
- const statements = [];
171
- if (tables.find((t)=>t.name === (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title)) {
172
- statements.push(`INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title} SELECT id,content,page,parent FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title} WHERE id IN (SELECT id FROM ${$2a3b237385dd2cff$var$PATCH_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title} WHERE is_deleted='0')`);
173
- statements.push((0, $e6f751831b705ed8$export$a38d1618b943c74f)($2a3b237385dd2cff$var$PATCH_DB_ALIAS, (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title));
174
- } else statements.push(`INSERT INTO main.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title} SELECT id,content,page,parent FROM ${$2a3b237385dd2cff$var$ASL_DB_ALIAS}.${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Title} WHERE is_deleted='0'`);
175
- return statements;
176
- };
177
- const $2a3b237385dd2cff$export$a8b8e03e6bbe5473 = async (db, aslDB, patchDB)=>{
178
- const statements = [
179
- (0, $e6f751831b705ed8$export$ee56083bb7df7ecc)(aslDB, $2a3b237385dd2cff$var$ASL_DB_ALIAS)
180
- ];
181
- if (patchDB) await db.execute((0, $e6f751831b705ed8$export$ee56083bb7df7ecc)(patchDB, $2a3b237385dd2cff$var$PATCH_DB_ALIAS));
182
- const { rows: tables } = patchDB ? await db.execute(`SELECT name FROM ${$2a3b237385dd2cff$var$PATCH_DB_ALIAS}.sqlite_master WHERE type='table'`) : {
183
- rows: []
184
- };
185
- (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).debug({
186
- tables: tables
187
- }, `Applying patches for...`);
188
- statements.push(...$2a3b237385dd2cff$var$getPagesToCopy(tables));
189
- statements.push(...$2a3b237385dd2cff$var$getTitlesToCopy(tables));
190
- await db.batch(statements);
191
- const detachStatements = [];
192
- detachStatements.push((0, $e6f751831b705ed8$export$7fec5208c714b262)($2a3b237385dd2cff$var$ASL_DB_ALIAS));
193
- if (patchDB) detachStatements.push((0, $e6f751831b705ed8$export$7fec5208c714b262)($2a3b237385dd2cff$var$PATCH_DB_ALIAS));
194
- return db.batch(detachStatements);
195
- };
196
210
 
197
211
 
198
212
 
@@ -203,6 +217,25 @@ const $14c03a3c41757845$export$3deaf0b0365f781e = "99999";
203
217
 
204
218
 
205
219
 
220
+ const $e19722dabbedc0a6$export$b3179f41dfd6e35b = async (db, sourceTables)=>{
221
+ const aliasToPath = sourceTables.reduce((acc, tablePath)=>{
222
+ const { name: name } = (0, $5oumB$path).parse(tablePath);
223
+ return {
224
+ ...acc,
225
+ [name]: tablePath
226
+ };
227
+ }, {});
228
+ const attachStatements = Object.entries(aliasToPath).map(([alias, dbPath])=>(0, $e6f751831b705ed8$export$ee56083bb7df7ecc)(dbPath, alias));
229
+ await db.batch(attachStatements);
230
+ const insertStatements = [
231
+ `INSERT INTO ${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Authors} SELECT id,name,biography,(CASE WHEN death_number = ${(0, $14c03a3c41757845$export$3deaf0b0365f781e)} THEN NULL ELSE death_number END) AS death_number FROM author WHERE is_deleted='0'`,
232
+ `INSERT INTO ${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Books} SELECT id,name,category,type,(CASE WHEN date = ${(0, $14c03a3c41757845$export$3deaf0b0365f781e)} THEN NULL ELSE date END) AS date,author,printed,major_release,minor_release,bibliography,hint,pdf_links,metadata FROM book WHERE is_deleted='0'`,
233
+ `INSERT INTO ${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Categories} SELECT id,name FROM category WHERE is_deleted='0'`
234
+ ];
235
+ await db.batch(insertStatements);
236
+ const detachStatements = Object.keys(aliasToPath).map((0, $e6f751831b705ed8$export$7fec5208c714b262));
237
+ await db.batch(detachStatements);
238
+ };
206
239
  const $e19722dabbedc0a6$export$5d28a6b0dd65e4c4 = async (db)=>{
207
240
  return db.batch([
208
241
  `CREATE TABLE authors (id INTEGER PRIMARY KEY, name TEXT, biography TEXT, death INTEGER)`,
@@ -224,31 +257,6 @@ const $e19722dabbedc0a6$export$b3b931905baa18df = async (db)=>{
224
257
  }));
225
258
  return authors;
226
259
  };
227
- const $e19722dabbedc0a6$export$36bfd9279b3a24b7 = async (db)=>{
228
- const rows = await (0, $b142353d92e15b6f$export$3274d151f0598f1)(db, (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Categories);
229
- const categories = rows.map((r)=>({
230
- id: r.id,
231
- name: r.name
232
- }));
233
- return categories;
234
- };
235
- const $e19722dabbedc0a6$var$parseAuthor = (value)=>{
236
- const result = value.split(",\\s+").map((id)=>parseInt(id.trim()));
237
- return result.length > 1 ? result : result[0];
238
- };
239
- const $e19722dabbedc0a6$var$parsePdfLinks = (value)=>{
240
- const result = JSON.parse(value);
241
- if (result.files) result.files = result.files.map((f)=>{
242
- const [file, id] = f.split("|");
243
- return {
244
- ...id && {
245
- id: id
246
- },
247
- file: file
248
- };
249
- });
250
- return result;
251
- };
252
260
  const $e19722dabbedc0a6$export$7111c27bf38a004f = async (db)=>{
253
261
  const rows = await (0, $b142353d92e15b6f$export$3274d151f0598f1)(db, (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Books);
254
262
  const books = rows.map((row)=>{
@@ -279,6 +287,31 @@ const $e19722dabbedc0a6$export$7111c27bf38a004f = async (db)=>{
279
287
  });
280
288
  return books;
281
289
  };
290
+ const $e19722dabbedc0a6$export$36bfd9279b3a24b7 = async (db)=>{
291
+ const rows = await (0, $b142353d92e15b6f$export$3274d151f0598f1)(db, (0, $167eb860ccdaab7d$export$a17a6870a08b950e).Categories);
292
+ const categories = rows.map((r)=>({
293
+ id: r.id,
294
+ name: r.name
295
+ }));
296
+ return categories;
297
+ };
298
+ const $e19722dabbedc0a6$var$parseAuthor = (value)=>{
299
+ const result = value.split(",\\s+").map((id)=>parseInt(id.trim()));
300
+ return result.length > 1 ? result : result[0];
301
+ };
302
+ const $e19722dabbedc0a6$var$parsePdfLinks = (value)=>{
303
+ const result = JSON.parse(value);
304
+ if (result.files) result.files = result.files.map((f)=>{
305
+ const [file, id] = f.split("|");
306
+ return {
307
+ ...id && {
308
+ id: id
309
+ },
310
+ file: file
311
+ };
312
+ });
313
+ return result;
314
+ };
282
315
  const $e19722dabbedc0a6$export$7a171f172be0782e = async (db)=>{
283
316
  const [authors, books, categories] = await Promise.all([
284
317
  $e19722dabbedc0a6$export$b3b931905baa18df(db),
@@ -291,25 +324,6 @@ const $e19722dabbedc0a6$export$7a171f172be0782e = async (db)=>{
291
324
  categories: categories
292
325
  };
293
326
  };
294
- const $e19722dabbedc0a6$export$b3179f41dfd6e35b = async (db, sourceTables)=>{
295
- const aliasToPath = sourceTables.reduce((acc, tablePath)=>{
296
- const { name: name } = (0, $5oumB$path).parse(tablePath);
297
- return {
298
- ...acc,
299
- [name]: tablePath
300
- };
301
- }, {});
302
- const attachStatements = Object.entries(aliasToPath).map(([alias, dbPath])=>(0, $e6f751831b705ed8$export$ee56083bb7df7ecc)(dbPath, alias));
303
- await db.batch(attachStatements);
304
- const insertStatements = [
305
- `INSERT INTO ${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Authors} SELECT id,name,biography,(CASE WHEN death_number = ${(0, $14c03a3c41757845$export$3deaf0b0365f781e)} THEN NULL ELSE death_number END) AS death_number FROM author WHERE is_deleted='0'`,
306
- `INSERT INTO ${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Books} SELECT id,name,category,type,(CASE WHEN date = ${(0, $14c03a3c41757845$export$3deaf0b0365f781e)} THEN NULL ELSE date END) AS date,author,printed,major_release,minor_release,bibliography,hint,pdf_links,metadata FROM book WHERE is_deleted='0'`,
307
- `INSERT INTO ${(0, $167eb860ccdaab7d$export$a17a6870a08b950e).Categories} SELECT id,name FROM category WHERE is_deleted='0'`
308
- ];
309
- await db.batch(insertStatements);
310
- const detachStatements = Object.keys(aliasToPath).map((0, $e6f751831b705ed8$export$7fec5208c714b262));
311
- await db.batch(detachStatements);
312
- };
313
327
 
314
328
 
315
329
 
@@ -430,59 +444,70 @@ const $da18f5255cf003e1$var$SOURCE_TABLES = [
430
444
  "book.sqlite",
431
445
  "category.sqlite"
432
446
  ];
433
- const $da18f5255cf003e1$export$c7660b0cda39b7c3 = (sourceTablePaths)=>{
434
- const sourceTableNames = sourceTablePaths.map((tablePath)=>(0, $5oumB$path).parse(tablePath).base);
435
- return $da18f5255cf003e1$var$SOURCE_TABLES.every((table)=>sourceTableNames.includes(table));
436
- };
437
447
  const $da18f5255cf003e1$export$37467b7f8cfc50b0 = ()=>{
438
448
  if (!(0, $5oumB$process).env.SHAMELA_API_MASTER_PATCH_ENDPOINT) throw new Error("SHAMELA_API_MASTER_PATCH_ENDPOINT environment variable not set");
439
449
  if (!(0, $5oumB$process).env.SHAMELA_API_KEY) throw new Error("SHAMELA_API_KEY environment variable not set");
440
450
  };
451
+ const $da18f5255cf003e1$export$c7660b0cda39b7c3 = (sourceTablePaths)=>{
452
+ const sourceTableNames = sourceTablePaths.map((tablePath)=>(0, $5oumB$path).parse(tablePath).base);
453
+ return $da18f5255cf003e1$var$SOURCE_TABLES.every((table)=>sourceTableNames.includes(table));
454
+ };
441
455
 
442
456
 
443
- const $96cb7a03b537cb37$export$b96de494209cdc35 = async (version = 0)=>{
457
+ const $96cb7a03b537cb37$export$4c209aa17b4b3e57 = async (id, options)=>{
444
458
  (0, $da18f5255cf003e1$export$37467b7f8cfc50b0)();
445
- const url = new (0, $5oumB$URL)((0, $5oumB$process).env.SHAMELA_API_MASTER_PATCH_ENDPOINT);
459
+ const url = new (0, $5oumB$URL)(`${(0, $5oumB$process).env.SHAMELA_API_BOOKS_ENDPOINT}/${id}`);
446
460
  {
447
461
  const params = new (0, $5oumB$URLSearchParams)();
448
462
  params.append("api_key", (0, $5oumB$process).env.SHAMELA_API_KEY);
449
- params.append("version", version.toString());
463
+ params.append("major_release", (options?.majorVersion || 0).toString());
464
+ params.append("minor_release", (options?.minorVersion || 0).toString());
450
465
  url.search = params.toString();
451
466
  }
452
- (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Fetching shamela.ws master database patch link: ${url.toString()}`);
467
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Fetching shamela.ws book link: ${url.toString()}`);
453
468
  try {
454
469
  const response = await (0, $932b4b3755196b46$export$c9e6217566c54f42)(url);
455
470
  return {
456
- url: response.patch_url,
457
- version: response.version
471
+ majorRelease: response.major_release,
472
+ majorReleaseUrl: response.major_release_url,
473
+ ...response.minor_release_url && {
474
+ minorReleaseUrl: response.minor_release_url
475
+ },
476
+ ...response.minor_release_url && {
477
+ minorRelease: response.minor_release
478
+ }
458
479
  };
459
480
  } catch (error) {
460
481
  throw new Error(`Error fetching master patch: ${error.message}`);
461
482
  }
462
483
  };
463
- const $96cb7a03b537cb37$export$fd8b6353fde3f1de = async (options)=>{
464
- (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`downloadMasterDatabase ${JSON.stringify(options)}`);
465
- const outputDir = await (0, $e8ee15c0ce3f020d$export$1c500f521ad591da)("shamela_downloadMaster");
466
- const masterResponse = options.masterMetadata || await $96cb7a03b537cb37$export$b96de494209cdc35((0, $14c03a3c41757845$export$5bc725975f47e62c));
467
- (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Downloading master database from: ${JSON.stringify(masterResponse)}`);
468
- const sourceTables = await (0, $e8ee15c0ce3f020d$export$fb61e277af91ac0)(masterResponse.url, outputDir);
469
- (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`sourceTables downloaded: ${sourceTables.toString()}`);
470
- if (!(0, $da18f5255cf003e1$export$c7660b0cda39b7c3)(sourceTables)) {
471
- (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).error(`Some source tables were not found: ${sourceTables.toString()}`);
472
- throw new Error("Expected tables not found!");
473
- }
474
- const dbPath = (0, $5oumB$path).join(outputDir, "master.db");
484
+ const $96cb7a03b537cb37$export$3560c45fd9de930d = async (id, options)=>{
485
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`downloadBook ${id} ${JSON.stringify(options)}`);
486
+ const outputDir = await (0, $e8ee15c0ce3f020d$export$1c500f521ad591da)("shamela_downloadBook");
487
+ const bookResponse = options?.bookMetadata || await $96cb7a03b537cb37$export$4c209aa17b4b3e57(id);
488
+ const [[bookDatabase], [patchDatabase] = []] = await Promise.all([
489
+ (0, $e8ee15c0ce3f020d$export$fb61e277af91ac0)(bookResponse.majorReleaseUrl, outputDir),
490
+ ...bookResponse.minorReleaseUrl ? [
491
+ (0, $e8ee15c0ce3f020d$export$fb61e277af91ac0)(bookResponse.minorReleaseUrl, outputDir)
492
+ ] : []
493
+ ]);
494
+ const dbPath = (0, $5oumB$path).join(outputDir, "book.db");
475
495
  const client = (0, $5oumB$createClient)({
476
496
  url: `file:${dbPath}`
477
497
  });
478
498
  try {
479
499
  (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Creating tables`);
480
- await (0, $e19722dabbedc0a6$export$5d28a6b0dd65e4c4)(client);
481
- (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Copying data to master table`);
482
- await (0, $e19722dabbedc0a6$export$b3179f41dfd6e35b)(client, sourceTables);
500
+ await (0, $2a3b237385dd2cff$export$5d28a6b0dd65e4c4)(client);
501
+ if (patchDatabase) {
502
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Applying patches from ${patchDatabase} to ${bookDatabase}`);
503
+ await (0, $2a3b237385dd2cff$export$a8b8e03e6bbe5473)(client, bookDatabase, patchDatabase);
504
+ } else {
505
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Copying table data from ${bookDatabase}`);
506
+ await (0, $2a3b237385dd2cff$export$61101aa23c771e7c)(client, bookDatabase);
507
+ }
483
508
  const { ext: extension } = (0, $5oumB$path).parse(options.outputFile.path);
484
509
  if (extension === ".json") {
485
- const result = await (0, $e19722dabbedc0a6$export$7a171f172be0782e)(client);
510
+ const result = await (0, $2a3b237385dd2cff$export$7a171f172be0782e)(client);
486
511
  await (0, $5oumB$promises).writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), "utf8");
487
512
  }
488
513
  client.close();
@@ -495,55 +520,49 @@ const $96cb7a03b537cb37$export$fd8b6353fde3f1de = async (options)=>{
495
520
  }
496
521
  return options.outputFile.path;
497
522
  };
498
- const $96cb7a03b537cb37$export$4c209aa17b4b3e57 = async (id, options)=>{
523
+ const $96cb7a03b537cb37$export$b96de494209cdc35 = async (version = 0)=>{
499
524
  (0, $da18f5255cf003e1$export$37467b7f8cfc50b0)();
500
- const url = new (0, $5oumB$URL)(`${(0, $5oumB$process).env.SHAMELA_API_BOOKS_ENDPOINT}/${id}`);
525
+ const url = new (0, $5oumB$URL)((0, $5oumB$process).env.SHAMELA_API_MASTER_PATCH_ENDPOINT);
501
526
  {
502
527
  const params = new (0, $5oumB$URLSearchParams)();
503
528
  params.append("api_key", (0, $5oumB$process).env.SHAMELA_API_KEY);
504
- params.append("major_release", (options?.majorVersion || 0).toString());
505
- params.append("minor_release", (options?.minorVersion || 0).toString());
529
+ params.append("version", version.toString());
506
530
  url.search = params.toString();
507
531
  }
508
- (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Fetching shamela.ws book link: ${url.toString()}`);
532
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Fetching shamela.ws master database patch link: ${url.toString()}`);
509
533
  try {
510
534
  const response = await (0, $932b4b3755196b46$export$c9e6217566c54f42)(url);
511
535
  return {
512
- majorRelease: response.major_release,
513
- majorReleaseUrl: response.major_release_url,
514
- ...response.minor_release_url && {
515
- minorReleaseUrl: response.minor_release_url
516
- },
517
- ...response.minor_release_url && {
518
- minorRelease: response.minor_release
519
- }
536
+ url: response.patch_url,
537
+ version: response.version
520
538
  };
521
539
  } catch (error) {
522
540
  throw new Error(`Error fetching master patch: ${error.message}`);
523
541
  }
524
542
  };
525
- const $96cb7a03b537cb37$export$3560c45fd9de930d = async (id, options)=>{
526
- (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`downloadBook ${id} ${JSON.stringify(options)}`);
527
- const outputDir = await (0, $e8ee15c0ce3f020d$export$1c500f521ad591da)("shamela_downloadBook");
528
- const bookResponse = options?.bookMetadata || await $96cb7a03b537cb37$export$4c209aa17b4b3e57(id);
529
- const [[bookDatabase], [patchDatabase]] = await Promise.all([
530
- (0, $e8ee15c0ce3f020d$export$fb61e277af91ac0)(bookResponse.majorReleaseUrl, outputDir),
531
- ...bookResponse.minorReleaseUrl ? [
532
- (0, $e8ee15c0ce3f020d$export$fb61e277af91ac0)(bookResponse.minorReleaseUrl, outputDir)
533
- ] : []
534
- ]);
535
- const dbPath = (0, $5oumB$path).join(outputDir, "book.db");
543
+ const $96cb7a03b537cb37$export$fd8b6353fde3f1de = async (options)=>{
544
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`downloadMasterDatabase ${JSON.stringify(options)}`);
545
+ const outputDir = await (0, $e8ee15c0ce3f020d$export$1c500f521ad591da)("shamela_downloadMaster");
546
+ const masterResponse = options.masterMetadata || await $96cb7a03b537cb37$export$b96de494209cdc35((0, $14c03a3c41757845$export$5bc725975f47e62c));
547
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Downloading master database from: ${JSON.stringify(masterResponse)}`);
548
+ const sourceTables = await (0, $e8ee15c0ce3f020d$export$fb61e277af91ac0)(masterResponse.url, outputDir);
549
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`sourceTables downloaded: ${sourceTables.toString()}`);
550
+ if (!(0, $da18f5255cf003e1$export$c7660b0cda39b7c3)(sourceTables)) {
551
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).error(`Some source tables were not found: ${sourceTables.toString()}`);
552
+ throw new Error("Expected tables not found!");
553
+ }
554
+ const dbPath = (0, $5oumB$path).join(outputDir, "master.db");
536
555
  const client = (0, $5oumB$createClient)({
537
556
  url: `file:${dbPath}`
538
557
  });
539
558
  try {
540
559
  (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Creating tables`);
541
- await (0, $2a3b237385dd2cff$export$5d28a6b0dd65e4c4)(client);
542
- (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Applying patches from ${patchDatabase} to ${bookDatabase}`);
543
- await (0, $2a3b237385dd2cff$export$a8b8e03e6bbe5473)(client, bookDatabase, patchDatabase);
560
+ await (0, $e19722dabbedc0a6$export$5d28a6b0dd65e4c4)(client);
561
+ (0, $2d2b29d79cbbfeda$export$2e2bcd8739ae039).info(`Copying data to master table`);
562
+ await (0, $e19722dabbedc0a6$export$b3179f41dfd6e35b)(client, sourceTables);
544
563
  const { ext: extension } = (0, $5oumB$path).parse(options.outputFile.path);
545
564
  if (extension === ".json") {
546
- const result = await (0, $2a3b237385dd2cff$export$7a171f172be0782e)(client);
565
+ const result = await (0, $e19722dabbedc0a6$export$7a171f172be0782e)(client);
547
566
  await (0, $5oumB$promises).writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), "utf8");
548
567
  }
549
568
  client.close();
@@ -571,6 +590,9 @@ const $96cb7a03b537cb37$export$be7c2acc48adceee = async (id)=>{
571
590
  };
572
591
 
573
592
 
593
+ var $b369a26e4279c768$exports = {};
594
+
595
+
574
596
 
575
597
 
576
598
  export {$96cb7a03b537cb37$export$3560c45fd9de930d as downloadBook, $96cb7a03b537cb37$export$fd8b6353fde3f1de as downloadMasterDatabase, $96cb7a03b537cb37$export$be7c2acc48adceee as getBook, $96cb7a03b537cb37$export$4c209aa17b4b3e57 as getBookMetadata, $96cb7a03b537cb37$export$b96de494209cdc35 as getMasterMetadata};
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"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","sources":["src/index.ts","src/api.ts","src/db/book.ts","src/utils/logger.ts","src/db/common.ts","src/db/queryBuilder.ts","src/db/types.ts","src/db/master.ts","src/utils/constants.ts","src/utils/io.ts","src/utils/network.ts","src/utils/validation.ts"],"sourcesContent":["import { downloadBook, downloadMasterDatabase, getBook, getBookMetadata, getMasterMetadata } from './api';\n\nexport { downloadBook, downloadMasterDatabase, getBook, getBookMetadata, getMasterMetadata };\n","import { Client, createClient } from '@libsql/client';\nimport { promises as fs } from 'fs';\nimport path from 'path';\nimport process from 'process';\nimport { URL, URLSearchParams } from 'url';\n\nimport { applyPatches, createTables as createBookTables, getData as getBookData } from './db/book.js';\nimport {\n copyForeignMasterTableData,\n createTables as createMasterTables,\n getData as getMasterData,\n} from './db/master.js';\nimport {\n BookData,\n DownloadBookOptions,\n DownloadMasterOptions,\n GetBookMetadataOptions,\n GetBookMetadataResponsePayload,\n GetMasterMetadataResponsePayload,\n} from './types.js';\nimport { DEFAULT_MASTER_METADATA_VERSION } from './utils/constants.js';\nimport { createTempDir, unzipFromUrl } from './utils/io.js';\nimport logger from './utils/logger.js';\nimport { httpsGet } from './utils/network.js';\nimport { validateEnvVariables, validateMasterSourceTables } from './utils/validation.js';\n\nexport const getMasterMetadata = async (version: number = 0): Promise<GetMasterMetadataResponsePayload> => {\n validateEnvVariables();\n\n const url = new URL(process.env.SHAMELA_API_MASTER_PATCH_ENDPOINT as string);\n {\n const params = new URLSearchParams();\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n params.append('version', version.toString());\n url.search = params.toString();\n }\n\n logger.info(`Fetching shamela.ws master database patch link: ${url.toString()}`);\n\n try {\n const response: Record<string, any> = await httpsGet(url);\n return { url: response.patch_url, version: response.version };\n } catch (error: any) {\n throw new Error(`Error fetching master patch: ${error.message}`);\n }\n};\n\nexport const downloadMasterDatabase = async (options: DownloadMasterOptions): Promise<string> => {\n logger.info(`downloadMasterDatabase ${JSON.stringify(options)}`);\n\n const outputDir = await createTempDir('shamela_downloadMaster');\n\n const masterResponse: GetMasterMetadataResponsePayload =\n options.masterMetadata || (await getMasterMetadata(DEFAULT_MASTER_METADATA_VERSION));\n\n logger.info(`Downloading master database from: ${JSON.stringify(masterResponse)}`);\n const sourceTables: string[] = await unzipFromUrl(masterResponse.url, outputDir);\n\n logger.info(`sourceTables downloaded: ${sourceTables.toString()}`);\n\n if (!validateMasterSourceTables(sourceTables)) {\n logger.error(`Some source tables were not found: ${sourceTables.toString()}`);\n throw new Error('Expected tables not found!');\n }\n\n const dbPath = path.join(outputDir, 'master.db');\n\n const client: Client = createClient({\n url: `file:${dbPath}`,\n });\n\n try {\n logger.info(`Creating tables`);\n await createMasterTables(client);\n\n logger.info(`Copying data to master table`);\n await copyForeignMasterTableData(client, sourceTables);\n\n const { ext: extension } = path.parse(options.outputFile.path);\n\n if (extension === '.json') {\n const result = await getMasterData(client);\n await fs.writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), 'utf8');\n }\n\n client.close();\n\n if (extension === '.db' || extension === '.sqlite') {\n await fs.rename(dbPath, options.outputFile.path);\n }\n\n await fs.rm(outputDir, { recursive: true });\n } finally {\n client.close();\n }\n\n return options.outputFile.path;\n};\n\nexport const getBookMetadata = async (\n id: number,\n options?: GetBookMetadataOptions,\n): Promise<GetBookMetadataResponsePayload> => {\n validateEnvVariables();\n\n const url = new URL(`${process.env.SHAMELA_API_BOOKS_ENDPOINT}/${id}`);\n {\n const params = new URLSearchParams();\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n params.append('major_release', (options?.majorVersion || 0).toString());\n params.append('minor_release', (options?.minorVersion || 0).toString());\n url.search = params.toString();\n }\n\n logger.info(`Fetching shamela.ws book link: ${url.toString()}`);\n\n try {\n const response: Record<string, any> = await httpsGet(url);\n return {\n majorRelease: response.major_release,\n majorReleaseUrl: response.major_release_url,\n ...(response.minor_release_url && { minorReleaseUrl: response.minor_release_url }),\n ...(response.minor_release_url && { minorRelease: response.minor_release }),\n };\n } catch (error: any) {\n throw new Error(`Error fetching master patch: ${error.message}`);\n }\n};\n\nexport const downloadBook = async (id: number, options: DownloadBookOptions): Promise<string> => {\n logger.info(`downloadBook ${id} ${JSON.stringify(options)}`);\n\n const outputDir = await createTempDir('shamela_downloadBook');\n\n const bookResponse: GetBookMetadataResponsePayload = options?.bookMetadata || (await getBookMetadata(id));\n const [[bookDatabase], [patchDatabase]]: string[][] = await Promise.all([\n unzipFromUrl(bookResponse.majorReleaseUrl, outputDir),\n ...(bookResponse.minorReleaseUrl ? [unzipFromUrl(bookResponse.minorReleaseUrl, outputDir)] : []),\n ]);\n const dbPath = path.join(outputDir, 'book.db');\n\n const client: Client = createClient({\n url: `file:${dbPath}`,\n });\n\n try {\n logger.info(`Creating tables`);\n await createBookTables(client);\n\n logger.info(`Applying patches from ${patchDatabase} to ${bookDatabase}`);\n await applyPatches(client, bookDatabase, patchDatabase);\n\n const { ext: extension } = path.parse(options.outputFile.path);\n\n if (extension === '.json') {\n const result = await getBookData(client);\n await fs.writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), 'utf8');\n }\n\n client.close();\n\n if (extension === '.db' || extension === '.sqlite') {\n await fs.rename(dbPath, options.outputFile.path);\n }\n\n await fs.rm(outputDir, { recursive: true });\n } finally {\n client.close();\n }\n\n return options.outputFile.path;\n};\n\nexport const getBook = async (id: number): Promise<BookData> => {\n const outputDir = await createTempDir('shamela_getBookData');\n const outputPath = await downloadBook(id, { outputFile: { path: path.join(outputDir, `${id}.json`) } });\n\n const data = JSON.parse(await fs.readFile(outputPath, 'utf8')) as BookData;\n await fs.rm(outputDir, { recursive: true });\n\n return data;\n};\n","import { Client } from '@libsql/client';\n\nimport { BookData, Page, Title } from '../types';\nimport logger from '../utils/logger';\nimport { selectAllRows } from './common';\nimport { attachDB, buildPagePatchQuery, buildTitlePatchQuery, detachDB } from './queryBuilder';\nimport { PageRow, Tables, TitleRow } from './types';\n\nconst PATCH_DB_ALIAS = 'patch';\nconst ASL_DB_ALIAS = 'asl';\n\ntype InternalTable = {\n name: string;\n};\n\nexport const createTables = async (db: Client) => {\n return db.batch([\n `CREATE TABLE page (id INTEGER PRIMARY KEY, content TEXT, part INTEGER, page INTEGER, number INTEGER)`,\n `CREATE TABLE title (id INTEGER PRIMARY KEY, content TEXT, page INTEGER, parent INTEGER)`,\n ]);\n};\n\nexport const getAllPages = async (db: Client): Promise<Page[]> => {\n const rows = await selectAllRows(db, Tables.Page);\n\n const pages: Page[] = rows.map((row: any) => {\n const { content, id, number, page, part } = row as PageRow;\n\n return {\n content,\n id,\n ...(page && { page }),\n ...(number && { number }),\n ...(part && { part }),\n };\n });\n\n return pages;\n};\n\nexport const getAllTitles = async (db: Client): Promise<Title[]> => {\n const rows = await selectAllRows(db, Tables.Title);\n\n const titles: Title[] = rows.map((row: any) => {\n const r = row as TitleRow;\n\n return {\n content: r.content,\n id: r.id,\n page: r.page,\n ...(r.parent && { number: r.parent }),\n };\n });\n\n return titles;\n};\n\nexport const getData = async (db: Client): Promise<BookData> => {\n const [pages, titles] = await Promise.all([getAllPages(db), getAllTitles(db)]);\n return { pages, titles };\n};\n\nconst getPagesToCopy = (tables: InternalTable[]): string[] => {\n const statements = [];\n\n if (tables.find((t) => t.name === Tables.Page)) {\n statements.push(\n `INSERT INTO main.${Tables.Page} SELECT id,content,part,page,number FROM ${ASL_DB_ALIAS}.${Tables.Page} WHERE id IN (SELECT id FROM ${PATCH_DB_ALIAS}.${Tables.Page} WHERE is_deleted='0')`,\n );\n statements.push(buildPagePatchQuery(PATCH_DB_ALIAS, Tables.Page));\n } else {\n statements.push(\n `INSERT INTO main.${Tables.Page} SELECT id,content,part,page,number FROM ${ASL_DB_ALIAS}.${Tables.Page} WHERE is_deleted='0'`,\n );\n }\n\n return statements;\n};\n\nconst getTitlesToCopy = (tables: InternalTable[]): string[] => {\n const statements = [];\n\n if (tables.find((t) => t.name === Tables.Title)) {\n statements.push(\n `INSERT INTO main.${Tables.Title} SELECT id,content,page,parent FROM ${ASL_DB_ALIAS}.${Tables.Title} WHERE id IN (SELECT id FROM ${PATCH_DB_ALIAS}.${Tables.Title} WHERE is_deleted='0')`,\n );\n statements.push(buildTitlePatchQuery(PATCH_DB_ALIAS, Tables.Title));\n } else {\n statements.push(\n `INSERT INTO main.${Tables.Title} SELECT id,content,page,parent FROM ${ASL_DB_ALIAS}.${Tables.Title} WHERE is_deleted='0'`,\n );\n }\n\n return statements;\n};\n\nexport const applyPatches = async (db: Client, aslDB: string, patchDB?: string) => {\n const statements: string[] = [attachDB(aslDB, ASL_DB_ALIAS)];\n\n if (patchDB) {\n await db.execute(attachDB(patchDB, PATCH_DB_ALIAS));\n }\n\n const { rows: tables } = patchDB\n ? await db.execute(`SELECT name FROM ${PATCH_DB_ALIAS}.sqlite_master WHERE type='table'`)\n : { rows: [] };\n\n logger.debug({ tables }, `Applying patches for...`);\n\n statements.push(...getPagesToCopy(tables as InternalTable[]));\n statements.push(...getTitlesToCopy(tables as InternalTable[]));\n\n await db.batch(statements);\n\n const detachStatements = [];\n detachStatements.push(detachDB(ASL_DB_ALIAS));\n\n if (patchDB) {\n detachStatements.push(detachDB(PATCH_DB_ALIAS));\n }\n\n return db.batch(detachStatements);\n};\n","import pino, { Logger } from 'pino';\nimport pretty, { PrettyOptions } from 'pino-pretty';\nimport process from 'process';\n\nconst stream = pretty({\n colorize: true,\n} as PrettyOptions);\n\nconst logger: Logger = pino(\n {\n base: { pid: undefined, hostname: undefined }, // This will remove pid and hostname but keep time\n level: process.env.LOG_LEVEL || 'info',\n },\n stream,\n);\n\nexport default logger;\n","import { Client, Row } from '@libsql/client';\n\nexport const selectAllRows = async (client: Client, table: string): Promise<Row[]> => {\n const { rows } = await client.execute(`SELECT * FROM ${table}`);\n return rows;\n};\n","const MAIN_DB_ALIAS = 'main';\n\nexport const createTable = (name: string, fields: string[]): string =>\n `CREATE TABLE IF NOT EXISTS ${name} (${fields.join(', ')})`;\n\nexport const attachDB = (dbFile: string, alias: string) => `ATTACH DATABASE '${dbFile}' AS ${alias}`;\n\nexport const detachDB = (alias: string) => `DETACH DATABASE ${alias}`;\n\nconst updatePageColumn = (columnName: string, aslAlias: string, patchAlias: string): string => `\n (SELECT CASE \n WHEN ${patchAlias}.page.${columnName} != '#' THEN ${patchAlias}.page.${columnName}\n ELSE ${aslAlias}.page.${columnName}\n END \n FROM ${patchAlias}.page\n WHERE ${aslAlias}.page.id = ${patchAlias}.page.id)\n`;\n\nexport const buildPagePatchQuery = (\n patchAlias: string,\n tableName: string,\n aslAlias: string = MAIN_DB_ALIAS,\n): string => `\n UPDATE ${aslAlias}.${tableName}\n SET content = ${updatePageColumn('content', aslAlias, patchAlias)},\n part = ${updatePageColumn('part', aslAlias, patchAlias)},\n page = ${updatePageColumn('page', aslAlias, patchAlias)},\n number = ${updatePageColumn('number', aslAlias, patchAlias)}\n WHERE EXISTS (\n SELECT 1\n FROM ${patchAlias}.${tableName}\n WHERE ${aslAlias}.${tableName}.id = ${patchAlias}.${tableName}.id\n );\n`;\n\nconst updateTitleColumn = (columnName: string, aslAlias: string, patchAlias: string) => `\n (SELECT CASE \n WHEN ${patchAlias}.title.${columnName} != '#' THEN ${patchAlias}.title.${columnName}\n ELSE ${aslAlias}.title.${columnName}\n END \n FROM ${patchAlias}.title\n WHERE ${aslAlias}.title.id = ${patchAlias}.title.id)\n`;\n\nexport const buildTitlePatchQuery = (\n patchAlias: string,\n tableName: string,\n aslAlias: string = MAIN_DB_ALIAS,\n): string => `\n UPDATE ${aslAlias}.${tableName}\n SET content = ${updateTitleColumn('content', aslAlias, patchAlias)},\n page = ${updateTitleColumn('page', aslAlias, patchAlias)},\n parent = ${updateTitleColumn('parent', aslAlias, patchAlias)}\n WHERE EXISTS (\n SELECT 1\n FROM ${patchAlias}.${tableName}\n WHERE ${aslAlias}.${tableName}.id = ${patchAlias}.${tableName}.id\n );\n`;\n\nexport const insertUnsafely = (table: string, fieldToValue: Record<string, any>, isDeleted = false): string => {\n const combinedRecords: Record<string, any> = { ...fieldToValue, is_deleted: isDeleted ? '1' : '0' };\n\n const sortedKeys = Object.keys(combinedRecords).sort();\n\n const sortedValues = sortedKeys.map((key) => combinedRecords[key]);\n\n return `INSERT INTO ${table} (${sortedKeys.toString()}) VALUES (${sortedValues\n .map((val) => {\n if (val === null) {\n return 'NULL';\n }\n\n return typeof val === 'string' ? `'${val}'` : val;\n })\n .toString()})`;\n};\n","export type AuthorRow = {\n biography: string;\n death: number;\n id: number;\n name: string;\n};\n\nexport type BookRow = {\n author: string;\n bibliography: string;\n category: number;\n date?: null | number;\n hint: null | string;\n id: number;\n major: number;\n metadata: string;\n minor?: number;\n name: string;\n pdf_links: null | string;\n printed: number;\n type: number;\n};\n\nexport type PageRow = {\n content: string;\n id: number;\n number: null | number;\n page: null | number;\n part: null | number;\n};\n\nexport type TitleRow = {\n content: string;\n id: number;\n page: number;\n parent: null | number;\n};\n\nexport type CategoryRow = {\n id: number;\n name: string;\n};\n\nexport enum Tables {\n Authors = 'authors',\n Books = 'books',\n Categories = 'categories',\n Page = 'page',\n Title = 'title',\n}\n","import { Client } from '@libsql/client';\nimport path from 'path';\n\nimport { Author, Book, Category, MasterData, PDFLinks } from '../types';\nimport { UNKNOWN_VALUE_PLACEHOLDER } from '../utils/constants';\nimport { selectAllRows } from './common';\nimport { attachDB, detachDB } from './queryBuilder';\nimport { BookRow, Tables } from './types';\n\nexport const createTables = async (db: Client) => {\n return db.batch([\n `CREATE TABLE authors (id INTEGER PRIMARY KEY, name TEXT, biography TEXT, death INTEGER)`,\n `CREATE TABLE books (id INTEGER PRIMARY KEY, name TEXT, category INTEGER, type INTEGER, date INTEGER, author TEXT, printed INTEGER, major INTEGER, minor INTEGER, bibliography TEXT, hint TEXT, pdf_links TEXT, metadata TEXT)`,\n `CREATE TABLE categories (id INTEGER PRIMARY KEY, name TEXT)`,\n ]);\n};\n\nexport const getAllAuthors = async (db: Client): Promise<Author[]> => {\n const rows = await selectAllRows(db, Tables.Authors);\n\n const authors: Author[] = rows.map((r: any) => ({\n ...(r.biography && { biography: r.biography }),\n ...(r.death && { death: r.death }),\n id: r.id,\n name: r.name,\n }));\n\n return authors;\n};\n\nexport const getAllCategories = async (db: Client): Promise<Category[]> => {\n const rows = await selectAllRows(db, Tables.Categories);\n\n const categories: Category[] = rows.map((r: any) => ({\n id: r.id,\n name: r.name,\n }));\n\n return categories;\n};\n\nconst parseAuthor = (value: string): number | number[] => {\n const result: number[] = value.split(',\\\\s+').map((id) => parseInt(id.trim()));\n return result.length > 1 ? result : result[0];\n};\n\nconst parsePdfLinks = (value: string): PDFLinks => {\n const result = JSON.parse(value);\n\n if (result.files) {\n result.files = (result.files as string[]).map((f: string) => {\n const [file, id] = f.split('|');\n return { ...(id && { id }), file };\n });\n }\n\n return result as PDFLinks;\n};\n\nexport const getAllBooks = async (db: Client): Promise<Book[]> => {\n const rows = await selectAllRows(db, Tables.Books);\n\n const books: Book[] = rows.map((row: any) => {\n const r = row as BookRow;\n\n return {\n author: parseAuthor(r.author),\n bibliography: r.bibliography,\n category: r.category,\n id: r.id,\n major: r.major,\n metadata: JSON.parse(r.metadata),\n name: r.name,\n printed: r.printed,\n type: r.type,\n ...(r.date && r.date.toString() !== UNKNOWN_VALUE_PLACEHOLDER && { date: r.date }),\n ...(r.hint && { hint: r.hint }),\n ...(r.pdf_links && { pdfLinks: parsePdfLinks(r.pdf_links) }),\n ...(r.minor && { minorRelease: r.minor }),\n };\n });\n\n return books;\n};\n\nexport const getData = async (db: Client): Promise<MasterData> => {\n const [authors, books, categories] = await Promise.all([getAllAuthors(db), getAllBooks(db), getAllCategories(db)]);\n return { authors, books, categories };\n};\n\nexport const copyForeignMasterTableData = async (db: Client, sourceTables: string[]) => {\n const aliasToPath: Record<string, string> = sourceTables.reduce((acc, tablePath) => {\n const { name } = path.parse(tablePath);\n return { ...acc, [name]: tablePath };\n }, {});\n\n const attachStatements: string[] = Object.entries(aliasToPath).map(([alias, dbPath]) => attachDB(dbPath, alias));\n await db.batch(attachStatements);\n\n const insertStatements: string[] = [\n `INSERT INTO ${Tables.Authors} SELECT id,name,biography,(CASE WHEN death_number = ${UNKNOWN_VALUE_PLACEHOLDER} THEN NULL ELSE death_number END) AS death_number FROM author WHERE is_deleted='0'`,\n `INSERT INTO ${Tables.Books} SELECT id,name,category,type,(CASE WHEN date = ${UNKNOWN_VALUE_PLACEHOLDER} THEN NULL ELSE date END) AS date,author,printed,major_release,minor_release,bibliography,hint,pdf_links,metadata FROM book WHERE is_deleted='0'`,\n `INSERT INTO ${Tables.Categories} SELECT id,name FROM category WHERE is_deleted='0'`,\n ];\n await db.batch(insertStatements);\n\n const detachStatements: string[] = Object.keys(aliasToPath).map(detachDB);\n await db.batch(detachStatements);\n};\n","export const DEFAULT_MASTER_METADATA_VERSION = 0;\n\nexport const UNKNOWN_VALUE_PLACEHOLDER = '99999';\n","import { createWriteStream, promises as fs } from 'fs';\nimport { IncomingMessage } from 'http';\nimport https from 'https';\nimport os from 'os';\nimport path from 'path';\nimport { pipeline } from 'stream/promises';\nimport unzipper, { Entry } from 'unzipper';\n\nexport const createTempDir = async (prefix = 'shamela') => {\n const tempDirBase = path.join(os.tmpdir(), prefix);\n return fs.mkdtemp(tempDirBase);\n};\n\nexport const fileExists = async (path: string) => !!(await fs.stat(path).catch(() => false));\n\n/**\n * Downloads and extracts a ZIP file from a given URL without loading the entire file into memory.\n *\n * @param url - The URL of the ZIP file to download and extract.\n * @param outputDir - The directory where the files should be extracted.\n * @returns A promise that resolves with the list of all extracted files.\n */\nexport async function unzipFromUrl(url: string, outputDir: string): Promise<string[]> {\n const extractedFiles: string[] = [];\n const entryPromises: Promise<void>[] = [];\n\n try {\n // Make HTTPS request and get the response stream\n const response = await new Promise<IncomingMessage>((resolve, reject) => {\n https\n .get(url, (res) => {\n if (res.statusCode !== 200) {\n reject(new Error(`Failed to download ZIP file: ${res.statusCode} ${res.statusMessage}`));\n } else {\n resolve(res);\n }\n })\n .on('error', (err) => {\n reject(new Error(`HTTPS request failed: ${err.message}`));\n });\n });\n\n // Create unzip stream\n const unzipStream = unzipper.Parse();\n\n // Handle entries in the ZIP file\n unzipStream.on('entry', (entry: Entry) => {\n const entryPromise = (async () => {\n const filePath = path.join(outputDir, entry.path);\n\n if (entry.type === 'Directory') {\n // Ensure the directory exists\n await fs.mkdir(filePath, { recursive: true });\n entry.autodrain();\n } else {\n // Ensure the parent directory exists\n const dir = path.dirname(filePath);\n await fs.mkdir(dir, { recursive: true });\n\n // Pipe the entry to a file\n await pipeline(entry, createWriteStream(filePath));\n extractedFiles.push(filePath);\n }\n })().catch((err) => {\n // Emit errors to be handled by the unzipStream error handler\n unzipStream.emit('error', err);\n });\n\n // Collect the promises\n entryPromises.push(entryPromise);\n });\n\n // Handle errors in the unzip stream\n unzipStream.on('error', (err) => {\n throw new Error(`Error during extraction: ${err.message}`);\n });\n\n // Pipe the response into the unzip stream\n await pipeline(response, unzipStream);\n\n // Wait for all entry promises to complete\n await Promise.all(entryPromises);\n\n return extractedFiles;\n } catch (error: any) {\n throw new Error(`Error processing URL: ${error.message}`);\n }\n}\n","import { Buffer } from 'buffer';\nimport { IncomingMessage } from 'http';\nimport https from 'https';\nimport process from 'process';\nimport { URL, URLSearchParams } from 'url';\n\nexport const buildUrl = (endpoint: string, params: Record<string, any>, useAuth: boolean = true): URL => {\n const url = new URL(endpoint);\n {\n const params = new URLSearchParams();\n\n Object.entries(params).forEach(([key, value]) => {\n params.append(key, value.toString());\n });\n\n if (useAuth) {\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n }\n\n url.search = params.toString();\n }\n\n return url;\n};\n\nexport const httpsGet = (url: string | URL): Promise<Buffer | Record<string, any>> => {\n return new Promise((resolve, reject) => {\n https\n .get(url, (res: IncomingMessage) => {\n const contentType = res.headers['content-type'] || '';\n const dataChunks: Buffer[] = [];\n\n res.on('data', (chunk: Buffer) => {\n dataChunks.push(chunk);\n });\n\n res.on('end', () => {\n const fullData = Buffer.concat(dataChunks);\n\n if (contentType.includes('application/json')) {\n try {\n const json = JSON.parse(fullData.toString('utf-8'));\n resolve(json);\n } catch (error: any) {\n reject(new Error(`Failed to parse JSON: ${error.message}`));\n }\n } else {\n resolve(fullData);\n }\n });\n })\n .on('error', (error) => {\n reject(new Error(`Error making request: ${error.message}`));\n });\n });\n};\n","import path from 'path';\nimport process from 'process';\n\nconst SOURCE_TABLES = ['author.sqlite', 'book.sqlite', 'category.sqlite'];\n\nexport const validateMasterSourceTables = (sourceTablePaths: string[]) => {\n const sourceTableNames = sourceTablePaths.map((tablePath) => path.parse(tablePath).base);\n return SOURCE_TABLES.every((table) => sourceTableNames.includes(table));\n};\n\nexport const validateEnvVariables = () => {\n if (!process.env.SHAMELA_API_MASTER_PATCH_ENDPOINT) {\n throw new Error('SHAMELA_API_MASTER_PATCH_ENDPOINT environment variable not set');\n }\n\n if (!process.env.SHAMELA_API_KEY) {\n throw new Error('SHAMELA_API_KEY environment variable not set');\n }\n};\n"],"names":[],"version":3,"file":"main.js.map","sourceRoot":"../"}
1
+ {"mappings":"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","sources":["src/index.ts","src/api.ts","src/db/book.ts","src/utils/logger.ts","src/db/common.ts","src/db/queryBuilder.ts","src/db/types.ts","src/db/master.ts","src/utils/constants.ts","src/utils/io.ts","src/utils/network.ts","src/utils/validation.ts","src/types.ts"],"sourcesContent":["import { downloadBook, downloadMasterDatabase, getBook, getBookMetadata, getMasterMetadata } from './api';\n\nexport { downloadBook, downloadMasterDatabase, getBook, getBookMetadata, getMasterMetadata };\n\nexport * from './types';\n","import { Client, createClient } from '@libsql/client';\nimport { promises as fs } from 'fs';\nimport path from 'path';\nimport process from 'process';\nimport { URL, URLSearchParams } from 'url';\n\nimport { applyPatches, copyTableData, createTables as createBookTables, getData as getBookData } from './db/book.js';\nimport {\n copyForeignMasterTableData,\n createTables as createMasterTables,\n getData as getMasterData,\n} from './db/master.js';\nimport {\n BookData,\n DownloadBookOptions,\n DownloadMasterOptions,\n GetBookMetadataOptions,\n GetBookMetadataResponsePayload,\n GetMasterMetadataResponsePayload,\n} from './types.js';\nimport { DEFAULT_MASTER_METADATA_VERSION } from './utils/constants.js';\nimport { createTempDir, unzipFromUrl } from './utils/io.js';\nimport logger from './utils/logger.js';\nimport { httpsGet } from './utils/network.js';\nimport { validateEnvVariables, validateMasterSourceTables } from './utils/validation.js';\n\nexport const getBookMetadata = async (\n id: number,\n options?: GetBookMetadataOptions,\n): Promise<GetBookMetadataResponsePayload> => {\n validateEnvVariables();\n\n const url = new URL(`${process.env.SHAMELA_API_BOOKS_ENDPOINT}/${id}`);\n {\n const params = new URLSearchParams();\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n params.append('major_release', (options?.majorVersion || 0).toString());\n params.append('minor_release', (options?.minorVersion || 0).toString());\n url.search = params.toString();\n }\n\n logger.info(`Fetching shamela.ws book link: ${url.toString()}`);\n\n try {\n const response: Record<string, any> = await httpsGet(url);\n return {\n majorRelease: response.major_release,\n majorReleaseUrl: response.major_release_url,\n ...(response.minor_release_url && { minorReleaseUrl: response.minor_release_url }),\n ...(response.minor_release_url && { minorRelease: response.minor_release }),\n };\n } catch (error: any) {\n throw new Error(`Error fetching master patch: ${error.message}`);\n }\n};\n\nexport const downloadBook = async (id: number, options: DownloadBookOptions): Promise<string> => {\n logger.info(`downloadBook ${id} ${JSON.stringify(options)}`);\n\n const outputDir = await createTempDir('shamela_downloadBook');\n\n const bookResponse: GetBookMetadataResponsePayload = options?.bookMetadata || (await getBookMetadata(id));\n const [[bookDatabase], [patchDatabase] = []]: string[][] = await Promise.all([\n unzipFromUrl(bookResponse.majorReleaseUrl, outputDir),\n ...(bookResponse.minorReleaseUrl ? [unzipFromUrl(bookResponse.minorReleaseUrl, outputDir)] : []),\n ]);\n const dbPath = path.join(outputDir, 'book.db');\n\n const client: Client = createClient({\n url: `file:${dbPath}`,\n });\n\n try {\n logger.info(`Creating tables`);\n await createBookTables(client);\n\n if (patchDatabase) {\n logger.info(`Applying patches from ${patchDatabase} to ${bookDatabase}`);\n await applyPatches(client, bookDatabase, patchDatabase);\n } else {\n logger.info(`Copying table data from ${bookDatabase}`);\n await copyTableData(client, bookDatabase);\n }\n\n const { ext: extension } = path.parse(options.outputFile.path);\n\n if (extension === '.json') {\n const result = await getBookData(client);\n await fs.writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), 'utf8');\n }\n\n client.close();\n\n if (extension === '.db' || extension === '.sqlite') {\n await fs.rename(dbPath, options.outputFile.path);\n }\n\n await fs.rm(outputDir, { recursive: true });\n } finally {\n client.close();\n }\n\n return options.outputFile.path;\n};\n\nexport const getMasterMetadata = async (version: number = 0): Promise<GetMasterMetadataResponsePayload> => {\n validateEnvVariables();\n\n const url = new URL(process.env.SHAMELA_API_MASTER_PATCH_ENDPOINT as string);\n {\n const params = new URLSearchParams();\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n params.append('version', version.toString());\n url.search = params.toString();\n }\n\n logger.info(`Fetching shamela.ws master database patch link: ${url.toString()}`);\n\n try {\n const response: Record<string, any> = await httpsGet(url);\n return { url: response.patch_url, version: response.version };\n } catch (error: any) {\n throw new Error(`Error fetching master patch: ${error.message}`);\n }\n};\n\nexport const downloadMasterDatabase = async (options: DownloadMasterOptions): Promise<string> => {\n logger.info(`downloadMasterDatabase ${JSON.stringify(options)}`);\n\n const outputDir = await createTempDir('shamela_downloadMaster');\n\n const masterResponse: GetMasterMetadataResponsePayload =\n options.masterMetadata || (await getMasterMetadata(DEFAULT_MASTER_METADATA_VERSION));\n\n logger.info(`Downloading master database from: ${JSON.stringify(masterResponse)}`);\n const sourceTables: string[] = await unzipFromUrl(masterResponse.url, outputDir);\n\n logger.info(`sourceTables downloaded: ${sourceTables.toString()}`);\n\n if (!validateMasterSourceTables(sourceTables)) {\n logger.error(`Some source tables were not found: ${sourceTables.toString()}`);\n throw new Error('Expected tables not found!');\n }\n\n const dbPath = path.join(outputDir, 'master.db');\n\n const client: Client = createClient({\n url: `file:${dbPath}`,\n });\n\n try {\n logger.info(`Creating tables`);\n await createMasterTables(client);\n\n logger.info(`Copying data to master table`);\n await copyForeignMasterTableData(client, sourceTables);\n\n const { ext: extension } = path.parse(options.outputFile.path);\n\n if (extension === '.json') {\n const result = await getMasterData(client);\n await fs.writeFile(options.outputFile.path, JSON.stringify(result, undefined, 2), 'utf8');\n }\n\n client.close();\n\n if (extension === '.db' || extension === '.sqlite') {\n await fs.rename(dbPath, options.outputFile.path);\n }\n\n await fs.rm(outputDir, { recursive: true });\n } finally {\n client.close();\n }\n\n return options.outputFile.path;\n};\n\nexport const getBook = async (id: number): Promise<BookData> => {\n const outputDir = await createTempDir('shamela_getBookData');\n const outputPath = await downloadBook(id, { outputFile: { path: path.join(outputDir, `${id}.json`) } });\n\n const data = JSON.parse(await fs.readFile(outputPath, 'utf8')) as BookData;\n await fs.rm(outputDir, { recursive: true });\n\n return data;\n};\n","import { Client } from '@libsql/client';\n\nimport { BookData, Page, Title } from '../types';\nimport logger from '../utils/logger';\nimport { getInternalTables, InternalTable, selectAllRows } from './common';\nimport { attachDB, buildPagePatchQuery, buildTitlePatchQuery, detachDB } from './queryBuilder';\nimport { PageRow, Tables, TitleRow } from './types';\n\nconst PATCH_DB_ALIAS = 'patch';\nconst ASL_DB_ALIAS = 'asl';\n\nconst getPagesToCopy = (tables: InternalTable[]): string[] => {\n const statements = [];\n\n if (tables.find((t) => t.name === Tables.Page)) {\n statements.push(\n `INSERT INTO main.${Tables.Page} SELECT id,content,part,page,number FROM ${ASL_DB_ALIAS}.${Tables.Page} WHERE id IN (SELECT id FROM ${PATCH_DB_ALIAS}.${Tables.Page} WHERE is_deleted='0')`,\n );\n statements.push(buildPagePatchQuery(PATCH_DB_ALIAS, Tables.Page));\n } else {\n statements.push(\n `INSERT INTO main.${Tables.Page} SELECT id,content,part,page,number FROM ${ASL_DB_ALIAS}.${Tables.Page} WHERE is_deleted='0'`,\n );\n }\n\n return statements;\n};\n\nconst getTitlesToCopy = (tables: InternalTable[]): string[] => {\n const statements = [];\n\n if (tables.find((t) => t.name === Tables.Title)) {\n statements.push(\n `INSERT INTO main.${Tables.Title} SELECT id,content,page,parent FROM ${ASL_DB_ALIAS}.${Tables.Title} WHERE id IN (SELECT id FROM ${PATCH_DB_ALIAS}.${Tables.Title} WHERE is_deleted='0')`,\n );\n statements.push(buildTitlePatchQuery(PATCH_DB_ALIAS, Tables.Title));\n } else {\n statements.push(\n `INSERT INTO main.${Tables.Title} SELECT id,content,page,parent FROM ${ASL_DB_ALIAS}.${Tables.Title} WHERE is_deleted='0'`,\n );\n }\n\n return statements;\n};\n\nexport const applyPatches = async (db: Client, aslDB: string, patchDB?: string) => {\n const statements: string[] = [attachDB(aslDB, ASL_DB_ALIAS)];\n\n if (patchDB) {\n await db.execute(attachDB(patchDB, PATCH_DB_ALIAS));\n }\n\n const tables = patchDB ? await getInternalTables(db, PATCH_DB_ALIAS) : [];\n\n logger.debug({ tables }, `Applying patches for...`);\n\n statements.push(...getPagesToCopy(tables));\n statements.push(...getTitlesToCopy(tables));\n\n await db.batch(statements);\n\n const detachStatements = [];\n detachStatements.push(detachDB(ASL_DB_ALIAS));\n\n if (patchDB) {\n detachStatements.push(detachDB(PATCH_DB_ALIAS));\n }\n\n return db.batch(detachStatements);\n};\n\nexport const copyTableData = async (db: Client, aslDB: string) => {\n await db.execute(attachDB(aslDB, ASL_DB_ALIAS));\n const tables = await getInternalTables(db, ASL_DB_ALIAS);\n\n logger.debug({ tables }, `Applying patches for...`);\n\n await db.batch([\n `INSERT INTO main.${Tables.Title} SELECT id,content,page,parent FROM ${ASL_DB_ALIAS}.${Tables.Title}`,\n `INSERT INTO main.${Tables.Page} SELECT id,content,part,page,number FROM ${ASL_DB_ALIAS}.${Tables.Page}`,\n ]);\n\n return db.execute(detachDB(ASL_DB_ALIAS));\n};\n\nexport const createTables = async (db: Client) => {\n return db.batch([\n `CREATE TABLE page (id INTEGER PRIMARY KEY, content TEXT, part INTEGER, page INTEGER, number INTEGER)`,\n `CREATE TABLE title (id INTEGER PRIMARY KEY, content TEXT, page INTEGER, parent INTEGER)`,\n ]);\n};\n\nexport const getAllPages = async (db: Client): Promise<Page[]> => {\n const rows = await selectAllRows(db, Tables.Page);\n\n const pages: Page[] = rows.map((row: any) => {\n const { content, id, number, page, part } = row as PageRow;\n\n return {\n content,\n id,\n ...(page && { page }),\n ...(number && { number }),\n ...(part && { part }),\n };\n });\n\n return pages;\n};\n\nexport const getAllTitles = async (db: Client): Promise<Title[]> => {\n const rows = await selectAllRows(db, Tables.Title);\n\n const titles: Title[] = rows.map((row: any) => {\n const r = row as TitleRow;\n\n return {\n content: r.content,\n id: r.id,\n page: r.page,\n ...(r.parent && { number: r.parent }),\n };\n });\n\n return titles;\n};\n\nexport const getData = async (db: Client): Promise<BookData> => {\n const [pages, titles] = await Promise.all([getAllPages(db), getAllTitles(db)]);\n return { pages, titles };\n};\n","import pino, { Logger } from 'pino';\nimport pretty, { PrettyOptions } from 'pino-pretty';\nimport process from 'process';\n\nconst stream = pretty({\n colorize: true,\n} as PrettyOptions);\n\nconst logger: Logger = pino(\n {\n base: { pid: undefined, hostname: undefined }, // This will remove pid and hostname but keep time\n level: process.env.LOG_LEVEL || 'info',\n },\n stream,\n);\n\nexport default logger;\n","import { Client, Row } from '@libsql/client';\n\nexport type InternalTable = {\n name: string;\n};\n\nexport const getInternalTables = async (db: Client, dbName: string): Promise<InternalTable[]> => {\n const { rows: tables } = await db.execute(`SELECT name FROM ${dbName}.sqlite_master WHERE type='table'`);\n\n return tables as unknown as InternalTable[];\n};\n\nexport const selectAllRows = async (client: Client, table: string): Promise<Row[]> => {\n const { rows } = await client.execute(`SELECT * FROM ${table}`);\n return rows;\n};\n","const MAIN_DB_ALIAS = 'main';\n\nexport const attachDB = (dbFile: string, alias: string) => `ATTACH DATABASE '${dbFile}' AS ${alias}`;\n\nexport const buildPagePatchQuery = (\n patchAlias: string,\n tableName: string,\n aslAlias: string = MAIN_DB_ALIAS,\n): string => `\n UPDATE ${aslAlias}.${tableName}\n SET content = ${updatePageColumn('content', aslAlias, patchAlias)},\n part = ${updatePageColumn('part', aslAlias, patchAlias)},\n page = ${updatePageColumn('page', aslAlias, patchAlias)},\n number = ${updatePageColumn('number', aslAlias, patchAlias)}\n WHERE EXISTS (\n SELECT 1\n FROM ${patchAlias}.${tableName}\n WHERE ${aslAlias}.${tableName}.id = ${patchAlias}.${tableName}.id\n );\n`;\n\nconst updateTitleColumn = (columnName: string, aslAlias: string, patchAlias: string) => `\n (SELECT CASE \n WHEN ${patchAlias}.title.${columnName} != '#' THEN ${patchAlias}.title.${columnName}\n ELSE ${aslAlias}.title.${columnName}\n END \n FROM ${patchAlias}.title\n WHERE ${aslAlias}.title.id = ${patchAlias}.title.id)\n`;\n\nexport const buildTitlePatchQuery = (\n patchAlias: string,\n tableName: string,\n aslAlias: string = MAIN_DB_ALIAS,\n): string => `\n UPDATE ${aslAlias}.${tableName}\n SET content = ${updateTitleColumn('content', aslAlias, patchAlias)},\n page = ${updateTitleColumn('page', aslAlias, patchAlias)},\n parent = ${updateTitleColumn('parent', aslAlias, patchAlias)}\n WHERE EXISTS (\n SELECT 1\n FROM ${patchAlias}.${tableName}\n WHERE ${aslAlias}.${tableName}.id = ${patchAlias}.${tableName}.id\n );\n`;\n\nexport const createTable = (name: string, fields: string[]): string =>\n `CREATE TABLE IF NOT EXISTS ${name} (${fields.join(', ')})`;\n\nexport const detachDB = (alias: string) => `DETACH DATABASE ${alias}`;\n\nconst updatePageColumn = (columnName: string, aslAlias: string, patchAlias: string): string => `\n (SELECT CASE \n WHEN ${patchAlias}.page.${columnName} != '#' THEN ${patchAlias}.page.${columnName}\n ELSE ${aslAlias}.page.${columnName}\n END \n FROM ${patchAlias}.page\n WHERE ${aslAlias}.page.id = ${patchAlias}.page.id)\n`;\n\nexport const insertUnsafely = (table: string, fieldToValue: Record<string, any>, isDeleted = false): string => {\n const combinedRecords: Record<string, any> = { ...fieldToValue, is_deleted: isDeleted ? '1' : '0' };\n\n const sortedKeys = Object.keys(combinedRecords).sort();\n\n const sortedValues = sortedKeys.map((key) => combinedRecords[key]);\n\n return `INSERT INTO ${table} (${sortedKeys.toString()}) VALUES (${sortedValues\n .map((val) => {\n if (val === null) {\n return 'NULL';\n }\n\n return typeof val === 'string' ? `'${val}'` : val;\n })\n .toString()})`;\n};\n","export type AuthorRow = {\n biography: string;\n death: number;\n id: number;\n name: string;\n};\n\nexport type BookRow = {\n author: string;\n bibliography: string;\n category: number;\n date?: null | number;\n hint: null | string;\n id: number;\n major: number;\n metadata: string;\n minor?: number;\n name: string;\n pdf_links: null | string;\n printed: number;\n type: number;\n};\n\nexport type PageRow = {\n content: string;\n id: number;\n number: null | number;\n page: null | number;\n part: null | number;\n};\n\nexport type TitleRow = {\n content: string;\n id: number;\n page: number;\n parent: null | number;\n};\n\nexport type CategoryRow = {\n id: number;\n name: string;\n};\n\nexport enum Tables {\n Authors = 'authors',\n Books = 'books',\n Categories = 'categories',\n Page = 'page',\n Title = 'title',\n}\n","import { Client } from '@libsql/client';\nimport path from 'path';\n\nimport { Author, Book, Category, MasterData, PDFLinks } from '../types';\nimport { UNKNOWN_VALUE_PLACEHOLDER } from '../utils/constants';\nimport { selectAllRows } from './common';\nimport { attachDB, detachDB } from './queryBuilder';\nimport { BookRow, Tables } from './types';\n\nexport const copyForeignMasterTableData = async (db: Client, sourceTables: string[]) => {\n const aliasToPath: Record<string, string> = sourceTables.reduce((acc, tablePath) => {\n const { name } = path.parse(tablePath);\n return { ...acc, [name]: tablePath };\n }, {});\n\n const attachStatements: string[] = Object.entries(aliasToPath).map(([alias, dbPath]) => attachDB(dbPath, alias));\n await db.batch(attachStatements);\n\n const insertStatements: string[] = [\n `INSERT INTO ${Tables.Authors} SELECT id,name,biography,(CASE WHEN death_number = ${UNKNOWN_VALUE_PLACEHOLDER} THEN NULL ELSE death_number END) AS death_number FROM author WHERE is_deleted='0'`,\n `INSERT INTO ${Tables.Books} SELECT id,name,category,type,(CASE WHEN date = ${UNKNOWN_VALUE_PLACEHOLDER} THEN NULL ELSE date END) AS date,author,printed,major_release,minor_release,bibliography,hint,pdf_links,metadata FROM book WHERE is_deleted='0'`,\n `INSERT INTO ${Tables.Categories} SELECT id,name FROM category WHERE is_deleted='0'`,\n ];\n await db.batch(insertStatements);\n\n const detachStatements: string[] = Object.keys(aliasToPath).map(detachDB);\n await db.batch(detachStatements);\n};\n\nexport const createTables = async (db: Client) => {\n return db.batch([\n `CREATE TABLE authors (id INTEGER PRIMARY KEY, name TEXT, biography TEXT, death INTEGER)`,\n `CREATE TABLE books (id INTEGER PRIMARY KEY, name TEXT, category INTEGER, type INTEGER, date INTEGER, author TEXT, printed INTEGER, major INTEGER, minor INTEGER, bibliography TEXT, hint TEXT, pdf_links TEXT, metadata TEXT)`,\n `CREATE TABLE categories (id INTEGER PRIMARY KEY, name TEXT)`,\n ]);\n};\n\nexport const getAllAuthors = async (db: Client): Promise<Author[]> => {\n const rows = await selectAllRows(db, Tables.Authors);\n\n const authors: Author[] = rows.map((r: any) => ({\n ...(r.biography && { biography: r.biography }),\n ...(r.death && { death: r.death }),\n id: r.id,\n name: r.name,\n }));\n\n return authors;\n};\n\nexport const getAllBooks = async (db: Client): Promise<Book[]> => {\n const rows = await selectAllRows(db, Tables.Books);\n\n const books: Book[] = rows.map((row: any) => {\n const r = row as BookRow;\n\n return {\n author: parseAuthor(r.author),\n bibliography: r.bibliography,\n category: r.category,\n id: r.id,\n major: r.major,\n metadata: JSON.parse(r.metadata),\n name: r.name,\n printed: r.printed,\n type: r.type,\n ...(r.date && r.date.toString() !== UNKNOWN_VALUE_PLACEHOLDER && { date: r.date }),\n ...(r.hint && { hint: r.hint }),\n ...(r.pdf_links && { pdfLinks: parsePdfLinks(r.pdf_links) }),\n ...(r.minor && { minorRelease: r.minor }),\n };\n });\n\n return books;\n};\n\nexport const getAllCategories = async (db: Client): Promise<Category[]> => {\n const rows = await selectAllRows(db, Tables.Categories);\n\n const categories: Category[] = rows.map((r: any) => ({\n id: r.id,\n name: r.name,\n }));\n\n return categories;\n};\n\nconst parseAuthor = (value: string): number | number[] => {\n const result: number[] = value.split(',\\\\s+').map((id) => parseInt(id.trim()));\n return result.length > 1 ? result : result[0];\n};\n\nconst parsePdfLinks = (value: string): PDFLinks => {\n const result = JSON.parse(value);\n\n if (result.files) {\n result.files = (result.files as string[]).map((f: string) => {\n const [file, id] = f.split('|');\n return { ...(id && { id }), file };\n });\n }\n\n return result as PDFLinks;\n};\n\nexport const getData = async (db: Client): Promise<MasterData> => {\n const [authors, books, categories] = await Promise.all([getAllAuthors(db), getAllBooks(db), getAllCategories(db)]);\n return { authors, books, categories };\n};\n","export const DEFAULT_MASTER_METADATA_VERSION = 0;\n\nexport const UNKNOWN_VALUE_PLACEHOLDER = '99999';\n","import { createWriteStream, promises as fs } from 'fs';\nimport { IncomingMessage } from 'http';\nimport https from 'https';\nimport os from 'os';\nimport path from 'path';\nimport { pipeline } from 'stream/promises';\nimport unzipper, { Entry } from 'unzipper';\n\nexport const createTempDir = async (prefix = 'shamela') => {\n const tempDirBase = path.join(os.tmpdir(), prefix);\n return fs.mkdtemp(tempDirBase);\n};\n\nexport const fileExists = async (path: string) => !!(await fs.stat(path).catch(() => false));\n\n/**\n * Downloads and extracts a ZIP file from a given URL without loading the entire file into memory.\n *\n * @param url - The URL of the ZIP file to download and extract.\n * @param outputDir - The directory where the files should be extracted.\n * @returns A promise that resolves with the list of all extracted files.\n */\nexport async function unzipFromUrl(url: string, outputDir: string): Promise<string[]> {\n const extractedFiles: string[] = [];\n const entryPromises: Promise<void>[] = [];\n\n try {\n // Make HTTPS request and get the response stream\n const response = await new Promise<IncomingMessage>((resolve, reject) => {\n https\n .get(url, (res) => {\n if (res.statusCode !== 200) {\n reject(new Error(`Failed to download ZIP file: ${res.statusCode} ${res.statusMessage}`));\n } else {\n resolve(res);\n }\n })\n .on('error', (err) => {\n reject(new Error(`HTTPS request failed: ${err.message}`));\n });\n });\n\n // Create unzip stream\n const unzipStream = unzipper.Parse();\n\n // Handle entries in the ZIP file\n unzipStream.on('entry', (entry: Entry) => {\n const entryPromise = (async () => {\n const filePath = path.join(outputDir, entry.path);\n\n if (entry.type === 'Directory') {\n // Ensure the directory exists\n await fs.mkdir(filePath, { recursive: true });\n entry.autodrain();\n } else {\n // Ensure the parent directory exists\n const dir = path.dirname(filePath);\n await fs.mkdir(dir, { recursive: true });\n\n // Pipe the entry to a file\n await pipeline(entry, createWriteStream(filePath));\n extractedFiles.push(filePath);\n }\n })().catch((err) => {\n // Emit errors to be handled by the unzipStream error handler\n unzipStream.emit('error', err);\n });\n\n // Collect the promises\n entryPromises.push(entryPromise);\n });\n\n // Handle errors in the unzip stream\n unzipStream.on('error', (err) => {\n throw new Error(`Error during extraction: ${err.message}`);\n });\n\n // Pipe the response into the unzip stream\n await pipeline(response, unzipStream);\n\n // Wait for all entry promises to complete\n await Promise.all(entryPromises);\n\n return extractedFiles;\n } catch (error: any) {\n throw new Error(`Error processing URL: ${error.message}`);\n }\n}\n","import { Buffer } from 'buffer';\nimport { IncomingMessage } from 'http';\nimport https from 'https';\nimport process from 'process';\nimport { URL, URLSearchParams } from 'url';\n\nexport const buildUrl = (endpoint: string, params: Record<string, any>, useAuth: boolean = true): URL => {\n const url = new URL(endpoint);\n {\n const params = new URLSearchParams();\n\n Object.entries(params).forEach(([key, value]) => {\n params.append(key, value.toString());\n });\n\n if (useAuth) {\n params.append('api_key', process.env.SHAMELA_API_KEY as string);\n }\n\n url.search = params.toString();\n }\n\n return url;\n};\n\nexport const httpsGet = (url: string | URL): Promise<Buffer | Record<string, any>> => {\n return new Promise((resolve, reject) => {\n https\n .get(url, (res: IncomingMessage) => {\n const contentType = res.headers['content-type'] || '';\n const dataChunks: Buffer[] = [];\n\n res.on('data', (chunk: Buffer) => {\n dataChunks.push(chunk);\n });\n\n res.on('end', () => {\n const fullData = Buffer.concat(dataChunks);\n\n if (contentType.includes('application/json')) {\n try {\n const json = JSON.parse(fullData.toString('utf-8'));\n resolve(json);\n } catch (error: any) {\n reject(new Error(`Failed to parse JSON: ${error.message}`));\n }\n } else {\n resolve(fullData);\n }\n });\n })\n .on('error', (error) => {\n reject(new Error(`Error making request: ${error.message}`));\n });\n });\n};\n","import path from 'path';\nimport process from 'process';\n\nconst SOURCE_TABLES = ['author.sqlite', 'book.sqlite', 'category.sqlite'];\n\nexport const validateEnvVariables = () => {\n if (!process.env.SHAMELA_API_MASTER_PATCH_ENDPOINT) {\n throw new Error('SHAMELA_API_MASTER_PATCH_ENDPOINT environment variable not set');\n }\n\n if (!process.env.SHAMELA_API_KEY) {\n throw new Error('SHAMELA_API_KEY environment variable not set');\n }\n};\n\nexport const validateMasterSourceTables = (sourceTablePaths: string[]) => {\n const sourceTableNames = sourceTablePaths.map((tablePath) => path.parse(tablePath).base);\n return SOURCE_TABLES.every((table) => sourceTableNames.includes(table));\n};\n","export type GetMasterMetadataResponsePayload = {\n url: string;\n version: number;\n};\n\nexport interface OutputOptions {\n path: string;\n}\n\nexport type DownloadMasterOptions = {\n masterMetadata?: GetMasterMetadataResponsePayload;\n outputFile: OutputOptions;\n};\n\nexport type GetBookMetadataOptions = {\n majorVersion: number;\n minorVersion: number;\n};\n\nexport type GetBookMetadataResponsePayload = {\n majorRelease: number;\n majorReleaseUrl: string;\n minorRelease?: number;\n minorReleaseUrl?: string;\n};\n\nexport type DownloadBookOptions = {\n bookMetadata?: GetBookMetadataResponsePayload;\n outputFile: OutputOptions;\n};\n\nexport type Author = {\n biography?: string;\n death?: number;\n id: number;\n name: string;\n};\n\ntype PDFFile = {\n file: string;\n id?: string;\n};\n\nexport type PDFLinks = {\n alias?: number;\n cover?: number;\n cover_alias?: number;\n files?: PDFFile[];\n root?: string;\n size?: number;\n};\n\nexport type Metadata = {\n coauthor?: number[];\n date: string;\n group?: number;\n hide_diacritic?: boolean;\n min_ver?: number;\n prefix?: string;\n shorts: Record<string, string>;\n sub_books: number[];\n suffix?: string;\n};\n\nexport type Book = {\n author: number | number[];\n bibliography: string;\n category: number;\n date?: number;\n hint?: string;\n id: number;\n major: number;\n metadata: Metadata;\n minor?: number;\n name: string;\n pdfLinks?: PDFLinks;\n printed: number;\n type: number;\n};\n\nexport type Category = {\n id: number;\n name: string;\n};\n\nexport type MasterData = {\n authors: Author[];\n books: Book[];\n categories: Category[];\n};\n\nexport type Page = {\n content: string;\n id: number;\n number?: number;\n page?: number;\n part?: number;\n};\n\nexport type Title = {\n content: string;\n id: number;\n page: number;\n parent?: number;\n};\n\nexport type BookData = {\n pages: Page[];\n titles?: Title[];\n};\n"],"names":[],"version":3,"file":"main.js.map","sourceRoot":"../"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shamela",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Library to interact with the Maktabah Shamela v4 APIs",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,35 +34,35 @@
34
34
  "author": "Ragaeeb Haq",
35
35
  "license": "MIT",
36
36
  "devDependencies": {
37
- "@eslint/js": "^9.10.0",
37
+ "@eslint/js": "^9.12.0",
38
38
  "@parcel/packager-ts": "^2.12.0",
39
39
  "@parcel/transformer-typescript-types": "^2.12.0",
40
40
  "@semantic-release/changelog": "^6.0.3",
41
41
  "@semantic-release/git": "^10.0.1",
42
42
  "@types/eslint__js": "^8.42.3",
43
- "@types/node": "^22.5.5",
43
+ "@types/node": "^22.7.5",
44
44
  "@types/unzipper": "^0.10.10",
45
- "@vitest/coverage-v8": "^2.1.1",
45
+ "@vitest/coverage-v8": "^2.1.2",
46
46
  "dotenv-vault": "^1.26.2",
47
- "eslint": "^9.10.0",
47
+ "eslint": "^9.12.0",
48
48
  "eslint-config-prettier": "^9.1.0",
49
- "eslint-plugin-import": "^2.30.0",
50
- "eslint-plugin-perfectionist": "^3.6.0",
49
+ "eslint-plugin-orderly-functions": "^1.1.0",
50
+ "eslint-plugin-perfectionist": "^3.8.0",
51
51
  "eslint-plugin-prettier": "^5.2.1",
52
52
  "eslint-plugin-vitest": "^0.5.4",
53
53
  "eslint-plugin-vitest-globals": "^1.5.0",
54
54
  "parcel": "^2.12.0",
55
55
  "prettier": "^3.3.3",
56
- "semantic-release": "^24.1.1",
57
- "ts-node": "^10.9.2",
58
- "typescript": "^5.6.2",
59
- "typescript-eslint": "^8.5.0",
60
- "vitest": "^2.1.1"
56
+ "semantic-release": "^24.1.2",
57
+ "typescript": "^5.6.3",
58
+ "typescript-eslint": "^8.8.1",
59
+ "vitest": "^2.1.2"
61
60
  },
62
61
  "dependencies": {
63
- "@libsql/client": "^0.11.0",
62
+ "@libsql/client": "^0.14.0",
64
63
  "pino": "^9.4.0",
65
64
  "pino-pretty": "^11.2.2",
66
65
  "unzipper": "^0.12.3"
67
- }
66
+ },
67
+ "packageManager": "pnpm@9.12.1+sha512.e5a7e52a4183a02d5931057f7a0dbff9d5e9ce3161e33fa68ae392125b79282a8a8a470a51dfc8a0ed86221442eb2fb57019b0990ed24fab519bf0e1bc5ccfc4"
68
68
  }