@tnotesjs/core 0.6.1 → 0.8.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.
Files changed (92) hide show
  1. package/commands/BaseCommand.ts +58 -0
  2. package/commands/build/BuildCommand.ts +25 -0
  3. package/commands/build/PreviewCommand.ts +29 -0
  4. package/commands/build/index.ts +8 -0
  5. package/commands/dev/DevCommand.ts +75 -0
  6. package/commands/dev/index.ts +7 -0
  7. package/commands/git/PullCommand.ts +25 -0
  8. package/commands/git/PushCommand.ts +64 -0
  9. package/commands/git/index.ts +8 -0
  10. package/commands/index.ts +11 -0
  11. package/commands/init-sub-repo/InitSubRepoCommand.ts +206 -0
  12. package/commands/init-sub-repo/index.ts +1 -0
  13. package/commands/misc/HelpCommand.ts +104 -0
  14. package/commands/misc/index.ts +7 -0
  15. package/commands/models.ts +87 -0
  16. package/commands/note/CreateNoteCommand.ts +160 -0
  17. package/commands/note/RenameNoteCommand.ts +147 -0
  18. package/commands/note/UpdateNoteConfigCommand.ts +78 -0
  19. package/commands/note/index.ts +9 -0
  20. package/commands/registry.ts +47 -0
  21. package/commands/update/UpdateCommand.ts +219 -0
  22. package/commands/update/index.ts +7 -0
  23. package/commands/update-completed-count/UpdateCompletedCountCommand.ts +208 -0
  24. package/commands/update-completed-count/index.ts +5 -0
  25. package/config/templates.ts +0 -5
  26. package/dist/{chunk-5F5RJ2HV.cjs → chunk-7FEANCT6.cjs} +16 -7
  27. package/dist/chunk-AGVER5MX.cjs +1746 -0
  28. package/dist/{chunk-TJ4527KA.cjs → chunk-BL22KD4V.cjs} +324 -950
  29. package/dist/{chunk-56PKXCOX.js → chunk-GWG75A5M.js} +13 -4
  30. package/dist/{chunk-DUTS75WQ.js → chunk-XNO3PCEH.js} +374 -1000
  31. package/dist/chunk-ZEQS64PE.js +1746 -0
  32. package/dist/cli/index.cjs +76 -155
  33. package/dist/cli/index.js +10 -89
  34. package/dist/markdown/index.cjs +8 -12
  35. package/dist/markdown/index.d.cts +1 -1
  36. package/dist/markdown/index.d.ts +1 -1
  37. package/dist/markdown/index.js +7 -11
  38. package/dist/{types-CwBWwNVv.d.ts → types-C_d0fFeD.d.ts} +8 -1
  39. package/dist/{types-CpsEy8lA.d.cts → types-MRBGgJTX.d.cts} +8 -1
  40. package/dist/vitepress/config/index.cjs +402 -178
  41. package/dist/vitepress/config/index.js +392 -168
  42. package/dist/workspace/index.cjs +4 -1202
  43. package/dist/workspace/index.d.cts +2 -2
  44. package/dist/workspace/index.d.ts +2 -2
  45. package/dist/workspace/index.js +4 -1202
  46. package/markdown/components.ts +86 -0
  47. package/markdown/index.ts +17 -0
  48. package/markdown/noteFormatter.test.ts +44 -0
  49. package/markdown/noteFormatter.ts +237 -0
  50. package/package.json +7 -3
  51. package/services/file-watcher/folderChangeHandler.ts +19 -15
  52. package/services/file-watcher/globalUpdateCoordinator.ts +21 -27
  53. package/services/file-watcher/service.ts +1 -6
  54. package/services/index.ts +0 -1
  55. package/services/note/service.ts +4 -6
  56. package/services/readme/service.ts +11 -18
  57. package/services/reconcileToc.ts +20 -0
  58. package/utils/index.ts +0 -9
  59. package/{services/toc → utils}/moveTocInside.test.ts +1 -1
  60. package/vitepress/components/BilibiliOutsidePlayer/BilibiliOutsidePlayer.vue +9 -18
  61. package/vitepress/components/EnWordList/EnWordList.vue +16 -662
  62. package/vitepress/components/Footprints/Footprints.vue +15 -537
  63. package/vitepress/components/Mermaid/Mermaid.vue +13 -588
  64. package/vitepress/components/MindmapPreview/MindmapPreview.vue +12 -434
  65. package/vitepress/components/MindmapPreview/markdown.ts +1 -1
  66. package/vitepress/components/NotesTable/NotesTable.vue +11 -130
  67. package/vitepress/components/constants.ts +2 -2
  68. package/vitepress/components/sidebar.data.ts +8 -5
  69. package/vitepress/configs/markdown.config.ts +170 -26
  70. package/vitepress/plugins/sidebarStructurePlugin.ts +242 -145
  71. package/vitepress/theme/index.ts +9 -13
  72. package/vitepress/theme/styles/base.scss +15 -0
  73. package/workspace/atomic.ts +113 -0
  74. package/workspace/errors.ts +27 -0
  75. package/workspace/index.ts +40 -0
  76. package/workspace/mutationQueue.ts +28 -0
  77. package/workspace/paths.ts +64 -0
  78. package/workspace/reconcile.test.ts +300 -0
  79. package/workspace/reconcile.ts +95 -0
  80. package/workspace/scanner.ts +292 -0
  81. package/workspace/types.ts +224 -0
  82. package/workspace/workspace.test.ts +333 -0
  83. package/workspace/workspace.ts +1020 -0
  84. package/dist/chunk-3R7QSABB.cjs +0 -502
  85. package/dist/chunk-CZXRQPFJ.js +0 -11
  86. package/dist/chunk-HXED7KVT.cjs +0 -11
  87. package/dist/chunk-U6IBLREL.js +0 -502
  88. package/services/toc/index.ts +0 -5
  89. package/services/toc/service.ts +0 -759
  90. package/utils/migrateReadmeToToc.test.ts +0 -111
  91. package/utils/migrateReadmeToToc.ts +0 -135
  92. package/vitepress/components/EnWordList/RightClickMenu.vue +0 -93
@@ -0,0 +1,292 @@
1
+ import { createHash } from 'node:crypto'
2
+ import fs from 'node:fs/promises'
3
+ import path from 'node:path'
4
+
5
+ import {
6
+ buildSidebarFromTocTree,
7
+ parseTocToTree,
8
+ } from '../utils/tocHelpers'
9
+
10
+ import type { WorkspacePaths } from './paths'
11
+ import type {
12
+ KnowledgeBaseSnapshot,
13
+ WorkspaceDiagnostic,
14
+ WorkspaceKnowledgeBaseConfig,
15
+ WorkspaceNoteConfig,
16
+ WorkspaceNoteSummary,
17
+ } from './types'
18
+ import type { NoteInfo } from '../types/note'
19
+
20
+ const NOTE_DIRECTORY_PATTERN = /^(\d{4})\.\s*(.+)$/
21
+ const CURRENT_SCHEMA_VERSION = 1
22
+
23
+ function digest(...values: Array<string | Buffer>): string {
24
+ const hash = createHash('sha256')
25
+ for (const value of values) {
26
+ hash.update(value)
27
+ hash.update('\0')
28
+ }
29
+ return hash.digest('hex')
30
+ }
31
+
32
+ async function readText(filePath: string): Promise<string | null> {
33
+ try {
34
+ return await fs.readFile(filePath, 'utf8')
35
+ } catch {
36
+ return null
37
+ }
38
+ }
39
+
40
+ function parseJsonObject<T extends Record<string, unknown>>(
41
+ content: string,
42
+ ): T | null {
43
+ try {
44
+ const value = JSON.parse(content) as unknown
45
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
46
+ ? (value as T)
47
+ : null
48
+ } catch {
49
+ return null
50
+ }
51
+ }
52
+
53
+ function noteInfoFromSummary(note: WorkspaceNoteSummary): NoteInfo {
54
+ return {
55
+ index: note.index,
56
+ path: note.directoryPath,
57
+ dirName: note.dirName,
58
+ readmePath: note.readmePath,
59
+ configPath: note.configPath,
60
+ config: note.config,
61
+ }
62
+ }
63
+
64
+ export interface ScannedWorkspace {
65
+ snapshot: KnowledgeBaseSnapshot
66
+ configText: string | null
67
+ tocText: string | null
68
+ }
69
+
70
+ export async function scanWorkspace(
71
+ paths: WorkspacePaths,
72
+ ): Promise<ScannedWorkspace> {
73
+ const diagnostics: WorkspaceDiagnostic[] = []
74
+ let rootIsDirectory = false
75
+ try {
76
+ rootIsDirectory = (await fs.stat(paths.root)).isDirectory()
77
+ } catch {
78
+ // Handled as a diagnostic below.
79
+ }
80
+ if (!rootIsDirectory) {
81
+ diagnostics.push({
82
+ code: 'ROOT_NOT_DIRECTORY',
83
+ message: '知识库根目录不存在或不是目录',
84
+ severity: 'error',
85
+ path: paths.root,
86
+ })
87
+ }
88
+
89
+ const configText = await readText(paths.config)
90
+ let config: WorkspaceKnowledgeBaseConfig | null = null
91
+ if (configText === null) {
92
+ diagnostics.push({
93
+ code: 'CONFIG_MISSING',
94
+ message: '缺少知识库配置 .tnotes.json',
95
+ severity: 'error',
96
+ path: paths.config,
97
+ })
98
+ } else {
99
+ config = parseJsonObject<WorkspaceKnowledgeBaseConfig>(configText)
100
+ if (!config) {
101
+ diagnostics.push({
102
+ code: 'CONFIG_INVALID_JSON',
103
+ message: '知识库配置不是有效的 JSON 对象',
104
+ severity: 'error',
105
+ path: paths.config,
106
+ })
107
+ } else {
108
+ if (typeof config.id !== 'string' || !config.id.trim()) {
109
+ diagnostics.push({
110
+ code: 'CONFIG_ID_MISSING',
111
+ message: '知识库配置缺少稳定的 id',
112
+ severity: 'error',
113
+ path: paths.config,
114
+ })
115
+ }
116
+ if (typeof config.repoName !== 'string' || !config.repoName.trim()) {
117
+ diagnostics.push({
118
+ code: 'CONFIG_REPO_NAME_MISSING',
119
+ message: '知识库配置缺少 repoName',
120
+ severity: 'error',
121
+ path: paths.config,
122
+ })
123
+ }
124
+ }
125
+ }
126
+
127
+ let notesDirectoryExists = false
128
+ try {
129
+ notesDirectoryExists = (await fs.stat(paths.notes)).isDirectory()
130
+ } catch {
131
+ // Handled below.
132
+ }
133
+ if (!notesDirectoryExists) {
134
+ diagnostics.push({
135
+ code: 'NOTES_DIRECTORY_MISSING',
136
+ message: '缺少 notes 目录',
137
+ severity: 'error',
138
+ path: paths.notes,
139
+ })
140
+ }
141
+
142
+ const tocText = await readText(paths.toc)
143
+ if (tocText === null) {
144
+ diagnostics.push({
145
+ code: 'TOC_MISSING',
146
+ message: '缺少目录真相源 TOC.md',
147
+ severity: 'error',
148
+ path: paths.toc,
149
+ })
150
+ }
151
+
152
+ const notes: WorkspaceNoteSummary[] = []
153
+ const usedIndexes = new Map<string, string>()
154
+ const usedIds = new Map<string, string>()
155
+ if (notesDirectoryExists) {
156
+ const entries = await fs.readdir(paths.notes, { withFileTypes: true })
157
+ entries.sort((left, right) => left.name.localeCompare(right.name))
158
+ for (const entry of entries) {
159
+ if (!entry.isDirectory() || entry.name.startsWith('.')) continue
160
+ const match = NOTE_DIRECTORY_PATTERN.exec(entry.name)
161
+ if (!match) continue
162
+
163
+ const [, index, rawTitle] = match
164
+ const title = rawTitle.trim()
165
+ const directoryPath = path.join(paths.notes, entry.name)
166
+ const readmePath = path.join(directoryPath, 'README.md')
167
+ const configPath = path.join(directoryPath, '.tnotes.json')
168
+ const readme = await readText(readmePath)
169
+ const noteConfigText = await readText(configPath)
170
+
171
+ if (readme === null) {
172
+ diagnostics.push({
173
+ code: 'NOTE_README_MISSING',
174
+ message: `笔记 ${entry.name} 缺少 README.md`,
175
+ severity: 'error',
176
+ path: readmePath,
177
+ })
178
+ continue
179
+ }
180
+ if (noteConfigText === null) {
181
+ diagnostics.push({
182
+ code: 'NOTE_CONFIG_MISSING',
183
+ message: `笔记 ${entry.name} 缺少 .tnotes.json`,
184
+ severity: 'error',
185
+ path: configPath,
186
+ })
187
+ continue
188
+ }
189
+
190
+ const noteConfig = parseJsonObject<WorkspaceNoteConfig>(noteConfigText)
191
+ if (!noteConfig || typeof noteConfig.id !== 'string' || !noteConfig.id) {
192
+ diagnostics.push({
193
+ code: 'NOTE_CONFIG_INVALID',
194
+ message: `笔记 ${entry.name} 的配置无法解析或缺少 id`,
195
+ severity: 'error',
196
+ path: configPath,
197
+ })
198
+ continue
199
+ }
200
+
201
+ const existingIndex = usedIndexes.get(index)
202
+ if (existingIndex) {
203
+ diagnostics.push({
204
+ code: 'NOTE_INDEX_DUPLICATE',
205
+ message: `笔记编号 ${index} 重复:${existingIndex}、${entry.name}`,
206
+ severity: 'error',
207
+ path: directoryPath,
208
+ })
209
+ } else {
210
+ usedIndexes.set(index, entry.name)
211
+ }
212
+ const existingId = usedIds.get(noteConfig.id)
213
+ if (existingId) {
214
+ diagnostics.push({
215
+ code: 'NOTE_ID_DUPLICATE',
216
+ message: `笔记 id ${noteConfig.id} 重复:${existingId}、${entry.name}`,
217
+ severity: 'error',
218
+ path: configPath,
219
+ })
220
+ } else {
221
+ usedIds.set(noteConfig.id, entry.name)
222
+ }
223
+
224
+ notes.push({
225
+ uuid: noteConfig.id,
226
+ index,
227
+ title,
228
+ dirName: entry.name,
229
+ directoryPath,
230
+ readmePath,
231
+ configPath,
232
+ config: noteConfig,
233
+ revision: digest(entry.name, readme, noteConfigText),
234
+ })
235
+ }
236
+ }
237
+
238
+ const noteInfos = notes.map(noteInfoFromSummary)
239
+ const toc = tocText ? parseTocToTree(tocText.split('\n'), noteInfos) : []
240
+ const sidebar = buildSidebarFromTocTree(toc, noteInfos, {
241
+ sidebarShowNoteId: config?.sidebarShowNoteId ?? true,
242
+ sidebarIsCollapsed: true,
243
+ })
244
+
245
+ const schemaVersion = config?.schemaVersion
246
+ const futureSchema =
247
+ typeof schemaVersion === 'number' && schemaVersion > CURRENT_SCHEMA_VERSION
248
+ if (futureSchema) {
249
+ diagnostics.push({
250
+ code: 'FUTURE_SCHEMA',
251
+ message: `知识库 schemaVersion ${schemaVersion} 高于当前支持版本 ${CURRENT_SCHEMA_VERSION}`,
252
+ severity: 'error',
253
+ path: paths.config,
254
+ })
255
+ }
256
+
257
+ const health = futureSchema
258
+ ? { status: 'future-schema' as const, diagnostics }
259
+ : diagnostics.some((diagnostic) => diagnostic.severity === 'error')
260
+ ? { status: 'invalid' as const, diagnostics }
261
+ : { status: 'ready' as const, diagnostics }
262
+
263
+ const id =
264
+ config && typeof config.id === 'string' && config.id.trim()
265
+ ? config.id
266
+ : `path-${digest(paths.root).slice(0, 24)}`
267
+ const revision = digest(
268
+ paths.root,
269
+ configText ?? '',
270
+ tocText ?? '',
271
+ ...notes.map((note) => `${note.uuid}:${note.revision}`),
272
+ )
273
+
274
+ return {
275
+ snapshot: {
276
+ id,
277
+ rootPath: paths.root,
278
+ config,
279
+ health,
280
+ toc,
281
+ sidebar,
282
+ notes,
283
+ revision,
284
+ },
285
+ configText,
286
+ tocText,
287
+ }
288
+ }
289
+
290
+ export function toNoteInfo(note: WorkspaceNoteSummary): NoteInfo {
291
+ return noteInfoFromSummary(note)
292
+ }
@@ -0,0 +1,224 @@
1
+ import type { TNotesConfig } from '../types/config'
2
+ import type { NoteConfig } from '../types/note'
3
+ import type { TocTreeNode, TocSidebarItem } from '../utils/tocHelpers'
4
+
5
+ export type WorkspaceDiagnosticSeverity = 'error' | 'warning' | 'info'
6
+
7
+ export interface WorkspaceDiagnostic {
8
+ code: string
9
+ message: string
10
+ severity: WorkspaceDiagnosticSeverity
11
+ path?: string
12
+ }
13
+
14
+ export type WorkspaceHealth =
15
+ | { status: 'ready'; diagnostics: WorkspaceDiagnostic[] }
16
+ | { status: 'invalid'; diagnostics: WorkspaceDiagnostic[] }
17
+ | { status: 'future-schema'; diagnostics: WorkspaceDiagnostic[] }
18
+
19
+ /**
20
+ * Core only edits known fields, but it must retain fields introduced by a
21
+ * knowledge base or by a newer Core release.
22
+ */
23
+ export type WorkspaceNoteConfig = NoteConfig & Record<string, unknown>
24
+ export type WorkspaceKnowledgeBaseConfig = TNotesConfig &
25
+ Record<string, unknown>
26
+
27
+ export interface WorkspaceNoteSummary {
28
+ uuid: string
29
+ index: string
30
+ title: string
31
+ dirName: string
32
+ directoryPath: string
33
+ readmePath: string
34
+ configPath: string
35
+ config: WorkspaceNoteConfig
36
+ revision: string
37
+ }
38
+
39
+ export interface KnowledgeBaseSnapshot {
40
+ id: string
41
+ rootPath: string
42
+ config: WorkspaceKnowledgeBaseConfig | null
43
+ health: WorkspaceHealth
44
+ toc: TocTreeNode[]
45
+ sidebar: TocSidebarItem[]
46
+ notes: WorkspaceNoteSummary[]
47
+ revision: string
48
+ }
49
+
50
+ export interface NoteDocument extends WorkspaceNoteSummary {
51
+ content: string
52
+ }
53
+
54
+ export interface ChangedFile {
55
+ path: string
56
+ kind: 'created' | 'updated' | 'deleted' | 'renamed' | 'trashed'
57
+ previousPath?: string
58
+ }
59
+
60
+ export interface MutationResult<T> {
61
+ value: T
62
+ changedFiles: ChangedFile[]
63
+ snapshotRevision: string
64
+ }
65
+
66
+ export interface WorkspaceLogger {
67
+ debug?(message: string, details?: unknown): void
68
+ info?(message: string, details?: unknown): void
69
+ warn?(message: string, details?: unknown): void
70
+ error?(message: string, details?: unknown): void
71
+ }
72
+
73
+ export interface CreateWorkspaceOptions {
74
+ rootPath: string
75
+ logger?: WorkspaceLogger
76
+ format?: {
77
+ prettier?: boolean
78
+ }
79
+ }
80
+
81
+ export interface SaveNoteInput {
82
+ noteUuid: string
83
+ content: string
84
+ expectedRevision: string
85
+ prettier?: boolean
86
+ }
87
+
88
+ export type NotePlacement =
89
+ | { type: 'root'; placement?: 'start' | 'end' }
90
+ | {
91
+ type: 'note'
92
+ targetNoteUuid: string
93
+ placement: 'before' | 'after' | 'inside'
94
+ }
95
+ | {
96
+ type: 'folder'
97
+ folderPath: string[]
98
+ placement: 'before' | 'after' | 'inside'
99
+ }
100
+
101
+ export interface CreateNoteInput {
102
+ title: string
103
+ placement?: NotePlacement
104
+ config?: Partial<Pick<WorkspaceNoteConfig, 'description' | 'enableDiscussions'>>
105
+ expectedSnapshotRevision?: string
106
+ }
107
+
108
+ export interface RenameNoteInput {
109
+ noteUuid: string
110
+ title: string
111
+ expectedRevision: string
112
+ }
113
+
114
+ export interface UpdateNoteConfigInput {
115
+ noteUuid: string
116
+ updates: Partial<
117
+ Pick<
118
+ WorkspaceNoteConfig,
119
+ 'done' | 'description' | 'enableDiscussions'
120
+ >
121
+ >
122
+ expectedRevision: string
123
+ }
124
+
125
+ export type TocEntryRef =
126
+ | { type: 'note'; noteUuid: string }
127
+ | { type: 'folder'; folderPath: string[] }
128
+ | { type: 'line'; tocLineIndex: number }
129
+
130
+ export interface MoveTocEntryInput {
131
+ source: TocEntryRef
132
+ target: TocEntryRef
133
+ placement: 'before' | 'after' | 'inside'
134
+ expectedSnapshotRevision: string
135
+ }
136
+
137
+ export interface CreateTocGroupInput {
138
+ title: string
139
+ placement?: NotePlacement
140
+ expectedSnapshotRevision: string
141
+ }
142
+
143
+ export interface RenameTocGroupInput {
144
+ folderPath: string[]
145
+ title: string
146
+ expectedSnapshotRevision: string
147
+ }
148
+
149
+ export interface DeletePreviewItem {
150
+ noteUuid: string
151
+ index: string
152
+ title: string
153
+ directoryPath: string
154
+ }
155
+
156
+ export interface DeleteTocEntryPreview {
157
+ entry: TocEntryRef
158
+ notes: DeletePreviewItem[]
159
+ filePaths: string[]
160
+ directoryPaths: string[]
161
+ snapshotRevision: string
162
+ }
163
+
164
+ export interface DeleteTocEntryInput {
165
+ entry: TocEntryRef
166
+ expectedSnapshotRevision: string
167
+ }
168
+
169
+ export interface WriteAttachmentInput {
170
+ noteUuid: string
171
+ fileName: string
172
+ data: Uint8Array
173
+ }
174
+
175
+ export interface AttachmentResult {
176
+ absolutePath: string
177
+ markdownPath: string
178
+ }
179
+
180
+ export interface TNotesWorkspace {
181
+ inspect(): Promise<KnowledgeBaseSnapshot>
182
+ refresh(): Promise<KnowledgeBaseSnapshot>
183
+ reconcileTocCompletion(): Promise<MutationResult<KnowledgeBaseSnapshot>>
184
+
185
+ notes: {
186
+ read(noteUuid: string): Promise<NoteDocument>
187
+ save(input: SaveNoteInput): Promise<MutationResult<NoteDocument>>
188
+ create(input: CreateNoteInput): Promise<MutationResult<NoteDocument>>
189
+ rename(input: RenameNoteInput): Promise<MutationResult<NoteDocument>>
190
+ updateConfig(
191
+ input: UpdateNoteConfigInput,
192
+ ): Promise<MutationResult<NoteDocument>>
193
+ }
194
+
195
+ toc: {
196
+ move(input: MoveTocEntryInput): Promise<MutationResult<KnowledgeBaseSnapshot>>
197
+ createGroup(
198
+ input: CreateTocGroupInput,
199
+ ): Promise<MutationResult<KnowledgeBaseSnapshot>>
200
+ renameGroup(
201
+ input: RenameTocGroupInput,
202
+ ): Promise<MutationResult<KnowledgeBaseSnapshot>>
203
+ previewDelete(entry: TocEntryRef): Promise<DeleteTocEntryPreview>
204
+ deleteEntry(
205
+ input: DeleteTocEntryInput,
206
+ ): Promise<MutationResult<KnowledgeBaseSnapshot>>
207
+ setDone(input: UpdateNoteConfigInput): Promise<MutationResult<NoteDocument>>
208
+ /**
209
+ * Align TOC.md + sidebar.json with the filesystem truth (files-first).
210
+ * Valid notes missing from the TOC are appended (root level, by index);
211
+ * note dirs with a missing/invalid config are soft-deleted to
212
+ * notes/.trash/. Idempotent: no changes -> changedFiles = [].
213
+ */
214
+ reconcileFromFiles(): Promise<MutationResult<KnowledgeBaseSnapshot>>
215
+ }
216
+
217
+ attachments: {
218
+ writeLocal(
219
+ input: WriteAttachmentInput,
220
+ ): Promise<MutationResult<AttachmentResult>>
221
+ }
222
+
223
+ dispose(): Promise<void>
224
+ }