@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.d.ts +99 -8
- package/dist/index.js +313 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|