@im-nobsidian/core 0.14.1 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -31,7 +31,6 @@ declare const ConfigSchema: z.ZodObject<{
31
31
  notion: z.ZodObject<{
32
32
  token: z.ZodString;
33
33
  rootPageId: z.ZodString;
34
- workspaceId: z.ZodOptional<z.ZodString>;
35
34
  parentMode: z.ZodDefault<z.ZodEnum<["page", "database"]>>;
36
35
  databaseId: z.ZodOptional<z.ZodString>;
37
36
  databases: z.ZodDefault<z.ZodArray<z.ZodObject<{
@@ -65,12 +64,10 @@ declare const ConfigSchema: z.ZodObject<{
65
64
  pullFilter?: unknown;
66
65
  }[];
67
66
  databaseId?: string | undefined;
68
- workspaceId?: string | undefined;
69
67
  }, {
70
68
  token: string;
71
69
  rootPageId: string;
72
70
  databaseId?: string | undefined;
73
- workspaceId?: string | undefined;
74
71
  parentMode?: "page" | "database" | undefined;
75
72
  databases?: {
76
73
  databaseId: string;
@@ -82,7 +79,7 @@ declare const ConfigSchema: z.ZodObject<{
82
79
  }>;
83
80
  sync: z.ZodObject<{
84
81
  direction: z.ZodDefault<z.ZodEnum<["push", "pull", "both"]>>;
85
- conflictStrategy: z.ZodDefault<z.ZodEnum<["local-first", "remote-first", "manual", "duplicate"]>>;
82
+ conflictStrategy: z.ZodDefault<z.ZodEnum<["local-first", "remote-first", "manual", "duplicate", "merge"]>>;
86
83
  autoSync: z.ZodDefault<z.ZodBoolean>;
87
84
  autoSyncInterval: z.ZodDefault<z.ZodNumber>;
88
85
  fullReconcileInterval: z.ZodDefault<z.ZodNumber>;
@@ -93,8 +90,8 @@ declare const ConfigSchema: z.ZodObject<{
93
90
  notifications: z.ZodDefault<z.ZodEnum<["silent", "default"]>>;
94
91
  }, "strip", z.ZodTypeAny, {
95
92
  notifications: "silent" | "default";
96
- direction: "push" | "both" | "pull";
97
- conflictStrategy: "manual" | "local-first" | "remote-first" | "duplicate";
93
+ direction: "push" | "pull" | "both";
94
+ conflictStrategy: "local-first" | "remote-first" | "manual" | "duplicate" | "merge";
98
95
  autoSync: boolean;
99
96
  autoSyncInterval: number;
100
97
  fullReconcileInterval: number;
@@ -104,8 +101,8 @@ declare const ConfigSchema: z.ZodObject<{
104
101
  createDatabases: boolean;
105
102
  }, {
106
103
  notifications?: "silent" | "default" | undefined;
107
- direction?: "push" | "both" | "pull" | undefined;
108
- conflictStrategy?: "manual" | "local-first" | "remote-first" | "duplicate" | undefined;
104
+ direction?: "push" | "pull" | "both" | undefined;
105
+ conflictStrategy?: "local-first" | "remote-first" | "manual" | "duplicate" | "merge" | undefined;
109
106
  autoSync?: boolean | undefined;
110
107
  autoSyncInterval?: number | undefined;
111
108
  fullReconcileInterval?: number | undefined;
@@ -117,33 +114,30 @@ declare const ConfigSchema: z.ZodObject<{
117
114
  paths: z.ZodObject<{
118
115
  include: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
119
116
  exclude: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
117
+ excludeObsidianOnly: z.ZodDefault<z.ZodBoolean>;
120
118
  attachments: z.ZodDefault<z.ZodString>;
121
119
  }, "strip", z.ZodTypeAny, {
122
120
  attachments: string;
123
121
  include: string[];
124
122
  exclude: string[];
123
+ excludeObsidianOnly: boolean;
125
124
  }, {
126
125
  attachments?: string | undefined;
127
126
  include?: string[] | undefined;
128
127
  exclude?: string[] | undefined;
128
+ excludeObsidianOnly?: boolean | undefined;
129
129
  }>;
130
130
  conversion: z.ZodObject<{
131
131
  preferMarkdownApi: z.ZodDefault<z.ZodBoolean>;
132
- preserveMarkers: z.ZodDefault<z.ZodBoolean>;
133
- frontmatterMapping: z.ZodDefault<z.ZodBoolean>;
134
132
  imageDownload: z.ZodDefault<z.ZodEnum<["immediate", "lazy", "skip"]>>;
135
133
  timeZone: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
136
134
  }, "strip", z.ZodTypeAny, {
137
135
  preferMarkdownApi: boolean;
138
- preserveMarkers: boolean;
139
- frontmatterMapping: boolean;
140
136
  imageDownload: "immediate" | "lazy" | "skip";
141
137
  timeZone?: string | undefined;
142
138
  }, {
143
139
  timeZone?: string | undefined;
144
140
  preferMarkdownApi?: boolean | undefined;
145
- preserveMarkers?: boolean | undefined;
146
- frontmatterMapping?: boolean | undefined;
147
141
  imageDownload?: "immediate" | "lazy" | "skip" | undefined;
148
142
  }>;
149
143
  advanced: z.ZodObject<{
@@ -202,7 +196,6 @@ declare const ConfigSchema: z.ZodObject<{
202
196
  markdownCompletionMaxBlocks?: number | undefined;
203
197
  }>;
204
198
  }, "strip", z.ZodTypeAny, {
205
- version: 1;
206
199
  notion: {
207
200
  token: string;
208
201
  rootPageId: string;
@@ -215,12 +208,17 @@ declare const ConfigSchema: z.ZodObject<{
215
208
  pullFilter?: unknown;
216
209
  }[];
217
210
  databaseId?: string | undefined;
218
- workspaceId?: string | undefined;
219
211
  };
212
+ conversion: {
213
+ preferMarkdownApi: boolean;
214
+ imageDownload: "immediate" | "lazy" | "skip";
215
+ timeZone?: string | undefined;
216
+ };
217
+ version: 1;
220
218
  sync: {
221
219
  notifications: "silent" | "default";
222
- direction: "push" | "both" | "pull";
223
- conflictStrategy: "manual" | "local-first" | "remote-first" | "duplicate";
220
+ direction: "push" | "pull" | "both";
221
+ conflictStrategy: "local-first" | "remote-first" | "manual" | "duplicate" | "merge";
224
222
  autoSync: boolean;
225
223
  autoSyncInterval: number;
226
224
  fullReconcileInterval: number;
@@ -233,13 +231,7 @@ declare const ConfigSchema: z.ZodObject<{
233
231
  attachments: string;
234
232
  include: string[];
235
233
  exclude: string[];
236
- };
237
- conversion: {
238
- preferMarkdownApi: boolean;
239
- preserveMarkers: boolean;
240
- frontmatterMapping: boolean;
241
- imageDownload: "immediate" | "lazy" | "skip";
242
- timeZone?: string | undefined;
234
+ excludeObsidianOnly: boolean;
243
235
  };
244
236
  advanced: {
245
237
  concurrency: number;
@@ -261,12 +253,10 @@ declare const ConfigSchema: z.ZodObject<{
261
253
  markdownCompletionMaxBlocks: number;
262
254
  };
263
255
  }, {
264
- version: 1;
265
256
  notion: {
266
257
  token: string;
267
258
  rootPageId: string;
268
259
  databaseId?: string | undefined;
269
- workspaceId?: string | undefined;
270
260
  parentMode?: "page" | "database" | undefined;
271
261
  databases?: {
272
262
  databaseId: string;
@@ -276,10 +266,16 @@ declare const ConfigSchema: z.ZodObject<{
276
266
  titleProperty?: string | undefined;
277
267
  }[] | undefined;
278
268
  };
269
+ conversion: {
270
+ timeZone?: string | undefined;
271
+ preferMarkdownApi?: boolean | undefined;
272
+ imageDownload?: "immediate" | "lazy" | "skip" | undefined;
273
+ };
274
+ version: 1;
279
275
  sync: {
280
276
  notifications?: "silent" | "default" | undefined;
281
- direction?: "push" | "both" | "pull" | undefined;
282
- conflictStrategy?: "manual" | "local-first" | "remote-first" | "duplicate" | undefined;
277
+ direction?: "push" | "pull" | "both" | undefined;
278
+ conflictStrategy?: "local-first" | "remote-first" | "manual" | "duplicate" | "merge" | undefined;
283
279
  autoSync?: boolean | undefined;
284
280
  autoSyncInterval?: number | undefined;
285
281
  fullReconcileInterval?: number | undefined;
@@ -292,13 +288,7 @@ declare const ConfigSchema: z.ZodObject<{
292
288
  attachments?: string | undefined;
293
289
  include?: string[] | undefined;
294
290
  exclude?: string[] | undefined;
295
- };
296
- conversion: {
297
- timeZone?: string | undefined;
298
- preferMarkdownApi?: boolean | undefined;
299
- preserveMarkers?: boolean | undefined;
300
- frontmatterMapping?: boolean | undefined;
301
- imageDownload?: "immediate" | "lazy" | "skip" | undefined;
291
+ excludeObsidianOnly?: boolean | undefined;
302
292
  };
303
293
  advanced: {
304
294
  concurrency?: number | undefined;
@@ -327,7 +317,9 @@ type SyncDirection = "push" | "pull" | "both";
327
317
  type FileType = "file" | "folder-note" | "folder-only" | "db-row";
328
318
  type SyncStatus = "synced" | "pending" | "conflict" | "error";
329
319
  type OperationType = "create" | "update" | "delete" | "move";
330
- type ConflictStrategy = "local-first" | "remote-first" | "manual" | "duplicate";
320
+ /** 양쪽이 바뀌었을 때 무엇이 이기나 — 설정 검증(`ConfigSchema`)이 이 목록을 읽는다. */
321
+ declare const CONFLICT_STRATEGIES: readonly ["local-first", "remote-first", "manual", "duplicate", "merge"];
322
+ type ConflictStrategy = (typeof CONFLICT_STRATEGIES)[number];
331
323
  interface SyncRecord {
332
324
  readonly id: string;
333
325
  readonly obsidianPath: string;
@@ -423,6 +415,7 @@ interface ProgressItem {
423
415
  * 받아 봤지만 볼트에 쓰지 않았다(pull) — 바뀐 것이 없거나 로컬을 지켰다. 진행 수에는 들지만 화면이 바뀐
424
416
  * 노트로 적지 않는다. 다시 그리기(B14)는
425
417
  * 받아 둔 노트를 모두 받아 보므로, 적으면 바뀌지 않은 노트마다 「updated」 줄이 찍혔다.
418
+ * push 는 보낼 것이 없던 고침 — 읽기 전용 속성만 고친 행.
426
419
  */
427
420
  readonly unchanged?: boolean;
428
421
  }
@@ -514,7 +507,9 @@ interface ViewEdit {
514
507
  readonly view: string;
515
508
  /** 이름을 바꿨으면 옛 이름. */
516
509
  readonly from?: string;
517
- /** 올린 것 — 이름 · 열 · 정렬 · 필터. */
510
+ /** 볼트에서 더해 Notion 에 만든 보기 · 지워 Notion 에서 지운 보기. 없으면 고친 보기. */
511
+ readonly action?: "created" | "deleted";
512
+ /** 올린 것 — 이름 · 열 · 정렬 · 필터. 만들고 지운 보기는 비었다. */
518
513
  readonly changed: readonly ("name" | "columns" | "sort" | "filter")[];
519
514
  }
520
515
  /** 고친 사이드카 하나가 Notion DB 에 한 일 — {@link PushResult.schemaEdits}. */
@@ -530,10 +525,11 @@ interface SchemaEdit {
530
525
  /** 설정(수식 · 숫자 형식 · 옵션)을 바꾼 속성. */
531
526
  readonly redefined: readonly string[];
532
527
  /**
533
- * 지운 선택 옵션 — 속성 이름 → 옵션 이름. Notion 은 그 옵션을 가진 행의 값을 비운다(옵션 이름을 바꾼 것도 지우고
534
- * 새로 만든 것이다). 없으면 지운 옵션이 없다.
528
+ * 지운 선택 옵션 — 속성 이름 → 옵션 이름. Notion 은 그 옵션을 가진 행의 값을 비운다. 없으면 지운 옵션이 없다.
535
529
  */
536
530
  readonly droppedOptions?: ReadonlyArray<readonly [string, readonly string[]]>;
531
+ /** 이름을 바꾼 선택 옵션 — 속성 이름 · 옛 이름 · 새 이름. 그 값을 가진 Notion 행도 새 이름으로 옮긴다. */
532
+ readonly renamedOptions?: ReadonlyArray<readonly [string, string, string]>;
537
533
  }
538
534
  /** 볼트에서 바꾼 DB 속성 이름 하나 — {@link PushResult.renamedProperties}. */
539
535
  interface PropertyRename {
@@ -608,12 +604,27 @@ interface PullResult {
608
604
  readonly restored: number;
609
605
  /** 되살린(dry-run 은 되살릴) 노트 · 행의 경로 — {@link restored} 의 목록. 없으면 생략. */
610
606
  readonly restoredPaths?: readonly string[];
607
+ /**
608
+ * 양쪽이 다른 줄을 고쳐 받은 원격에 로컬 편집을 합친 노트 · 행(`sync.conflictStrategy: "merge"`) — {@link updated} 에도 센다.
609
+ * 합친 글은 아직 Notion 에 없다 — 이어지는 push(`sync` 는 같은 실행)가 올린다. 없으면 생략.
610
+ */
611
+ readonly mergedPaths?: readonly string[];
612
+ /**
613
+ * 상태 기록에 없던 같은 자리의 노트 · 행을 그 Notion 페이지와 다시 이은 것(P7) — 상태 DB 를 잃었거나 처음 잇는 볼트.
614
+ * 새로 받은 것({@link created})에 세지 않는다. 글이 달라 충돌로 이은 것은 {@link conflicts} 에도 든다. 없으면 생략.
615
+ */
616
+ readonly relinkedPaths?: readonly string[];
617
+ /**
618
+ * dry-run 만 — 상태 기록에 Notion 과 이은 노트가 없어 실제 pull 은 같은 자리의 노트를 먼저 다시 잇는다(P7). 미리 보기는
619
+ * 노트 글을 받아 견주지 않아 그 노트들도 {@link created} 로 센다. 이을 노트가 없으면 생략.
620
+ */
621
+ readonly relinkPending?: true;
611
622
  /**
612
623
  * 볼트에서 고쳐 덮어쓰지 않은 사이드카(`.notion.json`) — push 하면 고친 속성을 Notion 에 올린다(ADR-045). 없으면 생략.
613
624
  */
614
625
  readonly heldSidecars?: readonly string[];
615
626
  /**
616
- * 볼트에서 보기를 고쳐 덮어쓰지 않은 `.base` — push 하면 고친 보기 이름 · 열 · 정렬 · 필터를 Notion 에 올린다(ADR-046).
627
+ * 볼트에서 보기를 고쳐 덮어쓰지 않은 `.base` — push 하면 고친 보기 이름 · 열 · 정렬 · 필터와 더하고 지운 보기를 Notion 에 올린다(ADR-046).
617
628
  * 없으면 생략.
618
629
  */
619
630
  readonly heldBases?: readonly string[];
@@ -632,7 +643,7 @@ interface PullResult {
632
643
  readonly moved?: readonly RemoteMove[];
633
644
  /** Notion 에서 옮겼지만 볼트에서 옮기지 않은 것과 그 까닭. */
634
645
  readonly moveSkipped?: readonly RemoteMoveSkip[];
635
- /** 옮기거나 이름을 바꾼 노트를 가리키던 링크를 고친 노트 — 없으면 고친 것이 없다. */
646
+ /** 옮기거나 이름을 바꾼 노트를 가리키던 링크를 고친 노트 — 없으면 고친 것이 없다. 이 연결이 보지 않는 노트는 볼트 맨 위 기준 경로다. */
636
647
  readonly relinked?: readonly string[];
637
648
  /**
638
649
  * Notion 에 새로 생겼지만 동기화에서 뺀 자리(paths · `.im-nobsidian-ignore`)에 놓일 것이라 받지 않은 페이지 —
@@ -720,6 +731,14 @@ interface ChildTag {
720
731
  readonly tag: string;
721
732
  }
722
733
 
734
+ /** push 가 앵커 링크를 풀 때 쓰는 것 — 쓰기 전에 대상 페이지의 블록을 읽어 둔다(변환은 기다리지 않는다). */
735
+ interface AnchorLookup {
736
+ /** 올리는 노트의 페이지 — `[[#제목]]` 의 대상. 아직 만들지 않았으면 null. */
737
+ readonly selfPageId: string | null;
738
+ /** 그 페이지에서 앵커가 가리키는 블록 — 못 찾았으면 null. */
739
+ blockOf(pageId: string, anchor: string): string | null;
740
+ }
741
+
723
742
  type ConversionPath = "markdown-api" | "block-api";
724
743
  interface ProcessorInput {
725
744
  readonly content: string;
@@ -765,6 +784,8 @@ interface ConversionContext {
765
784
  readonly path: ConversionPath;
766
785
  readonly filePath: string;
767
786
  readonly parentMode?: "page" | "database";
787
+ /** push — 제목 · 블록으로 가는 위키링크를 Notion 블록 링크로 풀 때 쓴다(미리 읽은 대상 페이지의 블록). */
788
+ readonly anchors?: AnchorLookup;
768
789
  }
769
790
  interface Processor {
770
791
  readonly name: string;
@@ -951,6 +972,11 @@ interface IStateDB {
951
972
  /** 닫는다 — 파일에 남은 쓰기를 마쳐야 하는 구현(플러그인의 sql.js)은 그 일을 Promise 로 돌려준다. */
952
973
  close(): void | Promise<void>;
953
974
  getByPath(path: string): SyncRecord | null;
975
+ /**
976
+ * 대소문자를 가리지 않고 같은 경로의 기록들 — 받을 이름이 macOS · Windows 에서 다른 노트의 파일과 겹치는지(P9).
977
+ * SQLite 의 `NOCASE` 라 ASCII 만 접는다. 경로는 NFC 로 적혀 있다(`upgradeNfcPaths`).
978
+ */
979
+ getByPathKey(path: string): SyncRecord[];
954
980
  getByNotionId(pageId: string): SyncRecord | null;
955
981
  getByStatus(status: SyncStatus): SyncRecord[];
956
982
  getAll(): SyncRecord[];
@@ -994,7 +1020,13 @@ interface IStateDB {
994
1020
  declare class StateDB implements IStateDB {
995
1021
  private readonly lock;
996
1022
  private readonly db;
1023
+ /**
1024
+ * 준비한 문장 — SQL 글자마다 한 번만 준비한다. 노트마다 여러 번 부르는 조회(`getByPath` 등)가 부를 때마다 다시
1025
+ * 준비하면 5,000 노트 첫 push 에서 준비만 3초였다(P10 실측). 스키마가 바뀌면 SQLite 가 다시 준비한다.
1026
+ */
1027
+ private readonly statements;
997
1028
  private constructor();
1029
+ private sql;
998
1030
  /**
999
1031
  * 상태 DB 파일을 연다 — 없으면 새로 만든다. 한 볼트의 상태 DB 는 한 곳만 연다 — 플러그인이나 다른 CLI 가 쓰는
1000
1032
  * 중이면 {@link StateDbLockedError} 를 던진다(ADR-026). 저장된 파일이 비었거나 잘렸으면 빈 DB 로 열지 않고
@@ -1022,6 +1054,7 @@ declare class StateDB implements IStateDB {
1022
1054
  /** 닫고 잠금을 푼다 — 닫는 사이 다른 곳이 열지 않게 닫은 뒤에 푼다. */
1023
1055
  close(): void;
1024
1056
  getByPath(path: string): SyncRecord | null;
1057
+ getByPathKey(path: string): SyncRecord[];
1025
1058
  getByNotionId(pageId: string): SyncRecord | null;
1026
1059
  getByStatus(status: SyncStatus): SyncRecord[];
1027
1060
  getAll(): SyncRecord[];
@@ -1176,6 +1209,11 @@ declare const SAVED_STATE_TABLES_QUERY = "SELECT 1 FROM sqlite_master WHERE type
1176
1209
  * 예전 조회(`LIKE '%/노트.md'`)는 슬래시가 앞에 있어야 맞아서 볼트 맨 위 노트와 경로 붙은 링크를 못 찾았다 —
1177
1210
  * 제목이 파일 이름과 다른 노트(파일 이름에 못 쓰는 글자를 바꾼 노트)로 가는 링크가 Notion 에서 글로 남았다.
1178
1211
  * - LIKE 의 `%` · `_` 는 글자로 견준다. 예전에는 `a_b` 가 `a-b.md` 에도 맞았다.
1212
+ * - 링크 글자는 NFC 로 견준다 — 볼트 경로 · 제목이 NFC 다. macOS 에서 붙여 넣은 NFD 글자도 같은 노트로 간다.
1213
+ * - 끝으로 대소문자를 가리지 않고 한 번 더 — Obsidian 은 `[[note]]` 를 `Note.md` 로 잇는다. SQLite 의 `NOCASE` 는
1214
+ * ASCII 만 접는다.
1215
+ * - 별칭과 경로 꼬리(`%/노트.md`)는 무늬가 `%` 로 시작해 색인을 못 쓴다 — 어디에도 없는 링크(아직 올리지 않은 노트로 가는
1216
+ * 링크)는 그 둘에서 표를 훑는다. 5,000 노트 첫 push 에서 1초 남짓이다(P10 실측) — Notion 요청 시간에 견주면 작다.
1179
1217
  */
1180
1218
  interface WikilinkLookup {
1181
1219
  readonly sql: string;
@@ -1523,6 +1561,8 @@ interface DatabaseMeta {
1523
1561
  readonly parentPageId?: string | null;
1524
1562
  /** DB 의 아이콘 · 커버 · 설명 · 제목 표시 — 받은 그대로. */
1525
1563
  readonly appearance?: DatabaseAppearance;
1564
+ /** 휴지통에 있다 — 링크드 뷰 블록을 지우면 컨테이너가 이렇게 남는다. 아니면 없다. */
1565
+ readonly inTrash?: true;
1526
1566
  }
1527
1567
  /** DB 자체의 꾸밈 — 행이 아니라 DB 의 것이다. 값은 Notion 이 준 그대로(`icon` · `cover` 는 페이지와 같은 꼴). */
1528
1568
  interface DatabaseAppearance {
@@ -1981,7 +2021,13 @@ declare class NotionClient {
1981
2021
  */
1982
2022
  setWikilinkResolver(resolver: WikilinkResolver$1): void;
1983
2023
  extractProperties(page: PageObjectResponse): Record<string, unknown>;
1984
- private lastRequestTime;
2024
+ /**
2025
+ * 다음 요청이 나갈 수 있는 가장 이른 시각(epoch ms). 요청마다 이 자리를 «먼저 잡고» 기다린다 — 동시 칸
2026
+ * (`concurrency`)이 여럿이어도 시작 간격이 `minRequestInterval` 아래로 내려가지 않는다. 예전에는 칸마다 마지막 요청
2027
+ * 시각을 같이 읽고 같이 잔 뒤 한꺼번에 나가, 350ms 간격(초당 약 3회)이 실제로는 초당 8회 남짓이 되어 큰 볼트의 첫
2028
+ * push 가 429 를 거듭 맞았다(P10 실측 — 1,000 노트에서 Retry-After 40초).
2029
+ */
2030
+ private nextRequestAt;
1985
2031
  /**
1986
2032
  * 429 이후 **클라이언트 전체**가 쉬어야 하는 시각(epoch ms).
1987
2033
  *
@@ -2019,6 +2065,22 @@ declare class NotionClient {
2019
2065
  private waitForTurn;
2020
2066
  }
2021
2067
 
2068
+ /** Notion 에 닿는지 확인한 결과 — 읽은 것과 읽지 못한 까닭을 사람이 읽는 줄로. */
2069
+ interface NotionAccessCheck {
2070
+ readonly ok: boolean;
2071
+ readonly lines: readonly string[];
2072
+ }
2073
+ /** 무엇을 확인하나 — 루트 페이지, DB 모드면 그 DB. 빈 값은 건너뛴다. */
2074
+ interface NotionAccessTarget {
2075
+ readonly rootPageId: string;
2076
+ readonly databaseId?: string;
2077
+ }
2078
+ /**
2079
+ * 토큰이 맞는지, 루트 페이지(DB 모드면 DB)를 읽을 수 있는지 Notion 에 묻는다 — 첫 동기화에서야 알던 것을 미리.
2080
+ * 아무것도 쓰지 않는다. 쓰기 권한은 쓰지 않고는 알 수 없어 확인하지 않는다.
2081
+ */
2082
+ declare function checkNotionAccess(client: NotionClient, target: NotionAccessTarget): Promise<NotionAccessCheck>;
2083
+
2022
2084
  interface RichTextSegment {
2023
2085
  content: string;
2024
2086
  bold?: boolean;
@@ -2394,7 +2456,7 @@ declare function isRemoteDeletion(conflict: Conflict): boolean;
2394
2456
  declare function applicableChoices(conflict: Conflict): readonly ResolutionChoice[];
2395
2457
  /**
2396
2458
  * 전략이 이 충돌에 고르는 것. 원격에서 지운 노트는 복제할 원격이 없어 duplicate 도 «로컬 유지» —
2397
- * 둘 다 잃는 것이 없다. manual 은 자동 병합인데 지운 원격과는 병합할 수 없어 던진다.
2459
+ * 둘 다 잃는 것이 없다. manual · merge 는 자동 병합인데 지운 원격과는 병합할 수 없어 던진다.
2398
2460
  */
2399
2461
  declare function choiceForStrategy(conflict: Conflict, strategy: ConflictStrategy): ResolutionChoice;
2400
2462
  interface ResolutionResult {
@@ -2437,6 +2499,14 @@ declare class ConflictResolver {
2437
2499
  generateDiff(conflict: Conflict): string;
2438
2500
  }
2439
2501
 
2502
+ /** 볼트 전체 — 이 연결이 보지 않는 노트의 링크도 고칠 때({@link LinkUpdater}). */
2503
+ interface OutsideVault {
2504
+ /** 볼트 맨 위 기준의 VaultFS — 연결 폴더 · 경로 패턴으로 좁히지 않은 것. */
2505
+ readonly fs: VaultFS;
2506
+ /** 이 연결의 폴더(볼트 맨 위 기준). 볼트 맨 위면 `""`. */
2507
+ readonly folder: string;
2508
+ }
2509
+
2440
2510
  interface BaseFileOptions {
2441
2511
  readonly databaseId: string;
2442
2512
  readonly databaseName: string;
@@ -2671,6 +2741,16 @@ interface FolderDatabaseReport extends FolderDatabaseDraft {
2671
2741
  readonly pagesToRows: number;
2672
2742
  }
2673
2743
 
2744
+ /** 사용자가 만든 `.base` 의 폴더 필터가 옮긴 폴더를 가리킨다 — 묻고 고친다. */
2745
+ interface UserBaseFilterFix {
2746
+ /** `.base` 경로. */
2747
+ readonly path: string;
2748
+ /** 필터가 가리키는 옛 폴더. */
2749
+ readonly from: string;
2750
+ /** 그 폴더의 새 자리. */
2751
+ readonly to: string;
2752
+ }
2753
+
2674
2754
  /**
2675
2755
  * 한 오케스트레이터의 작업은 한 번에 하나만 돈다(S-09).
2676
2756
  *
@@ -2685,7 +2765,7 @@ interface FolderDatabaseReport extends FolderDatabaseDraft {
2685
2765
  * 긴 sync(실볼트 pull 500초) 동안 주기 sync 가 쌓인다.
2686
2766
  */
2687
2767
  /** 잠그는 작업 — 볼트 · 상태 DB · 원격을 바꾸거나 이번 실행의 기준을 정하는 것. */
2688
- type GatedOperation = "push" | "pull" | "sync" | "status" | "fetch" | "resolve" | "discard" | "prepare-database";
2768
+ type GatedOperation = "push" | "pull" | "sync" | "status" | "fetch" | "resolve" | "discard" | "prepare-database" | "base-filters" | "verify";
2689
2769
  declare function operationLabel(operation: GatedOperation): string;
2690
2770
  declare class SyncBusyError extends Error {
2691
2771
  /** 이미 도는 작업. */
@@ -2732,7 +2812,9 @@ declare class SyncOrchestrator {
2732
2812
  private readonly inspector;
2733
2813
  private readonly recovery;
2734
2814
  private readonly gate;
2735
- constructor(config: Config, stateDb: IStateDB, notionClient: NotionClient, vaultFs: VaultFS, customFetch?: typeof globalThis.fetch);
2815
+ constructor(config: Config, stateDb: IStateDB, notionClient: NotionClient, vaultFs: VaultFS, customFetch?: typeof globalThis.fetch,
2816
+ /** 볼트 전체 — 이 연결이 보지 않는 노트에서도 옮긴 노트로 가는 링크를 고친다(연결 폴더 · 경로 패턴). */
2817
+ outside?: OutsideVault);
2736
2818
  /** 도는 작업 — 없으면 null(S-09). 부른 쪽이 겹칠 요청을 미리 거를 때 쓴다. */
2737
2819
  get runningOperation(): GatedOperation | null;
2738
2820
  push(options?: PushOptions): Promise<PushResult>;
@@ -2741,6 +2823,24 @@ declare class SyncOrchestrator {
2741
2823
  * 목록에 없으므로, 그대로 돌리면 「볼트에서 지움」 으로 보고 Notion 페이지를 지우거나 되살리려 한다.
2742
2824
  */
2743
2825
  private assertConnectionScope;
2826
+ /**
2827
+ * 예전 CLI 가 적은 NFD 경로를 NFC 로 옮겨 적는다 — 한 번만(`upgradeNfcPaths`). dry-run · status 도 먼저 한다: 상태 기록의
2828
+ * 표기만 고치고 볼트 · Notion 은 그대로다. 안 고치면 그 노트를 지울 것 · 새로 만들 것으로 보인다.
2829
+ */
2830
+ private alignStatePaths;
2831
+ /**
2832
+ * 볼트의 첨부(노트가 아닌 파일)를 폴더 페이지에 올린다(`sync.syncFiles`). 올리지 못한 첨부는 `failed` 에 담는다. 올릴 노트가
2833
+ * 있든 없든 push 마다 부른다 — 바뀌지 않은 첨부는 파일 기록이 건너뛴다.
2834
+ */
2835
+ private pushVaultFiles;
2836
+ /**
2837
+ * @param mergedByPull sync dry-run 만 — 앞선 pull dry-run 이 합칠 노트. 실제 sync 는 합친 뒤 원격을 본 것으로
2838
+ * 적어 push 가 올린다 — dry-run 은 받지 않아 원격이 바뀐 그대로라, 원격을 보고 거절하지 않는다.
2839
+ */
2840
+ /**
2841
+ * @param relinkedByPull 같은 sync 의 dry-run pull 이 다시 이을 것이라고 미리 봤다 — 실제 sync 는 받으며 먼저 잇고 올리므로
2842
+ * 상태 기록이 비었어도 막지 않는다({@link assertVaultLinked}).
2843
+ */
2744
2844
  private executePush;
2745
2845
  /**
2746
2846
  * 볼트에서 지운 이 노트를 Notion 에서 지우지 않아 다음 pull 이 되살리나 — deleteSync 가 꺼져 있고 pull 이
@@ -2773,6 +2873,11 @@ declare class SyncOrchestrator {
2773
2873
  */
2774
2874
  status(options?: StatusOptions): Promise<StatusResult>;
2775
2875
  private executeStatus;
2876
+ /**
2877
+ * 다음 pull 이 Notion 에서 바꾼 제목으로 이름을 바꿀 행 — 바꾸지 않고 본다. 행 이름은 DB 받기가 바꾸므로
2878
+ * 페이지 이름 바꾸기({@link followRemoteRenames})에 없다. 판정은 받기와 같다(`retitledRowTarget`).
2879
+ */
2880
+ private previewRowRenames;
2776
2881
  /**
2777
2882
  * 로컬만 본다 — 원격 기준을 정하지 않아 도는 작업과 겹쳐도 된다. 변경은 push 가 쓰는 판정 그대로다
2778
2883
  * (옮긴 노트 · 폴더 포함). 상태 DB 는 바꾸지 않는다.
@@ -2787,6 +2892,10 @@ declare class SyncOrchestrator {
2787
2892
  recordLocalRename(from: string, to: string, kind: RenameKind): void;
2788
2893
  /** 볼트에서 지운 노트 · 폴더 — 그 자리를 새 경로로 적은 힌트를 버린다. */
2789
2894
  recordLocalDelete(path: string): void;
2895
+ /**
2896
+ * 토큰 · 루트 페이지(DB 모드면 DB)를 읽을 수 있는지 Notion 에 묻는다 — 아무것도 쓰지 않아 동기화와 겹쳐도 된다.
2897
+ */
2898
+ checkNotionAccess(): Promise<NotionAccessCheck>;
2790
2899
  /**
2791
2900
  * 볼트 완결성 검증 — 원격에 있는 것이 볼트에 빠짐없이 있는지 대조한다(R11-B · R12-C).
2792
2901
  *
@@ -2803,6 +2912,7 @@ declare class SyncOrchestrator {
2803
2912
  * 열거와 맞대 봐야 의미가 있다.
2804
2913
  */
2805
2914
  verifyCompleteness(): Promise<VaultCompletenessReport>;
2915
+ private executeVerifyCompleteness;
2806
2916
  fetch(): Promise<{
2807
2917
  newPages: number;
2808
2918
  deletedPages: number;
@@ -2839,6 +2949,12 @@ declare class SyncOrchestrator {
2839
2949
  * 않는다. 되돌릴 원본이 없는 것은 이유와 함께 거절한다.
2840
2950
  */
2841
2951
  discardLocalChange(path: string): Promise<void>;
2952
+ /**
2953
+ * 동기화가 옮긴 폴더를 가리키는 사용자 `.base` 의 폴더 필터 — 말없이 고치지 않고 고칠지 묻는다. 없으면 빈 목록.
2954
+ */
2955
+ userBaseFilterFixes(): UserBaseFilterFix[];
2956
+ /** {@link userBaseFilterFixes} 를 물은 답대로 — 고치면 고친 `.base` 경로. 어느 쪽이든 다시 묻지 않는다. */
2957
+ resolveUserBaseFilterFixes(accept: boolean): Promise<string[]>;
2842
2958
  /**
2843
2959
  * 볼트에서 만든 노트 폴더를 Notion DB 로 올릴 준비 — frontmatter · `.base` 로 사이드카를 써 둔다(#75).
2844
2960
  * Notion 에는 쓰지 않는다. 다음 push 가 DB 를 만들고 노트를 행으로 올린다(ADR-036 · ADR-037).
@@ -2853,11 +2969,31 @@ declare class SyncOrchestrator {
2853
2969
  interface PathFilterConfig {
2854
2970
  readonly include?: string[];
2855
2971
  readonly exclude?: string[];
2972
+ /**
2973
+ * Obsidian 에서만 쓰는 것(Canvas · Excalidraw · 템플릿 폴더)도 뺀다 — `true` 일 때만. 볼트를 여는 쪽(CLI · 플러그인)이
2974
+ * `obsidianOnlyExcludes` 로 패턴을 더한다.
2975
+ */
2976
+ readonly excludeObsidianOnly?: boolean;
2856
2977
  }
2978
+ /**
2979
+ * 볼트 경로는 NFC 다 — Obsidian 이 디스크의 NFD 이름(macOS Finder 가 만든 한글 이름 등)을 NFC 로 보이는 것과 같다
2980
+ * (2026-10-31 실측: Obsidian 1.12.4 의 `TFile.path` 는 NFC, NFD · NFC 어느 경로로도 읽힘). 예전 CLI 는 디스크 이름을
2981
+ * 그대로 써서 `[[회의록]]` 이 NFD 이름의 노트를 찾지 못했고, Notion 제목도 NFD 로 올렸다.
2982
+ */
2857
2983
  declare class NodeVaultFS implements VaultFS {
2858
2984
  private readonly rootPath;
2859
2985
  private readonly filter;
2860
- constructor(rootPath: string, pathConfig?: PathFilterConfig);
2986
+ /**
2987
+ * NFC 볼트 경로 → 디스크의 상대 경로 — ASCII 가 아닌 이름(파일 · 폴더)만. 걸을 때 · 처음 열 때 채운다. 새로 만드는 이름은
2988
+ * NFC 로 쓴다.
2989
+ * Linux 는 두 꼴을 다른 이름으로 보므로 NFC 경로를 그대로 열면 NFD 파일 옆에 새 파일이 생긴다.
2990
+ */
2991
+ private readonly diskPaths;
2992
+ /**
2993
+ * @param ignoreFile 폴더의 `.im-nobsidian-ignore` 를 따른다 — 볼트 전체를 보는 쪽(다른 연결의 노트에서 링크를 고칠 때)은
2994
+ * 그 폴더를 맡은 연결의 제외 목록을 따르지 않는다.
2995
+ */
2996
+ constructor(rootPath: string, pathConfig?: PathFilterConfig, ignoreFile?: boolean);
2861
2997
  excludesPath(path: string, kind?: "file" | "folder"): boolean;
2862
2998
  private loadImNobsidianIgnore;
2863
2999
  readFile(path: string): Promise<string>;
@@ -2874,8 +3010,23 @@ declare class NodeVaultFS implements VaultFS {
2874
3010
  listMarkdownFileStats(): Promise<FileStatInfo[]>;
2875
3011
  getFileStat(path: string): Promise<FileStatInfo | null>;
2876
3012
  listNonMarkdownFiles(): Promise<NonMdFileInfo[]>;
2877
- /** 볼트 경로 — Windows 의 `relative()` 는 `\` 로 잇는다. 상태 DB · 패턴 · Notion 경로는 모두 `/` 다. */
2878
- private vaultPath;
3013
+ /**
3014
+ * 한 폴더의 항목과 그 볼트 경로 — 숨김(`.`)은 뺀다. 경로는 `/` 로 잇고(Windows 의 `\\` 가 아니라 — 상태 DB · 패턴 ·
3015
+ * Notion 경로는 모두 `/`), NFD 이름은 NFC 로 보이며 디스크 이름을 적어 둔다.
3016
+ *
3017
+ * 같은 폴더에 NFC 꼴의 이름이 따로 있으면(Linux 에서만 둘 다 있을 수 있다) NFC 경로는 그것의 것이고 NFD 쪽은 디스크
3018
+ * 이름 그대로 — 하나로 접으면 한쪽 노트가 보이지 않고 다른 쪽 파일을 읽는다. 걷는 차례와 무관하게 같은 답이 나온다.
3019
+ */
3020
+ private entriesOf;
3021
+ private full;
3022
+ /**
3023
+ * 볼트 경로의 디스크 이름 — 위 폴더부터 같은 규칙으로. 걸으며 본 이름이면 그것. 아니면(걷기 전에 부른 이름) 디스크에
3024
+ * 그 꼴이 없고 NFC 로 같은 다른 꼴이 있을 때 그것을 쓴다 — Linux 는 두 꼴을 다른 이름으로 보아, 그대로 쓰면 NFD 파일
3025
+ * 옆에 새 파일이 생긴다. ASCII 이름은 보지 않는다.
3026
+ */
3027
+ private onDisk;
3028
+ /** 지운 것 아래의 디스크 이름을 잊는다. */
3029
+ private forget;
2879
3030
  private walkDirNonMd;
2880
3031
  private walkDirStats;
2881
3032
  private walkDir;
@@ -2999,8 +3150,16 @@ declare class ImageHandler {
2999
3150
  *
3000
3151
  * @param pageId 본문을 받은 페이지 — 그 페이지에 올린 것만 되찾는다
3001
3152
  * @param notePath 노트 경로 — 옛 캡션의 파일을 push 와 같은 사다리로 찾는다
3153
+ * @param adoptFrom 상태 기록에 없던 같은 자리의 노트 글(P7 다시 잇기) — {@link adoptLocalEmbed}
3154
+ */
3155
+ restoreUploadedMedia(markdown: string, pageId?: string, notePath?: string, adoptFrom?: string): Promise<string>;
3156
+ /**
3157
+ * 상태 DB 를 잃고 다시 잇는 노트(P7, ADR-049)의 미디어 — 올린 미디어 기록도 함께 잃어, push 가 올린 그림을 사본으로 받아
3158
+ * 노트가 달라졌다(실측: `![[img/blue.png]]` → `![[attachments/blue-<해시>.png]]` 로 충돌). 받은 미디어의 이름과 바이트가
3159
+ * 노트가 가리키는 볼트 파일과 같으면 그 임베드로 되살리고 받은 것으로 적는다 — 다음 push 가 그 블록을 둔다. 바이트를
3160
+ * 견주므로 Notion 에서 같은 이름의 다른 파일로 바꾼 것은 되살리지 않는다. 받지 못하거나 다르면 null — 사본을 받는다.
3002
3161
  */
3003
- restoreUploadedMedia(markdown: string, pageId?: string, notePath?: string): Promise<string>;
3162
+ private adoptLocalEmbed;
3004
3163
  /** 적어 둔 업로드면 되살릴 임베드 대상. 볼트에서 그 파일이 사라졌으면 null — 사본을 받는다. */
3005
3164
  private knownEmbedTarget;
3006
3165
  /** 미디어 URL 이 가리키는 파일 이름 — 서명 URL 은 경로 끝, 내부 참조는 `attachment:` 뒤. */
@@ -3185,6 +3344,8 @@ declare class FileHandler {
3185
3344
  * 호출이 늘어나는 **합성 경로**라 전체로는 여전히 무한대다. 상한을 넘긴 첨부는 경고만
3186
3345
  * 남기고 나머지 첨부는 계속 올린다 — 첨부 하나가 push 전체를 멎게 하지 않는다.
3187
3346
  *
3347
+ * @param failed 실패를 결과로 알릴 곳 — 있으면 실패를 여기 담고 경고 로그는 내지 않는다(화면이 결과로 알린다. 둘 다
3348
+ * 내면 같은 말이 두 번 나온다). 없으면 경고 로그로만 남는다.
3188
3349
  * @returns 업로드 결과. 변경 없음(스킵)이거나 실패했으면 null.
3189
3350
  */
3190
3351
  private pushSingleFile;
@@ -3200,7 +3361,13 @@ declare class FileHandler {
3200
3361
  * 때마다 같은 요청을 다시 보내 같은 이유로 실패했다(실볼트 `.ipynb` 22개).
3201
3362
  */
3202
3363
  private listUploadableFiles;
3203
- pushAllFiles(): Promise<FileUploadResult[]>;
3364
+ /**
3365
+ * 볼트의 첨부를 폴더 페이지마다 올린다.
3366
+ *
3367
+ * @param failed 올리지 못한 첨부를 담을 곳 — push 결과의 `failed` 를 넘기면 CLI · 플러그인이 처리하지 못한 것으로
3368
+ * 보인다. 예전엔 경고 로그로만 남아 push 가 「실패 0」 으로 끝났다.
3369
+ */
3370
+ pushAllFiles(failed?: FailedOperation[]): Promise<FileUploadResult[]>;
3204
3371
  downloadFileBlock(url: string, filename: string, targetFolder: string): Promise<FileDownloadResult>;
3205
3372
  downloadFileBlocks(blocks: Array<{
3206
3373
  type: string;
@@ -3245,6 +3412,8 @@ interface BaseViewRecord {
3245
3412
  readonly lossyFilter?: true;
3246
3413
  /** 그때 Notion 보기의 지문({@link viewFingerprint}) — 그 사이 Notion 에서도 고쳤는지 가른다. */
3247
3414
  readonly notion: string;
3415
+ /** 이 보기에서 올리지 않는 값의 지문({@link viewRestOf}). 예전 기록에는 없다. */
3416
+ readonly rest?: string;
3248
3417
  }
3249
3418
  interface BasesSort {
3250
3419
  readonly property: string;
@@ -3266,6 +3435,16 @@ interface DbBaseFile {
3266
3435
  readonly views?: readonly BaseViewRecord[];
3267
3436
  /** 올리지 않는 나머지의 지문(`restSignature`) — 같아야 고친 것을 모두 올린 것이다. */
3268
3437
  readonly rest?: string;
3438
+ /**
3439
+ * 보기 말고의 키의 지문(`docRestOf`) — 보기를 더하거나 지운 `.base` 는 {@link rest} 로 견줄 수 없어 보기마다의
3440
+ * 지문(`BaseViewRecord.rest`)과 이것으로 견준다. 예전 기록에는 없다.
3441
+ */
3442
+ readonly docRest?: string;
3443
+ /**
3444
+ * 링크드 뷰 컨테이너의 `.base` 면 행을 가진 원본 DB(줄인 id) — 원본 DB 폴더에 놓이고 그 폴더를 가리킨다. 원본의
3445
+ * 옛 이름 산출물을 치울 때 지우지 않고, push 가 이 `.base` 임베드를 컨테이너 블록으로 되돌린다.
3446
+ */
3447
+ readonly linkedTo?: string;
3269
3448
  }
3270
3449
  /**
3271
3450
  * DB 마다 실제로 기록한 `.base` 경로와 DB 제목 — 인라인 DB placeholder 를 `.base` 임베드로 바꿀 때
@@ -3286,6 +3465,12 @@ declare class DbBaseFiles {
3286
3465
  /** 기록한 DB 모두 — 키는 줄인 DB id. */
3287
3466
  all(): Array<[string, DbBaseFile]>;
3288
3467
  set(databaseId: string, info: DbBaseFile): void;
3468
+ /** 기록을 지운다 — Notion 에서 지운 링크드 뷰. */
3469
+ delete(databaseId: string): void;
3470
+ /** 이 DB 를 원본으로 둔 링크드 뷰의 `.base` 경로. */
3471
+ linkedBasesOf(databaseId: string): string[];
3472
+ /** 이 경로에 쓴 링크드 뷰 컨테이너(줄인 id) — 없으면 null. */
3473
+ linkedContainerAt(basePath: string): string | null;
3289
3474
  /** 상태 메타에서 읽는다 — 값이 그대로면 읽어 둔 것을 쓴다. 없거나 깨졌으면 비어 있다 — 이번 실행이 기록하는 것부터 다시 쌓는다. */
3290
3475
  private load;
3291
3476
  }
@@ -3397,7 +3582,19 @@ interface PlannedRow {
3397
3582
  readonly restore?: boolean;
3398
3583
  /** Notion 에서 DB 안으로 옮긴 페이지가 행이 되며 옮길 것 — 노트와 하위 페이지 폴더 · 옮긴 DB 의 폴더(ADR-047). */
3399
3584
  readonly moves?: readonly RemoteMove[];
3585
+ /** 로컬도 고친 행을 실제 pull 이 받지 않는 까닭 — 없으면 받는다. */
3586
+ readonly resolution?: PlannedResolution;
3400
3587
  }
3588
+ /**
3589
+ * 로컬도 고친 노트를 실제 pull 이 어떻게 처리하나 — 충돌로 남김 · 합침(merge) · 받지 않음(원격이 그대로거나
3590
+ * local-first). dry-run 이 미리 알린다.
3591
+ */
3592
+ type PlannedResolution = {
3593
+ readonly action: "conflict";
3594
+ readonly conflict: Conflict;
3595
+ } | {
3596
+ readonly action: "merge" | "skip";
3597
+ };
3401
3598
  /**
3402
3599
  * 행을 받는 진행 — 진행 표시가 페이지와 행을 한 목록 · 한 수로 보이게 한다. 행은 DB 를 조회해야 몇
3403
3600
  * 개인지 알아, 받기 전에 이 DB 에서 받을 행 수를 `planned` 로 알리고 행 하나를 마칠 때마다 `done` 을
@@ -3440,6 +3637,19 @@ declare class DatabaseSyncer {
3440
3637
  private renamedRows;
3441
3638
  /** 볼트에서 사라져 되살린 행의 경로 — pull 마감이 가져가 화면에 알린다(D8). */
3442
3639
  private restoredRows;
3640
+ /** 쓰다 끊긴 행을 알아본다 — {@link UpdateJournal}. */
3641
+ private readonly journal;
3642
+ /** merge 전략이 받은 행에 로컬 편집을 합친 행 — {@link takeMergedRows}. */
3643
+ private mergedRows;
3644
+ /** 상태 기록에 없던 같은 자리의 행 노트를 다시 이은 것(P7) — {@link takeRelinkedRows}. */
3645
+ private relinkedRows;
3646
+ /**
3647
+ * 이번 pull 을 시작할 때 Notion 과 이은 노트가 하나도 없었다 — 그때는 자연 이름에 있는 행 노트의 글이 달라도 다시
3648
+ * 잇는다({@link relinkExistingRow}). 오케스트레이터가 pull 을 시작할 때 정한다({@link beginPull}).
3649
+ */
3650
+ private unlinkedVault;
3651
+ /** 이번 pull 에서 다시 이으려고 고른 행 노트 경로 — 같은 이름의 두 행이 한 노트를 고르지 않게. */
3652
+ private readonly relinkClaims;
3443
3653
  /** Notion 에서 바뀐 속성을 행 노트에 옮긴 것 — pull 마감이 가져가 화면에 알린다(ADR-045). */
3444
3654
  private schemaFollowed;
3445
3655
  /** pull 이 마지막으로 쓴 사이드카 — 볼트에서 고친 것은 덮어쓰지 않는다(ADR-045). */
@@ -3448,6 +3658,10 @@ declare class DatabaseSyncer {
3448
3658
  private heldSidecars;
3449
3659
  /** 이번 pull 이 볼트에서 고친 것이라 덮어쓰지 않은 `.base` 경로(ADR-046). */
3450
3660
  private heldBases;
3661
+ /** 이번 pull 이 치운 링크드 뷰의 `.base`({@link takeRetiredBases}). */
3662
+ private readonly retiredBases;
3663
+ /** 이번 실행에서 받은 DB(줄인 id)의 기간 날짜 짝 키 — 그 DB 를 원본으로 둔 링크드 뷰의 `.base` 도 같게 쓴다. */
3664
+ private readonly rangeEnds;
3451
3665
  /**
3452
3666
  * 실제로 기록한 .base 경로/DB 제목 — placeholder 임베드 재작성(F22)의 SSOT. 이번 pull 이 조회하지
3453
3667
  * 않은 DB 의 것도 남아 있다({@link DbBaseFiles}).
@@ -3526,6 +3740,22 @@ declare class DatabaseSyncer {
3526
3740
  */
3527
3741
  movingInVault?: ReadonlySet<string>;
3528
3742
  }): Promise<PlannedRow[]>;
3743
+ /**
3744
+ * 받은 행이 지난 사본 그대로인가 — 렌더한 글이 달라도 받을 것이 없으면 그 사이 로컬 편집을 충돌로 올리지 않는다
3745
+ * (N-05). 본문은 지문으로, 본문 밖은 지난 사본의 속성과 견준다. 이 도구가 이 행을 쓰다 끊긴 원격도 받을 것이
3746
+ * 없다 — push 가 마저 올린다({@link UpdateJournal}).
3747
+ */
3748
+ private rowRemoteUnchanged;
3749
+ /**
3750
+ * dry-run 이 알릴, 로컬도 고친 행을 실제 pull 이 어떻게 처리할지 — 받은 행과 견주는 판정은 실제 pull 과 같다.
3751
+ * 첨부를 내려받지 않고 렌더하며 상태 DB 를 바꾸지 않는다. 로컬을 고치지 않았거나 읽지 못하면 null(받는다).
3752
+ */
3753
+ private previewRowResolution;
3754
+ /**
3755
+ * 수정 시각 · 편집자로 가르지 못한 행이 지난 사본 그대로인가 — 본문 지문과 본문 밖 속성으로({@link rowRemoteUnchanged}).
3756
+ * dry-run 이 실제 pull 처럼 받을 것이 없는 행을 세지 않게. 견줄 사본 · 지문이 없거나 본문을 읽지 못하면 아니다.
3757
+ */
3758
+ private unverifiedRowUnchanged;
3529
3759
  private planRows;
3530
3760
  /**
3531
3761
  * 이 DB 에서 볼 행을 조회한다. 범위(`paths`)가 이 DB 폴더에 닿지 않으면 조회하지 않는다 — 예전에는
@@ -3637,6 +3867,26 @@ declare class DatabaseSyncer {
3637
3867
  */
3638
3868
  private appearanceOf;
3639
3869
  private readAppearance;
3870
+ /**
3871
+ * 링크드 뷰 컨테이너의 `.base` 를 그 컨테이너의 보기(이름 · 필터 · 정렬)로 원본 DB 폴더에 쓴다. 행은 원본 DB 가
3872
+ * 갖는다(F25) — 폴더 필터도 원본 폴더를 가리킨다. 예전에는 링크드 뷰를 원본의 `.base` 로 몰아, 링크드 뷰가 고른
3873
+ * 보기가 볼트에 오지 않았다.
3874
+ *
3875
+ * 이름은 Notion 이 그 블록 위에 보이는 것처럼 「원본 제목 - 첫 보기 이름」 이다. 컨테이너 제목은 비어 온다.
3876
+ *
3877
+ * @returns `gone` — Notion 에서 컨테이너를 지웠다. 쓴 `.base` 를 치웠으니 부른 쪽이 연결을 잊는다.
3878
+ * `failed` — 읽지 못했다. 쓴 `.base` 는 그대로 두고 다음 pull 이 다시 본다.
3879
+ */
3880
+ pullLinkedView(containerId: string, owner: DatabaseSyncConfig): Promise<"written" | "gone" | "failed">;
3881
+ /** 링크드 뷰 `.base` 의 이름 — 같은 폴더의 다른 `.base` 가 쓰는 이름이면 컨테이너 id 앞 네 자리를 붙인다. */
3882
+ private linkedBaseName;
3883
+ /** Notion 에서 지운 링크드 뷰 — 쓴 `.base` 를 치우고 기록을 잊는다. */
3884
+ private retireLinkedView;
3885
+ /**
3886
+ * pull 이 쓴 그대로인 링크드 뷰 `.base` 를 지운다 — 볼트에서 고쳤으면 두고 알린다.
3887
+ * @returns 지웠나.
3888
+ */
3889
+ private removeLinkedBase;
3640
3890
  /** 볼트에서 고친 `.base` 를 덮어쓰거나 지우지 않았다고 한 번 알린다. */
3641
3891
  private warnEditedBase;
3642
3892
  /**
@@ -3676,9 +3926,12 @@ declare class DatabaseSyncer {
3676
3926
  * @param options.localPath 로컬 노트가 지금 있는 자리 — 코드 펜스 표기를 되살리는 근거(S-20).
3677
3927
  * 다른 폴더로 옮기기 전이면 옛 경로다. 기본은 `filePath`.
3678
3928
  */
3679
- renderRow(page: PageObjectResponse, filePath: string, options?: {
3929
+ renderRow(page: PageObjectResponse, filePath: string,
3930
+ /** `adoptFrom` — 다시 잇는 행 노트의 글(P7). 받은 미디어가 노트의 볼트 파일과 같으면 그 임베드로 되살린다. */
3931
+ options?: {
3680
3932
  downloadMedia?: boolean;
3681
3933
  localPath?: string;
3934
+ adoptFrom?: string;
3682
3935
  }): Promise<{
3683
3936
  content: string;
3684
3937
  title: string;
@@ -3708,6 +3961,23 @@ declare class DatabaseSyncer {
3708
3961
  private rowPathOwners;
3709
3962
  /** 되살린 행의 경로를 가져가고 비운다. */
3710
3963
  takeRestoredRows(): string[];
3964
+ /** pull 을 시작한다 — 이은 노트가 하나도 없는 볼트인지 적고 다시 잇기 장부를 비운다. */
3965
+ beginPull(unlinkedVault: boolean): void;
3966
+ /** 이번 받기에서 다시 이은 행의 경로를 가져가고 비운다. */
3967
+ takeRelinkedRows(): string[];
3968
+ /**
3969
+ * 상태 기록에 없는 행 노트가 이 행이 놓일 자리에 이미 있다 — 이 행 id 를 단 이름이 먼저, 그 다음 자연 이름. 페이지의
3970
+ * `claimExistingNote` 와 같은 규칙이다.
3971
+ */
3972
+ private claimExistingRow;
3973
+ /**
3974
+ * 상태 기록에 없던 행 노트를 이 행과 다시 잇는다(P7) — 페이지의 `relinkExistingNote` 와 같은 규칙. 글이 같으면 잇고, 다르면
3975
+ * 이 행 id 를 단 이름은 충돌 전략을 따르고 · 자연 이름은 이은 노트가 없는 볼트에서만 충돌로 잇는다. 잇지 않으면 null.
3976
+ * remote-first 는 `"write"` — 호출측이 받은 행으로 덮는다.
3977
+ */
3978
+ private relinkExistingRow;
3979
+ /** 이번 받기에서 로컬 편집을 합친 행의 경로를 가져가고 비운다. */
3980
+ takeMergedRows(): string[];
3711
3981
  /**
3712
3982
  * Notion 에서 다른 페이지 아래로 옮긴 DB 의 폴더를 볼트에서도 옮긴다 — 옮겼으면 그 이동. 옮기지 못하면 까닭을 남기고
3713
3983
  * 옛 자리에서 받는다.
@@ -3718,19 +3988,31 @@ declare class DatabaseSyncer {
3718
3988
  /** 볼트에서 옮기고 아직 올리지 않았나 — 이동 WAL, 또는 dry-run 이 옮겨 적지 않은 이번 이동. */
3719
3989
  private movedInVault;
3720
3990
  /**
3721
- * Notion 에서 다른 페이지 아래로 옮긴 발견 DB 의 폴더를 옮길 곳(ADR-047) — 제자리면 null.
3991
+ * Notion 에서 다른 페이지 아래로 옮기거나 이름을 바꾼 발견 DB 의 폴더를 옮길 곳(ADR-047 · {@link retitledFolderName})
3992
+ * — 제자리면 null.
3722
3993
  *
3723
3994
  * Notion 에서 DB 를 옮겨도 DB · 행의 수정 시각이 그대로라 받은 DB 의 부모로만 안다 — 전체 대조는 모든 DB 를 받으니
3724
3995
  * 거기서 보인다. 새 자리는 처음 발견할 때와 같다 — 부모 페이지의 하위 폴더 이름 그대로, 루트면 `databases` 선반.
3725
3996
  * 맨 위 폴더도 루트 아래로 본다(볼트에서 옮긴 DB 를 push 가 루트 아래에 둔다 — {@link DatabaseMover}).
3726
3997
  * 다음은 옮기지 않는다.
3727
- * - 부모가 블록(토글 · 열) 안 · 볼트가 모르는 페이지 — 볼트에 그 자리가 없다
3998
+ * - 부모가 블록(토글 · 열) 안 · 볼트가 모르는 페이지 — 볼트에 그 자리가 없다(이름만 따른다)
3728
3999
  * - 볼트에서 옮긴 DB 폴더 · 부모 노트를 아직 올리지 않았다 — 볼트가 먼저다(push 가 Notion 을 옮긴다)
3729
4000
  */
3730
4001
  private placementMoveOf;
4002
+ /**
4003
+ * Notion 에서 바꾼 DB 제목을 따른 폴더 이름(`sync.renameOnTitleChange`) — 바꿀 것이 없으면 null.
4004
+ *
4005
+ * 지난번에 받은 제목({@link DbBaseFiles})과 달라졌고, 폴더 이름이 그 옛 제목을 따르고 있을 때만 — 폴더를 만든 규칙
4006
+ * (`databaseFolderName`) 이나 `.base` 이름 규칙(`sanitizeFileName`, 볼트에서 바꿔 올린 이름) 그대로일 때다. 사용자가
4007
+ * 따로 정한 이름이면 두고, 새 이름도 지금 이름과 같은 규칙으로 짓는다. 같은 이름 DB 와 가르려 붙인 ` (id 조각)` 은
4008
+ * 떼고 견준다(F24) — 새 자리에서 다시 가른다.
4009
+ */
4010
+ private retitledFolderName;
3731
4011
  /** 이 폴더가 받는 DB — 설정한 DB 와 발견한 DB 에서. */
3732
4012
  private databaseAt;
3733
4013
  /** 이름을 바꾼 행을 가져가고 비운다. */
4014
+ /** 이번 pull 이 Notion 에서 지운 링크드 뷰라 치운 `.base` — 그것을 넣은 노트의 임베드를 뺀다({@link LinkUpdater.dropEmbeds}). */
4015
+ takeRetiredBases(): string[];
3734
4016
  takeRenamedRows(): {
3735
4017
  renamed: RemoteMove[];
3736
4018
  applied: RemoteMove[];
@@ -3740,6 +4022,17 @@ declare class DatabaseSyncer {
3740
4022
  * 든다. 추적하는 노트가 없으면 null.
3741
4023
  */
3742
4024
  private adoptedChildrenOf;
4025
+ /**
4026
+ * Notion 에서 바꾼 제목으로 행 이름을 바꿀 자리(`sync.renameOnTitleChange`) — 바꿀 것이 없으면 null.
4027
+ * 받기 · pull dry-run · status 가 같은 판정을 쓴다. 행의 하위 페이지 폴더(`행/`)도 새 이름으로 옮기며, 옮길 수
4028
+ * 없으면 이름을 바꾸지 않는다(예전처럼 제목만 받는다) — 그 까닭을 돌려준다.
4029
+ */
4030
+ retitledRowTarget(localFolder: string, record: SyncRecord, page: PageObjectResponse): Promise<{
4031
+ to: string;
4032
+ children: RemoteMove | null;
4033
+ } | {
4034
+ reason: string;
4035
+ } | null>;
3743
4036
  private pullDatabasePage;
3744
4037
  }
3745
4038
 
@@ -3756,6 +4049,11 @@ declare class WikilinkResolver implements Processor {
3756
4049
  readonly order = 20;
3757
4050
  constructor(resolve?: WikilinkResolverFn | undefined);
3758
4051
  process(input: ProcessorInput): ProcessorOutput;
4052
+ /**
4053
+ * `[[노트#제목]]` · `[[노트#^블록]]` · `[[#제목]]` → `[글자](https://www.notion.so/<페이지>#<블록>)`. 글자는 별칭,
4054
+ * 없으면 Obsidian 이 보이는 「노트 > 제목」 — pull 이 그 글자면 별칭을 붙이지 않는다. 대상 페이지 · 블록을 못 찾으면 null.
4055
+ */
4056
+ private anchorLink;
3759
4057
  }
3760
4058
 
3761
4059
  declare class CalloutTransformer implements Processor {
@@ -4346,9 +4644,14 @@ declare function notionIdsEqual(a: string, b: string): boolean;
4346
4644
  * markdown-api 경로(convertPageMentions)가 동일 형태로 수렴하도록 한다(rank20/I3).
4347
4645
  */
4348
4646
  declare function compactNotionId(id: string): string;
4647
+ /** 페이지 · DB 를 여는 주소 — 하이픈을 뗀 id 를 붙인다. */
4648
+ declare function notionPageUrl(id: string): string;
4349
4649
  declare function shortNotionId(id: string): string;
4350
4650
 
4351
- /** Notion 제목 → 볼트 파일 이름(확장자 없이). */
4651
+ /**
4652
+ * Notion 제목 → 볼트 파일 이름(확장자 없이). NFC 로 — 볼트 경로는 NFC 다(`NodeVaultFS`). macOS 에서 NFD 이름으로 올린
4653
+ * 제목도 같은 파일 이름이 된다.
4654
+ */
4352
4655
  declare function sanitizeFileName(name: string): string;
4353
4656
 
4354
4657
  /** 노트(마크다운 파일)의 경로 · 이름인가. */
@@ -4425,6 +4728,35 @@ declare function parseIgnorePatterns(content: string): string[];
4425
4728
  /** 운영체제 구분자로 이은 상대 경로 → 볼트 경로(`/`). `relative()` 의 결과에 쓴다. */
4426
4729
  declare function toVaultPath(relativePath: string, separator: string): string;
4427
4730
 
4731
+ /**
4732
+ * Obsidian 에서만 쓰는 것 — 기본으로 동기화하지 않는다(`paths.excludeObsidianOnly`, D10).
4733
+ *
4734
+ * - Canvas(`.canvas`) · Excalidraw(`.excalidraw.md` · `.excalidraw`) 는 JSON 이다. 노트로 올리면 Notion 에 수천 줄의 JSON 이
4735
+ * 생기고, 첨부로 올리면 Notion 에서 열 수 없는 파일 블록이 된다. Notion 에 그 그림을 그릴 곳이 없다.
4736
+ * - 템플릿 폴더의 노트는 `{{date}}` · `<% tp.date.now() %>` 같은 자리 표시를 품은 틀이다 — Notion 에 올려도 쓸 곳이 없고
4737
+ * Notion 의 페이지 목록만 어지럽힌다. 폴더는 Obsidian 의 설정에서 읽는다(코어 「템플릿」 · Templater).
4738
+ *
4739
+ * 이미 동기화한 노트를 빼도 Notion 페이지는 지우지 않는다 — 제외한 노트는 「볼트에서 지움」 으로 보지 않는다.
4740
+ */
4741
+ declare const OBSIDIAN_ONLY_PATTERNS: readonly string[];
4742
+ /** 템플릿 폴더를 적는 Obsidian 설정 — Obsidian 설정 폴더(`.obsidian`) 기준 파일과 그 키. */
4743
+ declare const TEMPLATE_FOLDER_SETTINGS: ReadonlyArray<{
4744
+ readonly file: string;
4745
+ readonly key: string;
4746
+ }>;
4747
+ /**
4748
+ * 설정 파일의 글에서 템플릿 폴더(볼트 기준)를 읽는다. 없거나 깨졌거나 비었으면 뺀다 — 폴더를 정하지 않은 템플릿은 볼트
4749
+ * 맨 위를 가리키지 않는다(Obsidian 은 고르지 않은 것으로 본다).
4750
+ *
4751
+ * @param contents `TEMPLATE_FOLDER_SETTINGS` 의 파일 → 글(없으면 null)
4752
+ */
4753
+ declare function templateFolders(contents: (file: string) => string | null): string[];
4754
+ /**
4755
+ * 이 연결 폴더(볼트 맨 위면 `""`)의 제외 패턴 — 템플릿 폴더는 연결 폴더 기준으로 옮긴다. 연결 밖의 템플릿 폴더는 뺀다. 연결
4756
+ * 폴더가 템플릿 폴더이거나 그 안이면 템플릿 폴더를 빼지 않는다 — 그 폴더를 일부러 연결한 것이다.
4757
+ */
4758
+ declare function obsidianOnlyExcludes(templates: readonly string[], folder: string): string[];
4759
+
4428
4760
  /** 줄 비교의 한 줄. 번호는 1부터 — 더한 줄은 옛 번호가, 지운 줄은 새 번호가 없다. */
4429
4761
  interface DiffLine {
4430
4762
  readonly kind: "same" | "added" | "removed";
@@ -4507,6 +4839,15 @@ declare class FilteredVaultFS implements VaultFS {
4507
4839
  getFileStat(path: string): Promise<FileStatInfo | null>;
4508
4840
  }
4509
4841
 
4842
+ /**
4843
+ * 상태 기록에 Notion 페이지와 이은 노트가 하나도 없는데, 새로 만들 노트가 Notion 에 이미 있는 페이지 · 행과 이름이 겹친다 —
4844
+ * 상태 DB 를 잃었거나 처음 잇는 볼트다. 이대로 push 하면 그 노트들을 새 페이지로 또 만든다.
4845
+ */
4846
+ declare class UnlinkedVaultError extends Error {
4847
+ readonly clashes: readonly string[];
4848
+ constructor(clashes: readonly string[]);
4849
+ }
4850
+
4510
4851
  /**
4511
4852
  * 볼트 하나에 연결 여럿 (ADR-038) — 연결마다 볼트 안의 폴더 하나를 맡는다.
4512
4853
  *
@@ -4617,6 +4958,8 @@ declare const DB_VIEWS_PATH = ".im-nobsidian/db-views.json";
4617
4958
  declare const STATE_DB_PATH = ".im-nobsidian/sync.db";
4618
4959
  /** 파일 감시에서 제외할 내부 디렉터리 glob. */
4619
4960
  declare const INTERNAL_DIR_GLOB = "**/.im-nobsidian/**";
4961
+ /** DB 사이드카 파일 확장자 — `<DB 이름>.notion.json`. */
4962
+ declare const SIDECAR_SUFFIX = ".notion.json";
4620
4963
  /** Obsidian 설정 폴더 기본 이름(볼트 맨 위). 사용자가 바꿀 수 있어 플러그인은 `vault.configDir` 를 쓴다. */
4621
4964
  declare const OBSIDIAN_CONFIG_DIR = ".obsidian";
4622
4965
  /**
@@ -4753,4 +5096,4 @@ declare function readColumnLayout(lines: readonly string[]): (ColumnPlace | unde
4753
5096
  /** 열 이름표 — `열 2/3 · 50%`. 비율이 없으면 `열 2/3`. */
4754
5097
  declare function columnLabel(place: ColumnPlace): string;
4755
5098
 
4756
- export { BaseFileGenerator, type BaseFileOptions, type BasePropertyOption, type BasePropertySchema, type BaseStatusGroup, type BaseSyncOptions, type BasesFilterNode, type BasesViewMapping, type BasesViewType, BlankLineCollapser, type BookmarkTarget, CONFIG_FILE, type CalendarEntry, type CalloutDesign, CalloutRestorer, CalloutTransformer, ChangeDetector, type ChangeDiff, ColorAnnotator, type ColumnPlace, type CompletenessFailure, type CompletenessLocalSource, type CompletenessOptions, type CompletenessRemoteSource, type CompletenessReport, type Config, ConfigManager, ConfigSchema, type Conflict, ConflictResolver, type ConflictStrategy, ConnectionBoundaryError, ConnectionScopeError, type ConversionContext, type ConversionPath, ConversionPipeline, type ConversionResult, type CoverConfig, type DBEntry, DB_VIEWS_FILE, DB_VIEWS_PATH, DEFAULT_CONFIG, DEFAULT_TITLE_PROPERTY, DEFAULT_WATCH_DEBOUNCE_MS, DIFF_SIGN, type DatabaseCompleteness, type DatabaseMove, type DatabaseSyncConfig, type DatabaseSyncResult, DatabaseSyncer, type DatabaseViewsConfig, type DeferredCode, type DegradeNote, type DesignColor, type DesignLine, type DesignSegment, type DiffHunk, type DiffLine, EmbedResolver, EntryEditor, type FailedOperation, type FidelityClassification, type FidelityContext, type FidelityDefect, type FidelityDefectForm, type FidelitySummary, type FileDownloadResult, FileHandler, type FileInfo, type FileRegistryEntry, type FileStatInfo, type FileSystemEntry, type FileType, type FileUploadResult, FileWatcher, type FilterCondition, FilteredVaultFS, type FolderDatabaseReport, type FolderMoveChange, FrontmatterExtractor, FrontmatterGenerator, type FullScanReason, GITIGNORE_ENTRY, type GatedOperation, type GroupByConfig, type GroupedEntries, IGNORE_FILE, INTERNAL_DIR, INTERNAL_DIR_GLOB, type IStateDB, type ImageDownloadResult, ImageHandler, type ImageReference, type InferredProperty, InlineAnnotationPreserver, InlineDBParser, type InlineStyle, type LineDiffOptions, type LineRange, type LocalChange, LocalImageRestorer, type LocalMoveAdoption, type LocalScan, type LocalScanOptions, type Logger, MARKER_BRAND, type MappingResult, type MappingType, MathNormalizer, MentionToWikilink, type MergeConflictRegion, type MergeResult, NOTION_COLOR_NAMES, NOTION_TOKEN_PREFIX, NOTION_TO_BASES_VIEW, type NestedFolderPage, type NestedFolderRecord, NodeVaultFS, type NonMdFileInfo, type NotionBlock, NotionBlockBuilder, NotionClient, type NotionClientOptions, type NotionColor, type NotionPageNode, type NotionRichText, type RichTextItem as NotionRichTextItem, type NotionSidecar, OBSIDIAN_CONFIG_DIR, type OperationType, type PageCompletenessRemoteSource, type PageCompletenessReport, type PageCover, type PageCreationPlan, type PageIcon, PathFilter, type PathFilterConfig, type PendingOperation, PendingWalError, type PlacementChange, type PlannedRow, type PreserveMarker, PreserveMarkerCollector, PreserveMarkerInjector, type Processor, type ProcessorInput, type ProcessorMetadata, type ProcessorOutput, type ProgressCallback, type ProgressItem, PropertiesTableInjector, PropertiesTableRestorer, PropertyMapper, type PropertyOption, type PropertyRename, type PropertySchema, type PropertyValue, type PullOptions, type PullResult, type PushOptions, type PushResult, RENDER_LINE_RULES, type ReadOnlySkip, type RecordPendingInput, type RegisterFileInput, type RemoteChange, type RemoteMove, type RemoteMoveSkip, type RemoteObservation, type RemoteScanInfo, type RenameHints, type RenameKind, type RenderFinding, type RenderLineRule, type ResolutionChoice, type ResolutionResult, type RichTextSegment, type RowProgress, SAVED_STATE_TABLES_QUERY, SEPARATOR_BODY, STATE_DB_FILE, STATE_DB_MIGRATIONS, STATE_DB_PATH, SavedStateDbError, type SchemaEdit, type SchemaFollowed, ScopedVaultFS, SidecarGenerator, type SidecarProperty, type SidecarView, StateDB, StateDbLockedError, type StateDbMigration, type StateDbTool, StateDbUnavailableError, StateLock, type StateLockClaim, type StateLockOwner, type StatusOptions, type StatusResult, type StyledRange, SyncBusyError, type SyncDirection, type SyncOptions, SyncOrchestrator, type SyncRecord, type SyncResult, type SyncStatus, type TableLineDesign, type TranslationResult, TreeMapper, UnsupportedBlockStripper, type UpsertSyncRecord, type VaultCompletenessReport, type VaultFS, type ViewConfig, ViewDataProvider, type ViewEdit, type ViewPropertyConfig, type ViewRenderData, type ViewType, WIKILINK_LOOKUPS, type WatchSyncOptions, type WatchSyncScope, WatchSyncService, type WikilinkEntry, type WikilinkLookup, WikilinkResolver, applicableChoices, assertNoPendingWal, basesViewMappingOf, basesViewTypeOf, choiceForStrategy, classifyBodyFidelity, columnLabel, compactNotionId, computeBufferHash, computeHash, configDirFrom, connectionFolderOf, createDefaultPipeline, extractCalendarEntries, filterByMonth, filterEntries, findConnectionFolders, findNestedFolderPages, formatUnifiedDiff, generateColorCSS, generateId, getLogger, getNotionBgColor, getNotionColor, getVisibleProperties, groupEntries, hasColumnLayout, hasDesignMarker, inAnyPathScope, isHeadingLine, isHeadingMarkerLine, isInternalPath, isMarkdownPath, isRemoteDeletion, lineDiff, lintRenderedMarkdown, matchesPathScope, normalizeNotionId, normalizeVaultPath, noteNameFromPath, notionIdFromInput, notionIdsEqual, operationLabel, parseDesignColor, parseIgnorePatterns, pendingWalBytes, readColumnLayout, readDesignLine, resolvePropertyName, sanitizeFileName, sectionLinesWithHeadingMarkers, setLogger, shortNotionId, sortEntries, stateDbLockPath, stateDbWalPath, stripMarkdownExtension, summarizeFidelity, systemTimeZone, threeWayMerge, toVaultPath, translateNotionFilter, verifyDatabaseCompleteness, verifyPageCompleteness, wikilinkLookupsIn };
5099
+ export { BaseFileGenerator, type BaseFileOptions, type BasePropertyOption, type BasePropertySchema, type BaseStatusGroup, type BaseSyncOptions, type BasesFilterNode, type BasesViewMapping, type BasesViewType, BlankLineCollapser, type BookmarkTarget, CONFIG_FILE, CONFLICT_STRATEGIES, type CalendarEntry, type CalloutDesign, CalloutRestorer, CalloutTransformer, ChangeDetector, type ChangeDiff, ColorAnnotator, type ColumnPlace, type CompletenessFailure, type CompletenessLocalSource, type CompletenessOptions, type CompletenessRemoteSource, type CompletenessReport, type Config, ConfigManager, ConfigSchema, type Conflict, ConflictResolver, type ConflictStrategy, ConnectionBoundaryError, ConnectionScopeError, type ConversionContext, type ConversionPath, ConversionPipeline, type ConversionResult, type CoverConfig, type DBEntry, DB_VIEWS_FILE, DB_VIEWS_PATH, DEFAULT_CONFIG, DEFAULT_TITLE_PROPERTY, DEFAULT_WATCH_DEBOUNCE_MS, DIFF_SIGN, type DatabaseCompleteness, type DatabaseMove, type DatabaseSyncConfig, type DatabaseSyncResult, DatabaseSyncer, type DatabaseViewsConfig, type DeferredCode, type DegradeNote, type DesignColor, type DesignLine, type DesignSegment, type DiffHunk, type DiffLine, EmbedResolver, EntryEditor, type FailedOperation, type FidelityClassification, type FidelityContext, type FidelityDefect, type FidelityDefectForm, type FidelitySummary, type FileDownloadResult, FileHandler, type FileInfo, type FileRegistryEntry, type FileStatInfo, type FileSystemEntry, type FileType, type FileUploadResult, FileWatcher, type FilterCondition, FilteredVaultFS, type FolderDatabaseReport, type FolderMoveChange, FrontmatterExtractor, FrontmatterGenerator, type FullScanReason, GITIGNORE_ENTRY, type GatedOperation, type GroupByConfig, type GroupedEntries, IGNORE_FILE, INTERNAL_DIR, INTERNAL_DIR_GLOB, type IStateDB, type ImageDownloadResult, ImageHandler, type ImageReference, type InferredProperty, InlineAnnotationPreserver, InlineDBParser, type InlineStyle, type LineDiffOptions, type LineRange, type LocalChange, LocalImageRestorer, type LocalMoveAdoption, type LocalScan, type LocalScanOptions, type Logger, MARKER_BRAND, type MappingResult, type MappingType, MathNormalizer, MentionToWikilink, type MergeConflictRegion, type MergeResult, NOTION_COLOR_NAMES, NOTION_TOKEN_PREFIX, NOTION_TO_BASES_VIEW, type NestedFolderPage, type NestedFolderRecord, NodeVaultFS, type NonMdFileInfo, type NotionAccessCheck, type NotionBlock, NotionBlockBuilder, NotionClient, type NotionClientOptions, type NotionColor, type NotionPageNode, type NotionRichText, type RichTextItem as NotionRichTextItem, type NotionSidecar, OBSIDIAN_CONFIG_DIR, OBSIDIAN_ONLY_PATTERNS, type OperationType, type OutsideVault, type PageCompletenessRemoteSource, type PageCompletenessReport, type PageCover, type PageCreationPlan, type PageIcon, PathFilter, type PathFilterConfig, type PendingOperation, PendingWalError, type PlacementChange, type PlannedRow, type PreserveMarker, PreserveMarkerCollector, PreserveMarkerInjector, type Processor, type ProcessorInput, type ProcessorMetadata, type ProcessorOutput, type ProgressCallback, type ProgressItem, PropertiesTableInjector, PropertiesTableRestorer, PropertyMapper, type PropertyOption, type PropertyRename, type PropertySchema, type PropertyValue, type PullOptions, type PullResult, type PushOptions, type PushResult, RENDER_LINE_RULES, type ReadOnlySkip, type RecordPendingInput, type RegisterFileInput, type RemoteChange, type RemoteMove, type RemoteMoveSkip, type RemoteObservation, type RemoteScanInfo, type RenameHints, type RenameKind, type RenderFinding, type RenderLineRule, type ResolutionChoice, type ResolutionResult, type RichTextSegment, type RowProgress, SAVED_STATE_TABLES_QUERY, SEPARATOR_BODY, SIDECAR_SUFFIX, STATE_DB_FILE, STATE_DB_MIGRATIONS, STATE_DB_PATH, SavedStateDbError, type SchemaEdit, type SchemaFollowed, ScopedVaultFS, SidecarGenerator, type SidecarProperty, type SidecarView, StateDB, StateDbLockedError, type StateDbMigration, type StateDbTool, StateDbUnavailableError, StateLock, type StateLockClaim, type StateLockOwner, type StatusOptions, type StatusResult, type StyledRange, SyncBusyError, type SyncDirection, type SyncOptions, SyncOrchestrator, type SyncRecord, type SyncResult, type SyncStatus, TEMPLATE_FOLDER_SETTINGS, type TableLineDesign, type TranslationResult, TreeMapper, UnlinkedVaultError, UnsupportedBlockStripper, type UpsertSyncRecord, type UserBaseFilterFix, type VaultCompletenessReport, type VaultFS, type ViewConfig, ViewDataProvider, type ViewEdit, type ViewPropertyConfig, type ViewRenderData, type ViewType, WIKILINK_LOOKUPS, type WatchSyncOptions, type WatchSyncScope, WatchSyncService, type WikilinkEntry, type WikilinkLookup, WikilinkResolver, applicableChoices, assertNoPendingWal, basesViewMappingOf, basesViewTypeOf, checkNotionAccess, choiceForStrategy, classifyBodyFidelity, columnLabel, compactNotionId, computeBufferHash, computeHash, configDirFrom, connectionFolderOf, createDefaultPipeline, extractCalendarEntries, filterByMonth, filterEntries, findConnectionFolders, findNestedFolderPages, formatUnifiedDiff, generateColorCSS, generateId, getLogger, getNotionBgColor, getNotionColor, getVisibleProperties, groupEntries, hasColumnLayout, hasDesignMarker, inAnyPathScope, isHeadingLine, isHeadingMarkerLine, isInternalPath, isMarkdownPath, isRemoteDeletion, lineDiff, lintRenderedMarkdown, matchesPathScope, normalizeNotionId, normalizeVaultPath, noteNameFromPath, notionIdFromInput, notionIdsEqual, notionPageUrl, obsidianOnlyExcludes, operationLabel, parseDesignColor, parseIgnorePatterns, pendingWalBytes, readColumnLayout, readDesignLine, resolvePropertyName, sanitizeFileName, sectionLinesWithHeadingMarkers, setLogger, shortNotionId, sortEntries, stateDbLockPath, stateDbWalPath, stripMarkdownExtension, summarizeFidelity, systemTimeZone, templateFolders, threeWayMerge, toVaultPath, translateNotionFilter, verifyDatabaseCompleteness, verifyPageCompleteness, wikilinkLookupsIn };