orgnote-api 0.17.0 → 0.17.2

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 (126) hide show
  1. package/dist/api.d.ts +112 -0
  2. package/dist/api.js +1 -0
  3. package/dist/encryption/__tests__/encryption-keys.d.ts +3 -0
  4. package/{encryption/__tests__/encryption-keys.ts → dist/encryption/__tests__/encryption-keys.js} +0 -2
  5. package/dist/encryption/__tests__/encryption.spec.d.ts +1 -0
  6. package/dist/encryption/__tests__/encryption.spec.js +287 -0
  7. package/dist/encryption/__tests__/note-encryption.spec.d.ts +1 -0
  8. package/dist/encryption/__tests__/note-encryption.spec.js +364 -0
  9. package/dist/encryption/encryption.d.ts +27 -0
  10. package/dist/encryption/encryption.js +156 -0
  11. package/dist/encryption/index.js +2 -0
  12. package/dist/encryption/note-encryption.d.ts +12 -0
  13. package/dist/encryption/note-encryption.js +42 -0
  14. package/dist/files-api.d.ts +7 -0
  15. package/dist/files-api.js +22 -0
  16. package/dist/index.js +5 -0
  17. package/dist/models/command.d.ts +29 -0
  18. package/dist/models/command.js +1 -0
  19. package/dist/models/completion.d.ts +22 -0
  20. package/dist/models/completion.js +1 -0
  21. package/dist/models/default-commands.d.ts +30 -0
  22. package/dist/models/default-commands.js +41 -0
  23. package/dist/models/editor.d.ts +23 -0
  24. package/dist/models/editor.js +1 -0
  25. package/dist/models/encryption.d.ts +31 -0
  26. package/dist/models/encryption.js +1 -0
  27. package/dist/models/extension.d.ts +34 -0
  28. package/dist/models/extension.js +1 -0
  29. package/dist/models/file-system.d.ts +23 -0
  30. package/dist/models/file-system.js +1 -0
  31. package/{models/index.ts → dist/models/index.d.ts} +2 -0
  32. package/dist/models/index.js +13 -0
  33. package/dist/models/modal.d.ts +10 -0
  34. package/dist/models/modal.js +1 -0
  35. package/dist/models/note.d.ts +23 -0
  36. package/dist/models/note.js +1 -0
  37. package/dist/models/sync.d.ts +34 -0
  38. package/dist/models/sync.js +1 -0
  39. package/dist/models/theme-variables.d.ts +192 -0
  40. package/dist/models/theme-variables.js +194 -0
  41. package/{models/vue-component.ts → dist/models/vue-component.d.ts} +1 -1
  42. package/dist/models/vue-component.js +1 -0
  43. package/dist/models/widget-type.d.ts +5 -0
  44. package/dist/models/widget-type.js +6 -0
  45. package/dist/models/widget.d.ts +51 -0
  46. package/dist/models/widget.js +1 -0
  47. package/dist/remote-api/api.d.ts +1525 -0
  48. package/{remote-api/api.ts → dist/remote-api/api.js} +246 -1149
  49. package/dist/remote-api/base.d.ts +66 -0
  50. package/{remote-api/base.ts → dist/remote-api/base.js} +13 -36
  51. package/dist/remote-api/common.d.ts +65 -0
  52. package/{remote-api/common.ts → dist/remote-api/common.js} +31 -48
  53. package/{remote-api/configuration.ts → dist/remote-api/configuration.d.ts} +3 -22
  54. package/dist/remote-api/configuration.js +95 -0
  55. package/dist/remote-api/index.d.ts +13 -0
  56. package/{remote-api/index.ts → dist/remote-api/index.js} +0 -3
  57. package/dist/tools/__tests__/find-files-diff.spec.d.ts +1 -0
  58. package/dist/tools/__tests__/find-files-diff.spec.js +110 -0
  59. package/dist/tools/__tests__/find-note-files-diff.spec.d.ts +1 -0
  60. package/dist/tools/__tests__/find-note-files-diff.spec.js +168 -0
  61. package/dist/tools/__tests__/get-file-name.spec.d.ts +1 -0
  62. package/dist/tools/__tests__/get-file-name.spec.js +14 -0
  63. package/dist/tools/__tests__/get-string-path.spec.d.ts +1 -0
  64. package/dist/tools/__tests__/get-string-path.spec.js +27 -0
  65. package/dist/tools/__tests__/is-gpg-encrypted.spec.d.ts +1 -0
  66. package/{tools/__tests__/is-gpg-encrypted.spec.ts → dist/tools/__tests__/is-gpg-encrypted.spec.js} +4 -8
  67. package/dist/tools/__tests__/is-org-file.spec.d.ts +1 -0
  68. package/dist/tools/__tests__/is-org-file.spec.js +54 -0
  69. package/dist/tools/__tests__/join.spec.d.ts +1 -0
  70. package/dist/tools/__tests__/join.spec.js +14 -0
  71. package/dist/tools/__tests__/read-org-files-recursively.spec.d.ts +1 -0
  72. package/dist/tools/__tests__/read-org-files-recursively.spec.js +51 -0
  73. package/dist/tools/extend-notes-files-diff.d.ts +3 -0
  74. package/dist/tools/extend-notes-files-diff.js +21 -0
  75. package/dist/tools/find-notes-files-diff.d.ts +5 -0
  76. package/dist/tools/find-notes-files-diff.js +108 -0
  77. package/dist/tools/get-file-name.d.ts +2 -0
  78. package/dist/tools/get-file-name.js +6 -0
  79. package/dist/tools/get-string-path.d.ts +1 -0
  80. package/dist/tools/get-string-path.js +6 -0
  81. package/dist/tools/index.d.ts +6 -0
  82. package/dist/tools/index.js +6 -0
  83. package/dist/tools/is-gpg-encrypted.d.ts +1 -0
  84. package/dist/tools/is-gpg-encrypted.js +6 -0
  85. package/dist/tools/is-org-file.d.ts +2 -0
  86. package/dist/tools/is-org-file.js +4 -0
  87. package/dist/tools/join.d.ts +1 -0
  88. package/dist/tools/join.js +3 -0
  89. package/dist/tools/mock-server.d.ts +1 -0
  90. package/dist/tools/mock-server.js +12 -0
  91. package/package.json +6 -14
  92. package/api.ts +0 -123
  93. package/encryption/__tests__/__snapshots__/note-encryption.spec.ts.snap +0 -231
  94. package/encryption/__tests__/encryption.spec.ts +0 -352
  95. package/encryption/__tests__/note-encryption.spec.ts +0 -425
  96. package/encryption/encryption.ts +0 -264
  97. package/encryption/note-encryption.ts +0 -77
  98. package/files-api.ts +0 -25
  99. package/models/command.ts +0 -45
  100. package/models/completion.ts +0 -30
  101. package/models/default-commands.ts +0 -44
  102. package/models/editor.ts +0 -27
  103. package/models/encryption.ts +0 -50
  104. package/models/extension.ts +0 -45
  105. package/models/modal.ts +0 -12
  106. package/models/note.ts +0 -26
  107. package/models/theme-variables.ts +0 -194
  108. package/models/widget-type.ts +0 -5
  109. package/models/widget.ts +0 -59
  110. package/remote-api/.gitignore +0 -4
  111. package/remote-api/.npmignore +0 -1
  112. package/remote-api/.openapi-generator/FILES +0 -8
  113. package/remote-api/.openapi-generator/VERSION +0 -1
  114. package/remote-api/.openapi-generator-ignore +0 -23
  115. package/remote-api/git_push.sh +0 -57
  116. package/tools/__tests__/find-notes-files-diff.spec.ts +0 -176
  117. package/tools/__tests__/get-string-path.spec.ts +0 -32
  118. package/tools/__tests__/is-org-file.spec.ts +0 -62
  119. package/tools/find-notes-files-diff.ts +0 -48
  120. package/tools/get-string-path.ts +0 -6
  121. package/tools/index.ts +0 -3
  122. package/tools/is-gpg-encrypted.ts +0 -6
  123. package/tools/is-org-file.ts +0 -7
  124. package/tools/mock-server.ts +0 -16
  125. /package/{encryption/index.ts → dist/encryption/index.d.ts} +0 -0
  126. /package/{index.ts → dist/index.d.ts} +0 -0
@@ -0,0 +1,168 @@
1
+ import { mkdirSync, writeFileSync, utimesSync, readdirSync } from 'fs';
2
+ import { afterEach, beforeEach, test, expect } from 'vitest';
3
+ import { findNoteFilesDiff } from '../find-notes-files-diff';
4
+ import { statSync } from 'fs';
5
+ import { rmSync } from 'fs';
6
+ import { getFileName } from '../get-file-name';
7
+ import { join } from '../join';
8
+ const testFilesFolder = 'src/tools/__tests__/miscellaneous/';
9
+ const nestedFolder = 'nested-folder/';
10
+ const fn = (fileName) => `${testFilesFolder}${fileName}`;
11
+ const fns = (fileName) => `${testFilesFolder}${nestedFolder}${fileName}`;
12
+ function initFiles() {
13
+ mkdirSync(testFilesFolder.slice(0, -1));
14
+ mkdirSync(fn(nestedFolder));
15
+ }
16
+ function cleanFiles() {
17
+ try {
18
+ rmSync(testFilesFolder, { recursive: true });
19
+ }
20
+ catch (e) { }
21
+ }
22
+ function createTestFile(filePath, updated, content) {
23
+ writeFileSync(filePath, content);
24
+ const time = updated.getTime() / 1000; // Convert to seconds
25
+ utimesSync(filePath, time, time);
26
+ }
27
+ beforeEach(() => initFiles());
28
+ afterEach(() => cleanFiles());
29
+ const fileStatToFileInfo = (path, stat) => ({
30
+ path,
31
+ name: getFileName(path),
32
+ type: stat.isFile() ? 'file' : 'directory',
33
+ size: stat.size,
34
+ atime: stat.atime.getTime(),
35
+ mtime: stat.mtime.getTime(),
36
+ ctime: stat.ctime.getTime(),
37
+ });
38
+ test('Should sync notes files', async () => {
39
+ const files = [
40
+ [fn('file-1.org')],
41
+ [fn('file-2.org')],
42
+ [fn('file-9.org'), new Date('2024-10-10')],
43
+ [fns('file-3.org')],
44
+ [fns('file-4.org'), new Date('2024-08-09')],
45
+ ];
46
+ files.forEach(([f, d], i) => createTestFile(f, d ?? new Date('2024-01-01'), `:PROPERTIES:
47
+ :ID: ${i + 1}
48
+ :PROPERTIES:
49
+
50
+ * Hello world from note:
51
+ - ${f}`));
52
+ const storedNotesInfo = [
53
+ {
54
+ id: '2',
55
+ filePath: fn('file-1.org').split('/'),
56
+ updatedAt: new Date('2024-01-01'),
57
+ },
58
+ {
59
+ id: '3',
60
+ filePath: fns('file-3.org').split('/'),
61
+ updatedAt: new Date('2024-01-01'),
62
+ },
63
+ {
64
+ id: '9',
65
+ filePath: fn('file-9.org').split('/'),
66
+ updatedAt: new Date('2020-01-01'),
67
+ },
68
+ {
69
+ id: '10',
70
+ filePath: fns('file-10.org').split('/'),
71
+ updatedAt: new Date('2020-01-01'),
72
+ },
73
+ ];
74
+ const notesFilesDiff = await findNoteFilesDiff({
75
+ fileInfo: async (path) => {
76
+ const stats = statSync(path);
77
+ const fileInfo = fileStatToFileInfo(path, stats);
78
+ return Promise.resolve(fileInfo);
79
+ },
80
+ readDir: async (path) => {
81
+ const dirents = readdirSync(path, { withFileTypes: true });
82
+ const fileInfos = dirents.map((dirent) => {
83
+ const stats = statSync(join(path, dirent.name));
84
+ const fileInfo = fileStatToFileInfo(join(path, dirent.name), stats);
85
+ return fileInfo;
86
+ });
87
+ return Promise.resolve(fileInfos);
88
+ },
89
+ storedNotesInfo,
90
+ dirPath: testFilesFolder,
91
+ });
92
+ expect(notesFilesDiff).toMatchInlineSnapshot(`
93
+ {
94
+ "created": [
95
+ {
96
+ "filePath": "src/tools/__tests__/miscellaneous/file-2.org",
97
+ },
98
+ {
99
+ "filePath": "src/tools/__tests__/miscellaneous/nested-folder/file-4.org",
100
+ },
101
+ ],
102
+ "deleted": [
103
+ {
104
+ "filePath": "src/tools/__tests__/miscellaneous/nested-folder/file-10.org",
105
+ "id": "10",
106
+ },
107
+ ],
108
+ "updated": [
109
+ {
110
+ "filePath": "src/tools/__tests__/miscellaneous/file-9.org",
111
+ },
112
+ ],
113
+ }
114
+ `);
115
+ });
116
+ test('Should detect no changes when all files match stored info', async () => {
117
+ const files = [
118
+ [fn('file-1.org'), new Date('2024-01-01')],
119
+ [fn('file-2.org'), new Date('2024-01-01')],
120
+ [fns('file-3.org'), new Date('2024-01-01')],
121
+ ];
122
+ files.forEach(([f, d], i) => createTestFile(f, d ?? new Date('2024-01-01'), `:PROPERTIES:
123
+ :ID: ${i + 1}
124
+ :PROPERTIES:
125
+
126
+ * Note:
127
+ - ${f}`));
128
+ const storedNotesInfo = [
129
+ {
130
+ id: '1',
131
+ filePath: fn('file-1.org').split('/'),
132
+ updatedAt: new Date('2024-01-01'),
133
+ },
134
+ {
135
+ id: '2',
136
+ filePath: fn('file-2.org').split('/'),
137
+ updatedAt: new Date('2024-01-01'),
138
+ },
139
+ {
140
+ id: '3',
141
+ filePath: fns('file-3.org').split('/'),
142
+ updatedAt: new Date('2024-01-01'),
143
+ },
144
+ ];
145
+ const notesFilesDiff = await findNoteFilesDiff({
146
+ fileInfo: async (path) => {
147
+ const stats = statSync(path);
148
+ const fileInfo = fileStatToFileInfo(path, stats);
149
+ return Promise.resolve(fileInfo);
150
+ },
151
+ readDir: async (path) => {
152
+ const dirents = readdirSync(path, { withFileTypes: true });
153
+ const fileInfos = dirents.map((dirent) => {
154
+ const stats = statSync(join(path, dirent.name));
155
+ const fileInfo = fileStatToFileInfo(join(path, dirent.name), stats);
156
+ return fileInfo;
157
+ });
158
+ return Promise.resolve(fileInfos);
159
+ },
160
+ storedNotesInfo,
161
+ dirPath: testFilesFolder,
162
+ });
163
+ expect(notesFilesDiff).toEqual({
164
+ created: [],
165
+ updated: [],
166
+ deleted: [],
167
+ });
168
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { getFileName, getFileNameWithoutExtension } from '../get-file-name';
2
+ import { test, expect } from 'vitest';
3
+ test('Should return file name from path', () => {
4
+ expect(getFileName('/some/path/foo.org')).toBe('foo.org');
5
+ });
6
+ test('Should return file name from file name', () => {
7
+ expect(getFileName('foo.org')).toBe('foo.org');
8
+ });
9
+ test('Should return file name without extension', () => {
10
+ expect(getFileNameWithoutExtension('foo.org')).toBe('foo');
11
+ });
12
+ test('Should return file name without extension from path', () => {
13
+ expect(getFileNameWithoutExtension('/some/path/foo.org')).toBe('foo');
14
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ import { getStringPath } from '../get-string-path';
2
+ import { test, expect } from 'vitest';
3
+ test('should return the same string if path is a string', () => {
4
+ const path = 'some/path';
5
+ const result = getStringPath(path);
6
+ expect(result).toBe('some/path');
7
+ });
8
+ test('should join array elements with "/" if path is an array', () => {
9
+ const path = ['some', 'path'];
10
+ const result = getStringPath(path);
11
+ expect(result).toBe('some/path');
12
+ });
13
+ test('should return an empty string if path is an empty array', () => {
14
+ const path = [];
15
+ const result = getStringPath(path);
16
+ expect(result).toBe('');
17
+ });
18
+ test('should handle array with one element correctly', () => {
19
+ const path = ['single'];
20
+ const result = getStringPath(path);
21
+ expect(result).toBe('single');
22
+ });
23
+ test('should handle array with multiple elements correctly', () => {
24
+ const path = ['this', 'is', 'a', 'test'];
25
+ const result = getStringPath(path);
26
+ expect(result).toBe('this/is/a/test');
27
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -1,8 +1,7 @@
1
1
  import { expect, test } from 'vitest';
2
2
  import { isGpgEncrypted } from '../is-gpg-encrypted';
3
-
4
3
  test('Should return true if the content is gpg encrypted', () => {
5
- const content = `-----BEGIN PGP MESSAGE-----
4
+ const content = `-----BEGIN PGP MESSAGE-----
6
5
 
7
6
  wcFMA/vryg+TTn0rAQ//TBFRjKmjRQoLhSrgeH+NbsZXbxvo7Ey4k+BQ9XA5
8
7
  +CMpXH9uFUxsSaI5+McUSEt32VI17HRpXQDCL9nwaWqWOanMaRe0tXXhtox2
@@ -33,12 +32,9 @@ PX6alTbxGnoHgZ4bG4J1wfpTNPppP1gJeVg67VqOypzdZi+SjofMWnFgRFmD
33
32
  yEN8xpFUs7A9xryVZOosp9Sfe3IbBkO99sAQ7jV4EoMYk3/GKA==
34
33
  =LjkG
35
34
  -----END PGP MESSAGE-----`;
36
-
37
- expect(isGpgEncrypted(content)).toBe(true);
35
+ expect(isGpgEncrypted(content)).toBe(true);
38
36
  });
39
-
40
37
  test('Should return false if the content is not gpg encrypted', () => {
41
- const content = `Hello World!`;
42
-
43
- expect(isGpgEncrypted(content)).toBe(false);
38
+ const content = `Hello World!`;
39
+ expect(isGpgEncrypted(content)).toBe(false);
44
40
  });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,54 @@
1
+ import { test, expect } from 'vitest';
2
+ import { isOrgFile, isOrgGpgFile } from '../is-org-file';
3
+ test('Should return true for org files', () => {
4
+ const files = [
5
+ 'myNote.org',
6
+ 'my_note.org',
7
+ '123.org',
8
+ 'some_long_note#4123$123eqasdasd.org.gpg',
9
+ 'some_long_note#4123$123eqasdasd.org',
10
+ 'note with space.org',
11
+ 'note with space.org.gpg',
12
+ ];
13
+ files.forEach((file) => {
14
+ expect(isOrgFile(file), file).toBe(true);
15
+ });
16
+ });
17
+ test('Should not return true for non-org files', () => {
18
+ const files = [
19
+ 'myNote.md',
20
+ 'my_note.md',
21
+ '123.md',
22
+ 'some_long_note#4123$123eqasdas',
23
+ 'note.org.file',
24
+ 'org',
25
+ 'org.',
26
+ 'text.gpg',
27
+ ];
28
+ files.forEach((file) => {
29
+ expect(isOrgFile(file), file).toBe(false);
30
+ });
31
+ });
32
+ test('Should return true for org.gpg files', () => {
33
+ const gpgFiles = [
34
+ 'myNote.org.gpg',
35
+ 'my_note.org.gpg',
36
+ '123.org.gpg',
37
+ 'org.org.gpg',
38
+ 'gp_org.org.gpg',
39
+ ];
40
+ gpgFiles.forEach((file) => {
41
+ expect(isOrgGpgFile(file), file).toBe(true);
42
+ });
43
+ });
44
+ test('Should not return true for not .org.gpg files', () => {
45
+ const notGpgFiles = [
46
+ 'myNote.org',
47
+ 'my_note.org',
48
+ '123.org',
49
+ 'some_gpg_file.txt',
50
+ ];
51
+ notGpgFiles.forEach((file) => {
52
+ expect(isOrgGpgFile(file), file).toBe(false);
53
+ });
54
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { test, expect } from 'vitest';
2
+ import { join } from '../join';
3
+ test('Should join file paths', () => {
4
+ const samples = [
5
+ ['dir1', 'subdir2', 'file'],
6
+ ['dir2/', '/file'],
7
+ ['/dri3', 'subdir2/', 'file'],
8
+ ['file'],
9
+ ];
10
+ samples.forEach((sample) => {
11
+ const result = join(...sample);
12
+ expect(result).toMatchSnapshot();
13
+ });
14
+ });
@@ -0,0 +1,51 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { readOrgFilesRecursively } from '../find-notes-files-diff';
3
+ // NOTE: AI generated
4
+ const mockReadDir = vi.fn();
5
+ const mockFileInfo = vi.fn();
6
+ describe('readOrgFilesRecursively', () => {
7
+ it('should read .org files recursively from a directory', async () => {
8
+ const mockFileSystem = {
9
+ fileInfo: mockFileInfo,
10
+ readDir: mockReadDir,
11
+ dirPath: '/root',
12
+ };
13
+ // Set up fake file system structure
14
+ mockReadDir.mockImplementation(async (path) => {
15
+ switch (path) {
16
+ case '/root':
17
+ return [
18
+ { name: 'file1.org', type: 'file', size: 100, mtime: Date.now() },
19
+ { name: 'subdir', type: 'directory', size: 0, mtime: Date.now() },
20
+ { name: 'file2.txt', type: 'file', size: 200, mtime: Date.now() },
21
+ ];
22
+ case '/root/subdir':
23
+ return [
24
+ { name: 'file3.org', type: 'file', size: 100, mtime: Date.now() },
25
+ { name: 'file4.md', type: 'file', size: 150, mtime: Date.now() },
26
+ ];
27
+ default:
28
+ return [];
29
+ }
30
+ });
31
+ // Execute the function
32
+ const orgFiles = await readOrgFilesRecursively(mockFileSystem);
33
+ // Check results
34
+ expect(orgFiles).toEqual(['/root/file1.org', '/root/subdir/file3.org']);
35
+ expect(mockReadDir).toHaveBeenCalledTimes(2);
36
+ });
37
+ it('should return an empty array if no .org files are found', async () => {
38
+ const mockFileSystem = {
39
+ fileInfo: mockFileInfo,
40
+ readDir: mockReadDir,
41
+ dirPath: '/emptyDir',
42
+ };
43
+ // Set up fake file system structure with no .org files
44
+ mockReadDir.mockResolvedValue([]);
45
+ // Execute the function
46
+ const orgFiles = await readOrgFilesRecursively(mockFileSystem);
47
+ // Check results
48
+ expect(orgFiles).toEqual([]);
49
+ expect(mockReadDir).toHaveBeenCalledWith('/emptyDir');
50
+ });
51
+ });
@@ -0,0 +1,3 @@
1
+ import { HandlersSyncNotesRequest } from 'src/remote-api';
2
+ import { NoteChanges, FileSystem } from '../models';
3
+ export declare function extendNotesFilesDiff(changes: NoteChanges, readFile: FileSystem['readFile']): Promise<HandlersSyncNotesRequest>;
@@ -0,0 +1,21 @@
1
+ import { isOrgGpgFile } from './is-org-file';
2
+ export async function extendNotesFilesDiff(changes, readFile) {
3
+ const upsertedNotesFromLastSync = [
4
+ ...changes.updated,
5
+ ...changes.created,
6
+ ];
7
+ const notesFromLastSync = [];
8
+ for (const nc of upsertedNotesFromLastSync) {
9
+ const encrypted = isOrgGpgFile(nc.filePath);
10
+ }
11
+ const noteIdsFromLastSync = new Set(notesFromLastSync.map((n) => n.id));
12
+ const deletedNotesIdsWithoutRename = changes.deleted.reduce((acc, nc) => {
13
+ if (!noteIdsFromLastSync.has(nc.id)) {
14
+ acc.push(nc.id);
15
+ }
16
+ return acc;
17
+ }, []);
18
+ return {
19
+ deletedNotesIds: deletedNotesIdsWithoutRename,
20
+ };
21
+ }
@@ -0,0 +1,5 @@
1
+ import { SyncParams, Changes, StoredNoteInfo, NoteChanges, FileScanParams, FileSystem } from 'src/models';
2
+ export declare function findNoteFilesDiff({ fileInfo, readDir, lastSync, storedNotesInfo, dirPath, }: SyncParams): Promise<NoteChanges>;
3
+ export declare function getOrgFilesFromLastSync(filePaths: string[], fileInfo: FileSystem['fileInfo'], lastSync?: Date): Promise<string[]>;
4
+ export declare function readOrgFilesRecursively({ fileInfo, readDir, dirPath, }: FileScanParams): Promise<string[]>;
5
+ export declare function findFilesDiff(filePaths: string[], storedNotesInfo: StoredNoteInfo[], updatedTimeGetter: (filePath: string) => Date): Changes;
@@ -0,0 +1,108 @@
1
+ import { getStringPath } from './get-string-path';
2
+ import { isOrgFile } from './is-org-file';
3
+ import { join } from './join';
4
+ export async function findNoteFilesDiff({ fileInfo, readDir, lastSync, storedNotesInfo, dirPath, }) {
5
+ const orgFilePaths = await readOrgFilesRecursively({
6
+ fileInfo,
7
+ readDir,
8
+ dirPath,
9
+ });
10
+ const filesFromLastSync = await getOrgFilesFromLastSync(orgFilePaths, fileInfo, lastSync);
11
+ const deleted = findDeletedNotes(orgFilePaths, storedNotesInfo);
12
+ const [created, updated] = await findUpdatedCreatedNotes(fileInfo, filesFromLastSync, storedNotesInfo);
13
+ return {
14
+ deleted,
15
+ created,
16
+ updated,
17
+ };
18
+ }
19
+ export async function getOrgFilesFromLastSync(filePaths, fileInfo, lastSync) {
20
+ if (!lastSync) {
21
+ return filePaths;
22
+ }
23
+ return Promise.all(filePaths.filter(async (filePath) => {
24
+ const stats = await fileInfo(filePath);
25
+ return (new Date(stats.mtime) > lastSync || new Date(stats.ctime) > lastSync);
26
+ }));
27
+ }
28
+ function findDeletedNotes(filePaths, storedNotesInfo) {
29
+ const uniqueFilePaths = new Set(filePaths);
30
+ return storedNotesInfo.reduce((acc, storedNote) => {
31
+ const storedNotePath = getStringPath(storedNote.filePath);
32
+ if (uniqueFilePaths.has(storedNotePath)) {
33
+ return acc;
34
+ }
35
+ acc.push({
36
+ filePath: storedNotePath,
37
+ id: storedNote.id,
38
+ });
39
+ return acc;
40
+ }, []);
41
+ }
42
+ async function findUpdatedCreatedNotes(fileInfo, orgFilePaths, storedNotesInfo) {
43
+ const created = [];
44
+ const updated = [];
45
+ const storedNotesInfoMap = getStoredNotesInfoMap(storedNotesInfo);
46
+ for (const f of orgFilePaths) {
47
+ const found = storedNotesInfoMap[f];
48
+ if (!found) {
49
+ created.push({ filePath: f });
50
+ continue;
51
+ }
52
+ const fileUpdatedTime = new Date((await fileInfo(f))?.mtime);
53
+ if (found.updatedAt < fileUpdatedTime) {
54
+ updated.push({ filePath: f });
55
+ }
56
+ }
57
+ return [created, updated];
58
+ }
59
+ function getStoredNotesInfoMap(storedNotesInfo) {
60
+ return storedNotesInfo.reduce((acc, n) => {
61
+ acc[getStringPath(n.filePath)] = n;
62
+ return acc;
63
+ }, {});
64
+ }
65
+ export async function readOrgFilesRecursively({ fileInfo, readDir, dirPath, }) {
66
+ const files = await readDir(dirPath);
67
+ const collectedPaths = [];
68
+ const getFullPath = (p) => join(dirPath, p);
69
+ for (const f of files) {
70
+ if (f.type === 'directory') {
71
+ const subDirFiles = await readOrgFilesRecursively({
72
+ fileInfo,
73
+ readDir,
74
+ dirPath: getFullPath(f.name),
75
+ });
76
+ collectedPaths.push(...subDirFiles);
77
+ continue;
78
+ }
79
+ if (!isOrgFile(f.name)) {
80
+ continue;
81
+ }
82
+ collectedPaths.push(getFullPath(f.name));
83
+ }
84
+ return collectedPaths;
85
+ }
86
+ export function findFilesDiff(filePaths, storedNotesInfo, updatedTimeGetter) {
87
+ const existingFilePaths = new Set(filePaths);
88
+ const storedNotesPathSet = new Set(storedNotesInfo.map((n) => getStringPath(n.filePath)));
89
+ const changedFiles = { deleted: [], created: [], updated: [] };
90
+ storedNotesInfo.forEach((storedNote) => {
91
+ const fullPath = getStringPath(storedNote.filePath);
92
+ if (!existingFilePaths.has(fullPath)) {
93
+ changedFiles.deleted.push(fullPath);
94
+ return;
95
+ }
96
+ const updatedTime = updatedTimeGetter(fullPath);
97
+ if (updatedTime > new Date(storedNote.updatedAt)) {
98
+ changedFiles.updated.push(fullPath);
99
+ }
100
+ });
101
+ filePaths.forEach((filePath) => {
102
+ if (!storedNotesPathSet.has(filePath)) {
103
+ changedFiles.created.push(filePath);
104
+ return;
105
+ }
106
+ });
107
+ return changedFiles;
108
+ }
@@ -0,0 +1,2 @@
1
+ export declare const getFileName: (path: string) => string;
2
+ export declare const getFileNameWithoutExtension: (path: string) => string;
@@ -0,0 +1,6 @@
1
+ export const getFileName = (path) => {
2
+ return path.split('/').pop();
3
+ };
4
+ export const getFileNameWithoutExtension = (path) => {
5
+ return getFileName(path).split('.').shift();
6
+ };
@@ -0,0 +1 @@
1
+ export declare function getStringPath(path: string | string[]): string;
@@ -0,0 +1,6 @@
1
+ export function getStringPath(path) {
2
+ if (Array.isArray(path)) {
3
+ return `${path.join('/')}`;
4
+ }
5
+ return path;
6
+ }
@@ -0,0 +1,6 @@
1
+ export * from './mock-server';
2
+ export * from './is-gpg-encrypted';
3
+ export * from './is-org-file';
4
+ export * from './get-string-path';
5
+ export * from './find-notes-files-diff';
6
+ export * from './join';
@@ -0,0 +1,6 @@
1
+ export * from './mock-server';
2
+ export * from './is-gpg-encrypted';
3
+ export * from './is-org-file';
4
+ export * from './get-string-path';
5
+ export * from './find-notes-files-diff';
6
+ export * from './join';
@@ -0,0 +1 @@
1
+ export declare function isGpgEncrypted(text: string | Uint8Array): boolean;
@@ -0,0 +1,6 @@
1
+ export function isGpgEncrypted(text) {
2
+ if (text instanceof Uint8Array) {
3
+ return true;
4
+ }
5
+ return text.startsWith('-----BEGIN PGP MESSAGE-----');
6
+ }
@@ -0,0 +1,2 @@
1
+ export declare const isOrgFile: (fileName: string) => boolean;
2
+ export declare const isOrgGpgFile: (fileName: string) => boolean;
@@ -0,0 +1,4 @@
1
+ const orgFileExtenstionRegex = /\.org(\.gpg)?$/;
2
+ export const isOrgFile = (fileName) => orgFileExtenstionRegex.test(fileName);
3
+ const orgGpgFileExtenstionRegex = /\.org\.gpg$/;
4
+ export const isOrgGpgFile = (fileName) => orgGpgFileExtenstionRegex.test(fileName);
@@ -0,0 +1 @@
1
+ export declare function join(...path: string[]): string;
@@ -0,0 +1,3 @@
1
+ export function join(...path) {
2
+ return path.join('/').replace(/\/+/g, '/').replace(/\/+$/, '');
3
+ }
@@ -0,0 +1 @@
1
+ export declare const mockServer: <T extends (...params: any[]) => any>(fn?: T, defaultValue?: ReturnType<T>) => (...params: Parameters<T>) => ReturnType<T>;
@@ -0,0 +1,12 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ export const mockServer = (fn, defaultValue) => {
3
+ if (!fn) {
4
+ return (() => { });
5
+ }
6
+ return (...params) => {
7
+ if (process.env.CLIENT) {
8
+ return fn(...params);
9
+ }
10
+ return defaultValue;
11
+ };
12
+ };
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "orgnote-api",
3
- "version": "0.17.0",
3
+ "version": "0.17.2",
4
4
  "description": "Official API for creating extensions for OrgNote app",
5
5
  "type": "module",
6
- "main": "./index.ts",
6
+ "main": "./dist/index.js",
7
7
  "scripts": {
8
8
  "test": "vitest",
9
9
  "build": "npm run clear && tsc --project tsconfig.json",
@@ -17,19 +17,11 @@
17
17
  "type": "git",
18
18
  "url": "git+https://github.com/artawower/orgnote-api.git"
19
19
  },
20
- "files": [
21
- "index.ts",
22
- "api.ts",
23
- "files-api.ts",
24
- "remote-api/**",
25
- "models/**",
26
- "encryption/**",
27
- "tools/**"
28
- ],
20
+ "files": ["dist/**"],
29
21
  "exports": {
30
- ".": "./index.ts",
31
- "./remote-api": "./remote-api/index.ts",
32
- "./encryption": "./encryption/index.ts"
22
+ ".": "./dist/index.js",
23
+ "./remote-api": "./dist/remote-api/index.js",
24
+ "./encryption": "./dist/encryption/index.js"
33
25
  },
34
26
  "keywords": ["orgnote", "org-mode", "org-roam", "api", "extensions"],
35
27
  "author": "darkawower <app.orgnote@gmail.com> (https://org-note.com)",