@im-nobsidian/core 0.1.8 → 0.1.10

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.js CHANGED
@@ -810,13 +810,16 @@ var NotionClient = class _NotionClient {
810
810
  sema;
811
811
  token;
812
812
  propertyMapper = new PropertyMapper();
813
+ customFetch;
813
814
  constructor(options) {
814
815
  this.client = new Client({
815
816
  auth: options.token,
816
817
  timeoutMs: options.timeoutMs ?? 3e4,
817
- logLevel: LogLevel.ERROR
818
+ logLevel: LogLevel.ERROR,
819
+ ...options.fetch ? { fetch: options.fetch } : {}
818
820
  });
819
821
  this.token = options.token;
822
+ this.customFetch = options.fetch;
820
823
  this.sema = new Sema(options.concurrency ?? 3);
821
824
  }
822
825
  getInternalClient() {
@@ -909,7 +912,8 @@ var NotionClient = class _NotionClient {
909
912
  const cleanId = databaseId.replace(/-/g, "");
910
913
  const formatted = `${cleanId.slice(0, 8)}-${cleanId.slice(8, 12)}-${cleanId.slice(12, 16)}-${cleanId.slice(16, 20)}-${cleanId.slice(20)}`;
911
914
  const resp = await this.withRateLimit(async () => {
912
- const r = await fetch(`https://api.notion.com/v1/databases/${formatted}`, {
915
+ const doFetch = this.customFetch ?? globalThis.fetch;
916
+ const r = await doFetch(`https://api.notion.com/v1/databases/${formatted}`, {
913
917
  headers: {
914
918
  Authorization: `Bearer ${this.token}`,
915
919
  "Notion-Version": "2022-06-28",
@@ -936,6 +940,39 @@ var NotionClient = class _NotionClient {
936
940
  }
937
941
  return schema;
938
942
  }
943
+ async getDatabaseSchemaFull(databaseId) {
944
+ const db = await this.fetchDatabaseLegacy(databaseId);
945
+ const properties = db.properties;
946
+ if (!properties) return {};
947
+ const schema = {};
948
+ for (const [name, prop] of Object.entries(properties)) {
949
+ const entry = {
950
+ id: prop.id,
951
+ type: prop.type
952
+ };
953
+ if (prop.type === "select" || prop.type === "multi_select") {
954
+ const typeData = prop[prop.type];
955
+ if (typeData?.options) {
956
+ entry.options = typeData.options.map((o) => ({ name: o.name, color: o.color }));
957
+ }
958
+ }
959
+ if (prop.type === "status") {
960
+ const statusData = prop.status;
961
+ if (statusData?.options) {
962
+ entry.options = statusData.options.map((o) => ({ name: o.name, color: o.color }));
963
+ }
964
+ if (statusData?.groups) {
965
+ entry.groups = statusData.groups.map((g) => ({
966
+ name: g.name,
967
+ color: g.color,
968
+ optionIds: g.option_ids
969
+ }));
970
+ }
971
+ }
972
+ schema[name] = entry;
973
+ }
974
+ return schema;
975
+ }
939
976
  async queryDatabase(databaseId, options) {
940
977
  const dsId = await this.getDataSourceId(databaseId);
941
978
  const response = await this.withRateLimit(
@@ -3142,14 +3179,19 @@ var EXTENSION_TO_MIME = {
3142
3179
  ".tiff": "image/tiff"
3143
3180
  };
3144
3181
  var ImageHandler = class {
3145
- constructor(vaultFs, attachmentFolder = "attachments", notionClient) {
3182
+ constructor(vaultFs, attachmentFolder = "attachments", notionClient, customFetch) {
3146
3183
  this.vaultFs = vaultFs;
3147
3184
  this.attachmentFolder = attachmentFolder;
3148
3185
  this.notionClient = notionClient;
3186
+ this.customFetch = customFetch;
3149
3187
  }
3150
3188
  vaultFs;
3151
3189
  attachmentFolder;
3152
3190
  notionClient;
3191
+ customFetch;
3192
+ get fetchFn() {
3193
+ return this.customFetch ?? globalThis.fetch;
3194
+ }
3153
3195
  async downloadImage(url, pageTitle) {
3154
3196
  const maxRetries = 3;
3155
3197
  let lastError = null;
@@ -3161,7 +3203,7 @@ var ImageHandler = class {
3161
3203
  `[Im-Nobsidian] \uC774\uBBF8\uC9C0 \uB2E4\uC6B4\uB85C\uB4DC \uC7AC\uC2DC\uB3C4 (${attempt + 1}/${maxRetries}): ${pageTitle}`
3162
3204
  );
3163
3205
  }
3164
- const response = await fetch(url);
3206
+ const response = await this.fetchFn(url);
3165
3207
  if (!response.ok) {
3166
3208
  throw new Error(`\uC774\uBBF8\uC9C0 \uB2E4\uC6B4\uB85C\uB4DC \uC2E4\uD328: ${response.status} ${response.statusText}`);
3167
3209
  }
@@ -3404,7 +3446,7 @@ var ImageHandler = class {
3404
3446
  `[Im-Nobsidian] \uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC7AC\uC2DC\uB3C4 (${attempt + 1}/${maxRetries}): ${caption}`
3405
3447
  );
3406
3448
  }
3407
- const response = await fetch(url);
3449
+ const response = await this.fetchFn(url);
3408
3450
  if (!response.ok) {
3409
3451
  throw new Error(`\uD30C\uC77C \uB2E4\uC6B4\uB85C\uB4DC \uC2E4\uD328: ${response.status} ${response.statusText}`);
3410
3452
  }
@@ -3759,6 +3801,168 @@ function sanitizeFileName(name) {
3759
3801
  return sanitized;
3760
3802
  }
3761
3803
 
3804
+ // src/view/base-file-generator.ts
3805
+ var NOTION_TO_BASES_VIEW = {
3806
+ table: "table",
3807
+ gallery: "cards",
3808
+ list: "list",
3809
+ board: "cards",
3810
+ calendar: null,
3811
+ timeline: null,
3812
+ form: null,
3813
+ chart: null,
3814
+ map: null,
3815
+ dashboard: null
3816
+ };
3817
+ var BaseFileGenerator = class {
3818
+ generate(options) {
3819
+ const lines = [];
3820
+ lines.push(`# Auto-generated by Im-Nobsidian from Notion DB: ${options.databaseName}`);
3821
+ lines.push(`# Database ID: ${options.databaseId}`);
3822
+ lines.push("");
3823
+ this.writeFilters(lines, options.folderPath);
3824
+ this.writeFormulas(lines, options.viewsConfig.views);
3825
+ this.writePropertyDisplayNames(lines, options.schema);
3826
+ this.writeViews(lines, options.viewsConfig.views, options.schema);
3827
+ return lines.join("\n");
3828
+ }
3829
+ writeFilters(lines, folderPath) {
3830
+ lines.push("filters:");
3831
+ lines.push(" and:");
3832
+ lines.push(` - file.inFolder("${folderPath}")`);
3833
+ lines.push("");
3834
+ }
3835
+ needsContentCoverFormula(views) {
3836
+ return views.some(
3837
+ (v) => v.type === "gallery" && v.cover && (v.cover.type === "page_content" || v.cover.type === "page_content_first")
3838
+ );
3839
+ }
3840
+ writeFormulas(lines, views) {
3841
+ if (!this.needsContentCoverFormula(views)) return;
3842
+ lines.push("formulas:");
3843
+ lines.push(" coverImage: file.embeds[0]");
3844
+ lines.push("");
3845
+ }
3846
+ writePropertyDisplayNames(lines, schema) {
3847
+ const entries = Object.entries(schema).filter(([, prop]) => prop.type !== "title");
3848
+ if (entries.length === 0) return;
3849
+ lines.push("properties:");
3850
+ for (const [name] of entries) {
3851
+ lines.push(` ${this.yamlKey(name)}:`);
3852
+ lines.push(` displayName: ${this.yamlValue(name)}`);
3853
+ }
3854
+ lines.push("");
3855
+ }
3856
+ writeViews(lines, views, schema) {
3857
+ const basesViews = views.map((v) => this.convertView(v, schema)).filter((v) => v !== null);
3858
+ if (basesViews.length === 0) {
3859
+ lines.push("views:");
3860
+ lines.push(" - type: table");
3861
+ lines.push(" name: Table");
3862
+ return;
3863
+ }
3864
+ lines.push("views:");
3865
+ for (const view of basesViews) {
3866
+ lines.push(` - type: ${view.type}`);
3867
+ lines.push(` name: ${this.yamlValue(view.name)}`);
3868
+ if (view.order && view.order.length > 0) {
3869
+ lines.push(" order:");
3870
+ for (const col of view.order) {
3871
+ lines.push(` - ${col}`);
3872
+ }
3873
+ }
3874
+ if (view.sort && view.sort.length > 0) {
3875
+ lines.push(" sort:");
3876
+ for (const s of view.sort) {
3877
+ lines.push(` - column: ${s.column}`);
3878
+ lines.push(` direction: ${s.direction}`);
3879
+ }
3880
+ }
3881
+ if (view.groupBy) {
3882
+ lines.push(" groupBy:");
3883
+ lines.push(` property: ${view.groupBy.property}`);
3884
+ if (view.groupBy.direction) {
3885
+ lines.push(` direction: ${view.groupBy.direction}`);
3886
+ }
3887
+ }
3888
+ if (view.image) {
3889
+ lines.push(` image: ${view.image}`);
3890
+ }
3891
+ }
3892
+ }
3893
+ convertView(view, schema) {
3894
+ const basesType = NOTION_TO_BASES_VIEW[view.type];
3895
+ if (!basesType) return null;
3896
+ const result = {
3897
+ type: basesType,
3898
+ name: view.name || view.type
3899
+ };
3900
+ if (view.properties && view.properties.length > 0) {
3901
+ const visible = view.properties.filter((p) => p.visible !== false).map((p) => {
3902
+ const name = p.propertyName ?? this.resolvePropertyName(p.propertyId, schema);
3903
+ return name ? this.toNoteRef(name) : null;
3904
+ }).filter((name) => !!name);
3905
+ if (visible.length > 0) {
3906
+ result.order = ["file.name", ...visible];
3907
+ }
3908
+ }
3909
+ if (view.sorts && view.sorts.length > 0) {
3910
+ result.sort = view.sorts.map((s) => {
3911
+ let column;
3912
+ if (s.property) {
3913
+ const propName = this.resolvePropertyName(s.property, schema) ?? s.property;
3914
+ column = this.toNoteRef(propName);
3915
+ } else if (s.timestamp) {
3916
+ column = s.timestamp === "created_time" ? "file.ctime" : "file.mtime";
3917
+ } else {
3918
+ return null;
3919
+ }
3920
+ return {
3921
+ column,
3922
+ direction: s.direction === "ascending" ? "ASC" : "DESC"
3923
+ };
3924
+ }).filter((s) => s !== null);
3925
+ }
3926
+ if (view.groupBy) {
3927
+ const propName = view.groupBy.propertyName ?? this.resolvePropertyName(view.groupBy.propertyId, schema);
3928
+ if (propName) {
3929
+ result.groupBy = {
3930
+ property: this.toNoteRef(propName),
3931
+ direction: view.groupBy.sort === "ascending" ? "ASC" : view.groupBy.sort === "descending" ? "DESC" : void 0
3932
+ };
3933
+ }
3934
+ }
3935
+ if (view.type === "gallery" && view.cover) {
3936
+ if (view.cover.type === "property" && view.cover.propertyId) {
3937
+ const propName = this.resolvePropertyName(view.cover.propertyId, schema);
3938
+ if (propName) result.image = this.toNoteRef(propName);
3939
+ } else if (view.cover.type === "page_cover") {
3940
+ result.image = "note.cover";
3941
+ } else if (view.cover.type === "page_content" || view.cover.type === "page_content_first") {
3942
+ result.image = "formula.coverImage";
3943
+ }
3944
+ }
3945
+ return result;
3946
+ }
3947
+ toNoteRef(propertyName) {
3948
+ return propertyName;
3949
+ }
3950
+ resolvePropertyName(propertyId, schema) {
3951
+ for (const [name, prop] of Object.entries(schema)) {
3952
+ if (prop.id === propertyId) return name;
3953
+ }
3954
+ return void 0;
3955
+ }
3956
+ yamlKey(key) {
3957
+ if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) return key;
3958
+ return `"${key.replace(/"/g, '\\"')}"`;
3959
+ }
3960
+ yamlValue(value) {
3961
+ if (/^[a-zA-Z0-9_-]+$/.test(value)) return value;
3962
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
3963
+ }
3964
+ };
3965
+
3762
3966
  // src/converter/enhanced-md-converter.ts
3763
3967
  var NOTION_CALLOUT_RE = /^::: callout\n([\s\S]*?)\n:::/gm;
3764
3968
  var NOTION_CALLOUT_TAG_RE = /<callout[^>]*>\n?([\s\S]*?)<\/callout>/g;
@@ -4232,6 +4436,7 @@ var DatabaseSyncer = class {
4232
4436
  pipeline;
4233
4437
  imageHandler;
4234
4438
  propertyMapper = new PropertyMapper();
4439
+ baseFileGenerator = new BaseFileGenerator();
4235
4440
  async pullAll() {
4236
4441
  const databases = this.config.notion.databases;
4237
4442
  if (!databases || databases.length === 0) {
@@ -4286,7 +4491,8 @@ var DatabaseSyncer = class {
4286
4491
  const schema = await this.notionClient.getDatabaseSchema(dbConfig.databaseId);
4287
4492
  this.propertyMapper.loadSchema(schema);
4288
4493
  await this.vaultFs.ensureFolder(dbConfig.localFolder);
4289
- await this.pullDatabaseViews(dbConfig);
4494
+ const viewsConfig = await this.pullDatabaseViews(dbConfig);
4495
+ await this.generateBaseFile(dbConfig, viewsConfig);
4290
4496
  const pages = await this.notionClient.queryAllDatabasePages(
4291
4497
  dbConfig.databaseId,
4292
4498
  dbConfig.pullFilter
@@ -4323,7 +4529,7 @@ var DatabaseSyncer = class {
4323
4529
  try {
4324
4530
  const existing = await this.vaultFs.readFile(configPath);
4325
4531
  const parsed = JSON.parse(existing);
4326
- if (parsed[dbConfig.databaseId]) return;
4532
+ if (parsed[dbConfig.databaseId]) return parsed[dbConfig.databaseId];
4327
4533
  } catch {
4328
4534
  }
4329
4535
  }
@@ -4340,8 +4546,33 @@ var DatabaseSyncer = class {
4340
4546
  getLogger().debug(
4341
4547
  `[DB Sync] \uBDF0 \uC124\uC815 ${viewsConfig.views.length}\uAC1C \uC800\uC7A5: ${dbConfig.databaseId}`
4342
4548
  );
4549
+ return viewsConfig;
4343
4550
  } catch (error) {
4344
4551
  getLogger().warn(`[DB Sync] \uBDF0 \uC124\uC815 Pull \uC2E4\uD328 (\uACC4\uC18D \uC9C4\uD589):`, error);
4552
+ return null;
4553
+ }
4554
+ }
4555
+ async generateBaseFile(dbConfig, viewsConfig) {
4556
+ try {
4557
+ const schemaFull = await this.notionClient.getDatabaseSchemaFull(dbConfig.databaseId);
4558
+ const dbName = viewsConfig?.databaseName || await this.notionClient.getDatabaseTitle(dbConfig.databaseId) || dbConfig.localFolder.split("/").pop() || "Database";
4559
+ const baseContent = this.baseFileGenerator.generate({
4560
+ databaseId: dbConfig.databaseId,
4561
+ databaseName: dbName,
4562
+ schema: schemaFull,
4563
+ viewsConfig: viewsConfig ?? {
4564
+ databaseId: dbConfig.databaseId,
4565
+ databaseName: dbName,
4566
+ lastSynced: (/* @__PURE__ */ new Date()).toISOString(),
4567
+ views: [{ id: "default", name: "Table", type: "table" }]
4568
+ },
4569
+ folderPath: dbConfig.localFolder
4570
+ });
4571
+ const basePath = `${dbConfig.localFolder}/${sanitizeFileName(dbName)}.base`;
4572
+ await this.vaultFs.writeFile(basePath, baseContent);
4573
+ getLogger().debug(`[DB Sync] .base \uD30C\uC77C \uC0DD\uC131: ${basePath}`);
4574
+ } catch (error) {
4575
+ getLogger().warn(`[DB Sync] .base \uD30C\uC77C \uC0DD\uC131 \uC2E4\uD328 (\uACC4\uC18D \uC9C4\uD589):`, error);
4345
4576
  }
4346
4577
  }
4347
4578
  async pullDatabasePage(page, dbConfig) {
@@ -4361,7 +4592,7 @@ var DatabaseSyncer = class {
4361
4592
  );
4362
4593
  const localUrlMatch = coverResult.content.match(/!\[cover\]\((.+?)\)/);
4363
4594
  if (localUrlMatch?.[1]) {
4364
- properties.cover = localUrlMatch[1];
4595
+ properties.cover = `[[${localUrlMatch[1]}]]`;
4365
4596
  } else {
4366
4597
  properties.cover = cover.url;
4367
4598
  }
@@ -4533,7 +4764,7 @@ function extractTitleFromPath(filePath) {
4533
4764
 
4534
4765
  // src/sync/orchestrator.ts
4535
4766
  var SyncOrchestrator = class {
4536
- constructor(config, stateDb, notionClient, vaultFs) {
4767
+ constructor(config, stateDb, notionClient, vaultFs, customFetch) {
4537
4768
  this.config = config;
4538
4769
  this.stateDb = stateDb;
4539
4770
  this.notionClient = notionClient;
@@ -4543,7 +4774,12 @@ var SyncOrchestrator = class {
4543
4774
  wikilinkResolver: (text) => stateDb.resolveWikilink(text)
4544
4775
  });
4545
4776
  this.blockConverter = new BlockConverter();
4546
- this.imageHandler = new ImageHandler(vaultFs, config.paths.attachments, notionClient);
4777
+ this.imageHandler = new ImageHandler(
4778
+ vaultFs,
4779
+ config.paths.attachments,
4780
+ notionClient,
4781
+ customFetch
4782
+ );
4547
4783
  this.fileHandler = new FileHandler(vaultFs, notionClient, stateDb);
4548
4784
  this.propertyMapper = new PropertyMapper();
4549
4785
  this.databaseSyncer = new DatabaseSyncer(
@@ -4642,6 +4878,7 @@ var SyncOrchestrator = class {
4642
4878
  const tasks = filtered.map((change) => async () => {
4643
4879
  await sema.acquire();
4644
4880
  try {
4881
+ if (options?.signal?.aborted) return;
4645
4882
  const op = change.type === "created" ? "create" : change.type === "deleted" ? "delete" : "update";
4646
4883
  options?.onProgress?.(++completed, total, { path: change.path, operation: op });
4647
4884
  switch (change.type) {
@@ -4830,6 +5067,7 @@ var SyncOrchestrator = class {
4830
5067
  const tasks = filtered.map((change) => async () => {
4831
5068
  await sema.acquire();
4832
5069
  try {
5070
+ if (options?.signal?.aborted) return;
4833
5071
  let resultPath;
4834
5072
  switch (change.type) {
4835
5073
  case "created": {
@@ -4980,9 +5218,9 @@ var SyncOrchestrator = class {
4980
5218
  async status() {
4981
5219
  const files = await this.vaultFs.listMarkdownFiles();
4982
5220
  const localChanges = this.changeDetector.detectLocalChanges(files);
4983
- const remoteChanges = await this.detectRemoteChanges();
4984
- const conflictRecords = this.stateDb.getByStatus("conflict");
4985
5221
  const lastSyncAt = this.stateDb.getMeta("last_sync_at");
5222
+ const remoteChanges = lastSyncAt ? await this.detectRemoteChangesIncremental(lastSyncAt) : await this.detectRemoteChanges();
5223
+ const conflictRecords = this.stateDb.getByStatus("conflict");
4986
5224
  const conflicts = await this.buildConflictsFromRecords(
4987
5225
  conflictRecords,
4988
5226
  localChanges,
@@ -5338,7 +5576,14 @@ var SyncOrchestrator = class {
5338
5576
  const record = this.stateDb.getByPath(path);
5339
5577
  if (!record?.notionPageId) return;
5340
5578
  if (this.config.sync.deleteSync) {
5341
- await this.notionClient.archivePage(record.notionPageId);
5579
+ try {
5580
+ await this.notionClient.archivePage(record.notionPageId);
5581
+ } catch (error) {
5582
+ const msg = error instanceof Error ? error.message : String(error);
5583
+ if (msg.includes("archived ancestor")) ; else {
5584
+ throw error;
5585
+ }
5586
+ }
5342
5587
  this.stateDb.delete(record.id);
5343
5588
  } else {
5344
5589
  this.stateDb.updateStatus(record.id, "pending");
@@ -5967,7 +6212,7 @@ var NodeVaultFS = class {
5967
6212
  if (this.isExcluded(relativePath)) continue;
5968
6213
  if (entry.isDirectory()) {
5969
6214
  await this.walkDirNonMd(fullPath, result);
5970
- } else if (entry.isFile() && !entry.name.endsWith(".md")) {
6215
+ } else if (entry.isFile() && !entry.name.endsWith(".md") && !entry.name.endsWith(".base")) {
5971
6216
  const fileStat = await stat(fullPath);
5972
6217
  result.push({
5973
6218
  path: relativePath,
@@ -6584,6 +6829,59 @@ function extractGroupName(val) {
6584
6829
  if (typeof val === "object" && "start" in val) return val.start;
6585
6830
  return null;
6586
6831
  }
6832
+ function filterEntries(entries, searchQuery, filters) {
6833
+ let result = entries;
6834
+ if (searchQuery && searchQuery.trim()) {
6835
+ const q = searchQuery.trim().toLowerCase();
6836
+ result = result.filter((entry) => {
6837
+ if (entry.title.toLowerCase().includes(q)) return true;
6838
+ return Object.values(entry.properties).some((val) => {
6839
+ if (val === null || val === void 0) return false;
6840
+ if (typeof val === "string") return val.toLowerCase().includes(q);
6841
+ if (Array.isArray(val)) return val.some((v) => v.toLowerCase().includes(q));
6842
+ if (typeof val === "object" && "start" in val) return val.start.includes(q);
6843
+ return String(val).toLowerCase().includes(q);
6844
+ });
6845
+ });
6846
+ }
6847
+ if (filters && filters.length > 0) {
6848
+ for (const filter of filters) {
6849
+ result = result.filter((entry) => matchFilter(entry, filter));
6850
+ }
6851
+ }
6852
+ return result;
6853
+ }
6854
+ function matchFilter(entry, filter) {
6855
+ const val = filter.property === "title" ? entry.title : entry.properties[filter.property] ?? null;
6856
+ switch (filter.operator) {
6857
+ case "isEmpty":
6858
+ return val === null || val === void 0 || val === "" || Array.isArray(val) && val.length === 0;
6859
+ case "isNotEmpty":
6860
+ return val !== null && val !== void 0 && val !== "" && !(Array.isArray(val) && val.length === 0);
6861
+ case "equals":
6862
+ if (typeof val === "boolean") return val === filter.value;
6863
+ return String(val ?? "") === String(filter.value ?? "");
6864
+ case "contains": {
6865
+ const needle = String(filter.value ?? "").toLowerCase();
6866
+ if (typeof val === "string") return val.toLowerCase().includes(needle);
6867
+ if (Array.isArray(val)) return val.some((v) => v.toLowerCase().includes(needle));
6868
+ return String(val ?? "").toLowerCase().includes(needle);
6869
+ }
6870
+ case "startsWith":
6871
+ return String(val ?? "").startsWith(String(filter.value ?? ""));
6872
+ case "gt":
6873
+ return typeof val === "number" && typeof filter.value === "number" && val > filter.value;
6874
+ case "lt":
6875
+ return typeof val === "number" && typeof filter.value === "number" && val < filter.value;
6876
+ case "between": {
6877
+ if (typeof val !== "number" || typeof filter.value !== "number" || typeof filter.valueTo !== "number")
6878
+ return false;
6879
+ return val >= filter.value && val <= filter.valueTo;
6880
+ }
6881
+ default:
6882
+ return true;
6883
+ }
6884
+ }
6587
6885
  function parseDate(value) {
6588
6886
  const match = /^(\d{4}-\d{2}-\d{2})/.exec(value);
6589
6887
  return match?.[1] ?? null;
@@ -6795,6 +7093,6 @@ ${lines.join("\n")}
6795
7093
  }`;
6796
7094
  }
6797
7095
 
6798
- export { BlockConverter, CalloutRestorer, CalloutTransformer, ChangeDetector, ColorAnnotator, ConfigManager, ConfigSchema, ConflictResolver, ConversionPipeline, DEFAULT_CONFIG, DatabaseSyncer, EmbedResolver, EntryEditor, FileHandler, FileWatcher, FrontmatterExtractor, FrontmatterGenerator, HtmlAnnotationStripper, ImageHandler, InlineDBParser, LocalImageRestorer, MathNormalizer, MentionToWikilink, NodeVaultFS, NotionBlockBuilder, NotionClient, PreserveMarkerCollector, PreserveMarkerInjector, PropertiesTableInjector, PropertiesTableRestorer, PropertyMapper, StateDB, SyncOrchestrator, TreeMapper, UnsupportedBlockStripper, ViewDataProvider, WatchSyncService, WikilinkResolver, computeBufferHash, computeHash, createDefaultPipeline, extractCalendarEntries, filterByMonth, generateColorCSS, generateId, getLogger, getNotionBgColor, getNotionColor, getVisibleProperties, groupEntries, normalizeNotionId, notionIdsEqual, sanitizeFileName, setLogger, sortEntries, threeWayMerge };
7096
+ export { BaseFileGenerator, BlockConverter, CalloutRestorer, CalloutTransformer, ChangeDetector, ColorAnnotator, ConfigManager, ConfigSchema, ConflictResolver, ConversionPipeline, DEFAULT_CONFIG, DatabaseSyncer, EmbedResolver, EntryEditor, FileHandler, FileWatcher, FrontmatterExtractor, FrontmatterGenerator, HtmlAnnotationStripper, ImageHandler, InlineDBParser, LocalImageRestorer, MathNormalizer, MentionToWikilink, NodeVaultFS, NotionBlockBuilder, NotionClient, PreserveMarkerCollector, PreserveMarkerInjector, PropertiesTableInjector, PropertiesTableRestorer, PropertyMapper, StateDB, SyncOrchestrator, TreeMapper, UnsupportedBlockStripper, ViewDataProvider, WatchSyncService, WikilinkResolver, computeBufferHash, computeHash, createDefaultPipeline, extractCalendarEntries, filterByMonth, filterEntries, generateColorCSS, generateId, getLogger, getNotionBgColor, getNotionColor, getVisibleProperties, groupEntries, normalizeNotionId, notionIdsEqual, sanitizeFileName, setLogger, sortEntries, threeWayMerge };
6799
7097
  //# sourceMappingURL=index.js.map
6800
7098
  //# sourceMappingURL=index.js.map