@im-nobsidian/core 0.15.0 → 0.17.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;
@@ -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,8 +208,13 @@ 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
220
  direction: "push" | "pull" | "both";
@@ -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,6 +266,12 @@ 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
277
  direction?: "push" | "pull" | "both" | 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;
@@ -425,6 +415,7 @@ interface ProgressItem {
425
415
  * 받아 봤지만 볼트에 쓰지 않았다(pull) — 바뀐 것이 없거나 로컬을 지켰다. 진행 수에는 들지만 화면이 바뀐
426
416
  * 노트로 적지 않는다. 다시 그리기(B14)는
427
417
  * 받아 둔 노트를 모두 받아 보므로, 적으면 바뀌지 않은 노트마다 「updated」 줄이 찍혔다.
418
+ * push 는 보낼 것이 없던 고침 — 읽기 전용 속성만 고친 행.
428
419
  */
429
420
  readonly unchanged?: boolean;
430
421
  }
@@ -981,6 +972,11 @@ interface IStateDB {
981
972
  /** 닫는다 — 파일에 남은 쓰기를 마쳐야 하는 구현(플러그인의 sql.js)은 그 일을 Promise 로 돌려준다. */
982
973
  close(): void | Promise<void>;
983
974
  getByPath(path: string): SyncRecord | null;
975
+ /**
976
+ * 대소문자를 가리지 않고 같은 경로의 기록들 — 받을 이름이 macOS · Windows 에서 다른 노트의 파일과 겹치는지(P9).
977
+ * SQLite 의 `NOCASE` 라 ASCII 만 접는다. 경로는 NFC 로 적혀 있다(`upgradeNfcPaths`).
978
+ */
979
+ getByPathKey(path: string): SyncRecord[];
984
980
  getByNotionId(pageId: string): SyncRecord | null;
985
981
  getByStatus(status: SyncStatus): SyncRecord[];
986
982
  getAll(): SyncRecord[];
@@ -1024,7 +1020,13 @@ interface IStateDB {
1024
1020
  declare class StateDB implements IStateDB {
1025
1021
  private readonly lock;
1026
1022
  private readonly db;
1023
+ /**
1024
+ * 준비한 문장 — SQL 글자마다 한 번만 준비한다. 노트마다 여러 번 부르는 조회(`getByPath` 등)가 부를 때마다 다시
1025
+ * 준비하면 5,000 노트 첫 push 에서 준비만 3초였다(P10 실측). 스키마가 바뀌면 SQLite 가 다시 준비한다.
1026
+ */
1027
+ private readonly statements;
1027
1028
  private constructor();
1029
+ private sql;
1028
1030
  /**
1029
1031
  * 상태 DB 파일을 연다 — 없으면 새로 만든다. 한 볼트의 상태 DB 는 한 곳만 연다 — 플러그인이나 다른 CLI 가 쓰는
1030
1032
  * 중이면 {@link StateDbLockedError} 를 던진다(ADR-026). 저장된 파일이 비었거나 잘렸으면 빈 DB 로 열지 않고
@@ -1052,6 +1054,7 @@ declare class StateDB implements IStateDB {
1052
1054
  /** 닫고 잠금을 푼다 — 닫는 사이 다른 곳이 열지 않게 닫은 뒤에 푼다. */
1053
1055
  close(): void;
1054
1056
  getByPath(path: string): SyncRecord | null;
1057
+ getByPathKey(path: string): SyncRecord[];
1055
1058
  getByNotionId(pageId: string): SyncRecord | null;
1056
1059
  getByStatus(status: SyncStatus): SyncRecord[];
1057
1060
  getAll(): SyncRecord[];
@@ -1206,6 +1209,11 @@ declare const SAVED_STATE_TABLES_QUERY = "SELECT 1 FROM sqlite_master WHERE type
1206
1209
  * 예전 조회(`LIKE '%/노트.md'`)는 슬래시가 앞에 있어야 맞아서 볼트 맨 위 노트와 경로 붙은 링크를 못 찾았다 —
1207
1210
  * 제목이 파일 이름과 다른 노트(파일 이름에 못 쓰는 글자를 바꾼 노트)로 가는 링크가 Notion 에서 글로 남았다.
1208
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 요청 시간에 견주면 작다.
1209
1217
  */
1210
1218
  interface WikilinkLookup {
1211
1219
  readonly sql: string;
@@ -2013,7 +2021,13 @@ declare class NotionClient {
2013
2021
  */
2014
2022
  setWikilinkResolver(resolver: WikilinkResolver$1): void;
2015
2023
  extractProperties(page: PageObjectResponse): Record<string, unknown>;
2016
- 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;
2017
2031
  /**
2018
2032
  * 429 이후 **클라이언트 전체**가 쉬어야 하는 시각(epoch ms).
2019
2033
  *
@@ -2051,6 +2065,22 @@ declare class NotionClient {
2051
2065
  private waitForTurn;
2052
2066
  }
2053
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
+
2054
2084
  interface RichTextSegment {
2055
2085
  content: string;
2056
2086
  bold?: boolean;
@@ -2735,7 +2765,7 @@ interface UserBaseFilterFix {
2735
2765
  * 긴 sync(실볼트 pull 500초) 동안 주기 sync 가 쌓인다.
2736
2766
  */
2737
2767
  /** 잠그는 작업 — 볼트 · 상태 DB · 원격을 바꾸거나 이번 실행의 기준을 정하는 것. */
2738
- type GatedOperation = "push" | "pull" | "sync" | "status" | "fetch" | "resolve" | "discard" | "prepare-database" | "base-filters";
2768
+ type GatedOperation = "push" | "pull" | "sync" | "status" | "fetch" | "resolve" | "discard" | "prepare-database" | "base-filters" | "verify";
2739
2769
  declare function operationLabel(operation: GatedOperation): string;
2740
2770
  declare class SyncBusyError extends Error {
2741
2771
  /** 이미 도는 작업. */
@@ -2793,6 +2823,16 @@ declare class SyncOrchestrator {
2793
2823
  * 목록에 없으므로, 그대로 돌리면 「볼트에서 지움」 으로 보고 Notion 페이지를 지우거나 되살리려 한다.
2794
2824
  */
2795
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;
2796
2836
  /**
2797
2837
  * @param mergedByPull sync dry-run 만 — 앞선 pull dry-run 이 합칠 노트. 실제 sync 는 합친 뒤 원격을 본 것으로
2798
2838
  * 적어 push 가 올린다 — dry-run 은 받지 않아 원격이 바뀐 그대로라, 원격을 보고 거절하지 않는다.
@@ -2852,6 +2892,10 @@ declare class SyncOrchestrator {
2852
2892
  recordLocalRename(from: string, to: string, kind: RenameKind): void;
2853
2893
  /** 볼트에서 지운 노트 · 폴더 — 그 자리를 새 경로로 적은 힌트를 버린다. */
2854
2894
  recordLocalDelete(path: string): void;
2895
+ /**
2896
+ * 토큰 · 루트 페이지(DB 모드면 DB)를 읽을 수 있는지 Notion 에 묻는다 — 아무것도 쓰지 않아 동기화와 겹쳐도 된다.
2897
+ */
2898
+ checkNotionAccess(): Promise<NotionAccessCheck>;
2855
2899
  /**
2856
2900
  * 볼트 완결성 검증 — 원격에 있는 것이 볼트에 빠짐없이 있는지 대조한다(R11-B · R12-C).
2857
2901
  *
@@ -2868,6 +2912,7 @@ declare class SyncOrchestrator {
2868
2912
  * 열거와 맞대 봐야 의미가 있다.
2869
2913
  */
2870
2914
  verifyCompleteness(): Promise<VaultCompletenessReport>;
2915
+ private executeVerifyCompleteness;
2871
2916
  fetch(): Promise<{
2872
2917
  newPages: number;
2873
2918
  deletedPages: number;
@@ -2924,10 +2969,26 @@ declare class SyncOrchestrator {
2924
2969
  interface PathFilterConfig {
2925
2970
  readonly include?: string[];
2926
2971
  readonly exclude?: string[];
2972
+ /**
2973
+ * Obsidian 에서만 쓰는 것(Canvas · Excalidraw · 템플릿 폴더)도 뺀다 — `true` 일 때만. 볼트를 여는 쪽(CLI · 플러그인)이
2974
+ * `obsidianOnlyExcludes` 로 패턴을 더한다.
2975
+ */
2976
+ readonly excludeObsidianOnly?: boolean;
2927
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
+ */
2928
2983
  declare class NodeVaultFS implements VaultFS {
2929
2984
  private readonly rootPath;
2930
2985
  private readonly filter;
2986
+ /**
2987
+ * NFC 볼트 경로 → 디스크의 상대 경로 — ASCII 가 아닌 이름(파일 · 폴더)만. 걸을 때 · 처음 열 때 채운다. 새로 만드는 이름은
2988
+ * NFC 로 쓴다.
2989
+ * Linux 는 두 꼴을 다른 이름으로 보므로 NFC 경로를 그대로 열면 NFD 파일 옆에 새 파일이 생긴다.
2990
+ */
2991
+ private readonly diskPaths;
2931
2992
  /**
2932
2993
  * @param ignoreFile 폴더의 `.im-nobsidian-ignore` 를 따른다 — 볼트 전체를 보는 쪽(다른 연결의 노트에서 링크를 고칠 때)은
2933
2994
  * 그 폴더를 맡은 연결의 제외 목록을 따르지 않는다.
@@ -2949,8 +3010,23 @@ declare class NodeVaultFS implements VaultFS {
2949
3010
  listMarkdownFileStats(): Promise<FileStatInfo[]>;
2950
3011
  getFileStat(path: string): Promise<FileStatInfo | null>;
2951
3012
  listNonMarkdownFiles(): Promise<NonMdFileInfo[]>;
2952
- /** 볼트 경로 — Windows 의 `relative()` 는 `\` 로 잇는다. 상태 DB · 패턴 · Notion 경로는 모두 `/` 다. */
2953
- 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;
2954
3030
  private walkDirNonMd;
2955
3031
  private walkDirStats;
2956
3032
  private walkDir;
@@ -3268,6 +3344,8 @@ declare class FileHandler {
3268
3344
  * 호출이 늘어나는 **합성 경로**라 전체로는 여전히 무한대다. 상한을 넘긴 첨부는 경고만
3269
3345
  * 남기고 나머지 첨부는 계속 올린다 — 첨부 하나가 push 전체를 멎게 하지 않는다.
3270
3346
  *
3347
+ * @param failed 실패를 결과로 알릴 곳 — 있으면 실패를 여기 담고 경고 로그는 내지 않는다(화면이 결과로 알린다. 둘 다
3348
+ * 내면 같은 말이 두 번 나온다). 없으면 경고 로그로만 남는다.
3271
3349
  * @returns 업로드 결과. 변경 없음(스킵)이거나 실패했으면 null.
3272
3350
  */
3273
3351
  private pushSingleFile;
@@ -3283,7 +3361,13 @@ declare class FileHandler {
3283
3361
  * 때마다 같은 요청을 다시 보내 같은 이유로 실패했다(실볼트 `.ipynb` 22개).
3284
3362
  */
3285
3363
  private listUploadableFiles;
3286
- pushAllFiles(): Promise<FileUploadResult[]>;
3364
+ /**
3365
+ * 볼트의 첨부를 폴더 페이지마다 올린다.
3366
+ *
3367
+ * @param failed 올리지 못한 첨부를 담을 곳 — push 결과의 `failed` 를 넘기면 CLI · 플러그인이 처리하지 못한 것으로
3368
+ * 보인다. 예전엔 경고 로그로만 남아 push 가 「실패 0」 으로 끝났다.
3369
+ */
3370
+ pushAllFiles(failed?: FailedOperation[]): Promise<FileUploadResult[]>;
3287
3371
  downloadFileBlock(url: string, filename: string, targetFolder: string): Promise<FileDownloadResult>;
3288
3372
  downloadFileBlocks(blocks: Array<{
3289
3373
  type: string;
@@ -4560,9 +4644,14 @@ declare function notionIdsEqual(a: string, b: string): boolean;
4560
4644
  * markdown-api 경로(convertPageMentions)가 동일 형태로 수렴하도록 한다(rank20/I3).
4561
4645
  */
4562
4646
  declare function compactNotionId(id: string): string;
4647
+ /** 페이지 · DB 를 여는 주소 — 하이픈을 뗀 id 를 붙인다. */
4648
+ declare function notionPageUrl(id: string): string;
4563
4649
  declare function shortNotionId(id: string): string;
4564
4650
 
4565
- /** Notion 제목 → 볼트 파일 이름(확장자 없이). */
4651
+ /**
4652
+ * Notion 제목 → 볼트 파일 이름(확장자 없이). NFC 로 — 볼트 경로는 NFC 다(`NodeVaultFS`). macOS 에서 NFD 이름으로 올린
4653
+ * 제목도 같은 파일 이름이 된다.
4654
+ */
4566
4655
  declare function sanitizeFileName(name: string): string;
4567
4656
 
4568
4657
  /** 노트(마크다운 파일)의 경로 · 이름인가. */
@@ -4639,6 +4728,35 @@ declare function parseIgnorePatterns(content: string): string[];
4639
4728
  /** 운영체제 구분자로 이은 상대 경로 → 볼트 경로(`/`). `relative()` 의 결과에 쓴다. */
4640
4729
  declare function toVaultPath(relativePath: string, separator: string): string;
4641
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
+
4642
4760
  /** 줄 비교의 한 줄. 번호는 1부터 — 더한 줄은 옛 번호가, 지운 줄은 새 번호가 없다. */
4643
4761
  interface DiffLine {
4644
4762
  readonly kind: "same" | "added" | "removed";
@@ -4690,6 +4808,31 @@ interface Logger {
4690
4808
  declare function setLogger(logger: Logger): void;
4691
4809
  declare function getLogger(): Logger;
4692
4810
 
4811
+ /**
4812
+ * lookbehind 없이 앞 글을 보는 정규식 — 소스에 `(?<!…)` · `(?<=…)` 를 쓰지 않는다.
4813
+ *
4814
+ * iOS 16.4 앞의 JavaScript 는 lookbehind 를 읽지 못해, 그런 정규식 하나가 든 스크립트 전체가 뜨지 않는다 — 플러그인이
4815
+ * 모바일에서 아예 켜지지 않는다(P11). 커뮤니티 디렉터리의 검사도 데스크톱 전용이 아닌 플러그인의 lookbehind 를
4816
+ * 거절한다. `tests/utils/no-lookbehind.test.ts` 가 소스에 다시 들어오지 않게 막는다.
4817
+ *
4818
+ * `exec` 만 갈아 끼운다 — `replace` · `matchAll` · `split` · `test` 가 모두 `exec` 를 부르므로 쓰는 곳은 바뀌지 않는다.
4819
+ * 맞은 자리의 앞 글이 조건에 맞지 않으면 그 자리를 버리고 다음 글자에서 다시 찾는다. 정규식 맨 앞(또는 마지막
4820
+ * 갈래의 맨 앞)의 lookbehind 와 결과가 같다 — 엔진도 그 자리에서 lookbehind 가 막히면 다음 글자로 넘어간다.
4821
+ */
4822
+ /** 맞은 것을 받나 — `index` 는 맞은 자리, `match` 는 맞은 것(갈래를 가를 때). */
4823
+ type Lookbehind = (text: string, index: number, match: RegExpExecArray) => boolean;
4824
+ declare class LookbehindRegExp extends RegExp {
4825
+ readonly accept: Lookbehind;
4826
+ /** 실제로 찾는 정규식 — `g`(또는 `y`) 로 어느 자리에서든 이어 찾는다. */
4827
+ private readonly scanner;
4828
+ constructor(pattern: string | RegExp, flags?: string, accept?: Lookbehind);
4829
+ exec(text: string): RegExpExecArray | null;
4830
+ }
4831
+ /** `index` 바로 앞의 글자(써로게이트 쌍은 하나로) — 맨 앞이면 "". */
4832
+ declare function charBefore(text: string, index: number): string;
4833
+ /** `(?<![…])` — 바로 앞 글자가 `set`(글자 하나를 보는 정규식)에 맞지 않거나 맨 앞이다. */
4834
+ declare function notAfter(set: RegExp): Lookbehind;
4835
+
4693
4836
  /**
4694
4837
  * 경로 패턴(`paths.include` · `paths.exclude` · `.im-nobsidian-ignore`)을 목록에 대는 VaultFS.
4695
4838
  *
@@ -4840,6 +4983,8 @@ declare const DB_VIEWS_PATH = ".im-nobsidian/db-views.json";
4840
4983
  declare const STATE_DB_PATH = ".im-nobsidian/sync.db";
4841
4984
  /** 파일 감시에서 제외할 내부 디렉터리 glob. */
4842
4985
  declare const INTERNAL_DIR_GLOB = "**/.im-nobsidian/**";
4986
+ /** DB 사이드카 파일 확장자 — `<DB 이름>.notion.json`. */
4987
+ declare const SIDECAR_SUFFIX = ".notion.json";
4843
4988
  /** Obsidian 설정 폴더 기본 이름(볼트 맨 위). 사용자가 바꿀 수 있어 플러그인은 `vault.configDir` 를 쓴다. */
4844
4989
  declare const OBSIDIAN_CONFIG_DIR = ".obsidian";
4845
4990
  /**
@@ -4976,4 +5121,4 @@ declare function readColumnLayout(lines: readonly string[]): (ColumnPlace | unde
4976
5121
  /** 열 이름표 — `열 2/3 · 50%`. 비율이 없으면 `열 2/3`. */
4977
5122
  declare function columnLabel(place: ColumnPlace): string;
4978
5123
 
4979
- 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 NotionBlock, NotionBlockBuilder, NotionClient, type NotionClientOptions, type NotionColor, type NotionPageNode, type NotionRichText, type RichTextItem as NotionRichTextItem, type NotionSidecar, OBSIDIAN_CONFIG_DIR, 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, 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, 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, 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 };
5124
+ 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, type Lookbehind, LookbehindRegExp, 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, charBefore, 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, notAfter, 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 };