@puredesktop/puredesktop-ui-bridge 2.1.0 → 2.1.1
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/package.json +3 -1
- package/src/bridge/dialog.d.mts +8 -5
- package/src/bridge/dialog.mjs +40 -10
- package/src/bridge/dialog.test.ts +73 -0
- package/src/bridge/fs.d.mts +41 -15
- package/src/bridge/fs.mjs +56 -12
- package/src/bridge/fs.test.ts +82 -8
- package/src/bridge/fs.ts +28 -10
- package/src/bridge/network.d.mts +17 -0
- package/src/bridge/network.mjs +22 -0
- package/src/bridge/storage.d.mts +27 -0
- package/src/bridge/storage.mjs +18 -0
- package/src/bridge/storage.test.ts +49 -0
- package/src/bridge/types.ts +58 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@puredesktop/puredesktop-ui-bridge",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "PureScience plugin SDK — bridge client, theme, and shared UI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
"./bridge/client": "./src/bridge/client.mjs",
|
|
21
21
|
"./bridge/events": "./src/bridge/events.mjs",
|
|
22
22
|
"./bridge/methods": "./src/bridge/methods.mjs",
|
|
23
|
+
"./bridge/network": "./src/bridge/network.mjs",
|
|
24
|
+
"./bridge/storage": "./src/bridge/storage.mjs",
|
|
23
25
|
"./bridge/vision": "./src/bridge/vision.mjs",
|
|
24
26
|
"./bridge/react/usePlatformBridge": "./src/bridge/react/usePlatformBridge.tsx",
|
|
25
27
|
"./bridge/react/useIpc": "./src/bridge/react/useIpc.tsx",
|
package/src/bridge/dialog.d.mts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
export interface PlatformDialogPathResult {
|
|
2
|
-
path: string | null
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export declare function
|
|
1
|
+
export interface PlatformDialogPathResult {
|
|
2
|
+
path: string | null
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export declare function openPlatformFolderDialog(): Promise<string | null>
|
|
6
|
+
export declare function savePlatformFolderDialog(): Promise<string | null>
|
|
7
|
+
export declare function openPlatformImageDialog(): Promise<string | null>
|
|
8
|
+
export declare function openPlatformFileDialog(): Promise<string | null>
|
package/src/bridge/dialog.mjs
CHANGED
|
@@ -1,13 +1,43 @@
|
|
|
1
|
-
import { bridge } from './client.mjs'
|
|
2
|
-
import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @returns {Promise<string | null>} Absolute path to the picked
|
|
6
|
-
*/
|
|
7
|
-
export async function
|
|
1
|
+
import { bridge } from './client.mjs'
|
|
2
|
+
import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @returns {Promise<string | null>} Absolute path to the picked folder, or null if cancelled.
|
|
6
|
+
*/
|
|
7
|
+
export async function openPlatformFolderDialog() {
|
|
8
|
+
const result = await bridge.call(
|
|
9
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FOLDER,
|
|
10
|
+
[],
|
|
11
|
+
)
|
|
12
|
+
return result?.path ?? null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @returns {Promise<string | null>} Absolute path to the picked parent folder, or null if cancelled.
|
|
17
|
+
*/
|
|
18
|
+
export async function savePlatformFolderDialog() {
|
|
19
|
+
const result = await bridge.call(
|
|
20
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_SAVE_FOLDER,
|
|
21
|
+
[],
|
|
22
|
+
)
|
|
23
|
+
return result?.path ?? null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @returns {Promise<string | null>} Absolute path to the picked image, or null if cancelled.
|
|
28
|
+
*/
|
|
29
|
+
export async function openPlatformImageDialog() {
|
|
8
30
|
const result = await bridge.call(
|
|
9
31
|
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_IMAGE,
|
|
10
32
|
[],
|
|
11
|
-
)
|
|
12
|
-
return result?.path ?? null
|
|
13
|
-
}
|
|
33
|
+
)
|
|
34
|
+
return result?.path ?? null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @returns {Promise<string | null>} Absolute path to the picked file, or null if cancelled.
|
|
39
|
+
*/
|
|
40
|
+
export async function openPlatformFileDialog() {
|
|
41
|
+
const result = await bridge.call(PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FILE, [])
|
|
42
|
+
return result?.path ?? null
|
|
43
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
3
|
+
|
|
4
|
+
const bridgeCall = vi.hoisted(() => vi.fn())
|
|
5
|
+
|
|
6
|
+
vi.mock('./client.mjs', () => ({
|
|
7
|
+
bridge: {
|
|
8
|
+
call: bridgeCall,
|
|
9
|
+
},
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
openPlatformFileDialog,
|
|
14
|
+
openPlatformFolderDialog,
|
|
15
|
+
openPlatformImageDialog,
|
|
16
|
+
savePlatformFolderDialog,
|
|
17
|
+
} from './dialog.mjs'
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
bridgeCall.mockReset()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('dialog bridge helpers', () => {
|
|
24
|
+
it('opens a folder dialog using the shell method with no arguments', async () => {
|
|
25
|
+
bridgeCall.mockResolvedValue({ path: '/tmp' })
|
|
26
|
+
|
|
27
|
+
await expect(openPlatformFolderDialog()).resolves.toBe('/tmp')
|
|
28
|
+
|
|
29
|
+
expect(bridgeCall).toHaveBeenCalledWith(
|
|
30
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FOLDER,
|
|
31
|
+
[],
|
|
32
|
+
)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('opens a save folder dialog using the shell method with no arguments', async () => {
|
|
36
|
+
bridgeCall.mockResolvedValue({ path: '/tmp/project' })
|
|
37
|
+
|
|
38
|
+
await expect(savePlatformFolderDialog()).resolves.toBe('/tmp/project')
|
|
39
|
+
|
|
40
|
+
expect(bridgeCall).toHaveBeenCalledWith(
|
|
41
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_SAVE_FOLDER,
|
|
42
|
+
[],
|
|
43
|
+
)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('opens an image dialog using the shell method with no arguments', async () => {
|
|
47
|
+
bridgeCall.mockResolvedValue({ path: '/tmp/image.png' })
|
|
48
|
+
|
|
49
|
+
await expect(openPlatformImageDialog()).resolves.toBe('/tmp/image.png')
|
|
50
|
+
|
|
51
|
+
expect(bridgeCall).toHaveBeenCalledWith(
|
|
52
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_IMAGE,
|
|
53
|
+
[],
|
|
54
|
+
)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('opens a file dialog using the shell method with no arguments', async () => {
|
|
58
|
+
bridgeCall.mockResolvedValue({ path: '/tmp/file.md' })
|
|
59
|
+
|
|
60
|
+
await expect(openPlatformFileDialog()).resolves.toBe('/tmp/file.md')
|
|
61
|
+
|
|
62
|
+
expect(bridgeCall).toHaveBeenCalledWith(
|
|
63
|
+
PLATFORM_BRIDGE_METHODS.DIALOG_OPEN_FILE,
|
|
64
|
+
[],
|
|
65
|
+
)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('returns null when the shell dialog is cancelled', async () => {
|
|
69
|
+
bridgeCall.mockResolvedValue({ path: null })
|
|
70
|
+
|
|
71
|
+
await expect(openPlatformFolderDialog()).resolves.toBeNull()
|
|
72
|
+
})
|
|
73
|
+
})
|
package/src/bridge/fs.d.mts
CHANGED
|
@@ -1,15 +1,31 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import type {
|
|
2
|
+
PlatformFileCreateFolderResult,
|
|
3
|
+
PlatformFileDeleteResult,
|
|
4
|
+
PlatformFileListResult,
|
|
5
|
+
PlatformFilePreviewUrlResult,
|
|
6
|
+
PlatformFileReadBinaryResult,
|
|
7
|
+
PlatformFileReadPreviewResult,
|
|
8
|
+
PlatformFileRenameResult,
|
|
9
|
+
PlatformFileWriteResult,
|
|
10
|
+
} from './types.js'
|
|
6
11
|
|
|
7
|
-
export declare const PLATFORM_FILE_TEXT_PREVIEW_MAX_BYTES: number
|
|
8
|
-
export declare const PLATFORM_FILE_BINARY_PREVIEW_MAX_BYTES: number
|
|
9
|
-
|
|
10
|
-
export declare function
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
export declare const PLATFORM_FILE_TEXT_PREVIEW_MAX_BYTES: number
|
|
13
|
+
export declare const PLATFORM_FILE_BINARY_PREVIEW_MAX_BYTES: number
|
|
14
|
+
|
|
15
|
+
export declare function listPlatformFiles(
|
|
16
|
+
rootPath: string,
|
|
17
|
+
): Promise<PlatformFileListResult>
|
|
18
|
+
|
|
19
|
+
export declare function readPlatformTextFile(path: string): Promise<string>
|
|
20
|
+
|
|
21
|
+
export declare function writePlatformTextFile(
|
|
22
|
+
path: string,
|
|
23
|
+
content: string,
|
|
24
|
+
): Promise<PlatformFileWriteResult>
|
|
25
|
+
|
|
26
|
+
export declare function readPlatformFilePreview(
|
|
27
|
+
path: string,
|
|
28
|
+
maxBytes?: number,
|
|
13
29
|
): Promise<PlatformFileReadPreviewResult>
|
|
14
30
|
|
|
15
31
|
export declare function readPlatformFileBinary(
|
|
@@ -35,7 +51,17 @@ export declare function writePlatformFileBinary(
|
|
|
35
51
|
base64: string,
|
|
36
52
|
): Promise<{ ok: true }>
|
|
37
53
|
|
|
38
|
-
export declare function createPlatformFolder(
|
|
39
|
-
parentPath: string,
|
|
40
|
-
name: string,
|
|
41
|
-
): Promise<
|
|
54
|
+
export declare function createPlatformFolder(
|
|
55
|
+
parentPath: string,
|
|
56
|
+
name: string,
|
|
57
|
+
): Promise<PlatformFileCreateFolderResult>
|
|
58
|
+
|
|
59
|
+
export declare function renamePlatformFile(
|
|
60
|
+
path: string,
|
|
61
|
+
name: string,
|
|
62
|
+
): Promise<PlatformFileRenameResult>
|
|
63
|
+
|
|
64
|
+
export declare function deletePlatformFile(
|
|
65
|
+
path: string,
|
|
66
|
+
recursive?: boolean,
|
|
67
|
+
): Promise<PlatformFileDeleteResult>
|
package/src/bridge/fs.mjs
CHANGED
|
@@ -5,13 +5,38 @@ import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
|
5
5
|
export const PLATFORM_FILE_TEXT_PREVIEW_MAX_BYTES = 64 * 1024
|
|
6
6
|
|
|
7
7
|
/** Default binary preview cap for legacy inline image reads. Prefer `fs.previewUrl`. */
|
|
8
|
-
export const PLATFORM_FILE_BINARY_PREVIEW_MAX_BYTES = 5 * 1024 * 1024
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @param {string}
|
|
12
|
-
* @returns {Promise<import('./types.ts').
|
|
13
|
-
*/
|
|
14
|
-
export async function
|
|
8
|
+
export const PLATFORM_FILE_BINARY_PREVIEW_MAX_BYTES = 5 * 1024 * 1024
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} rootPath
|
|
12
|
+
* @returns {Promise<import('./types.ts').PlatformFileListResult>}
|
|
13
|
+
*/
|
|
14
|
+
export async function listPlatformFiles(rootPath) {
|
|
15
|
+
return bridge.call(PLATFORM_BRIDGE_METHODS.FS_LIST, [{ rootPath }])
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} path
|
|
20
|
+
* @returns {Promise<string>}
|
|
21
|
+
*/
|
|
22
|
+
export async function readPlatformTextFile(path) {
|
|
23
|
+
return bridge.call(PLATFORM_BRIDGE_METHODS.FS_READ, [path])
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {string} path
|
|
28
|
+
* @param {string} content
|
|
29
|
+
* @returns {Promise<import('./types.ts').PlatformFileWriteResult>}
|
|
30
|
+
*/
|
|
31
|
+
export async function writePlatformTextFile(path, content) {
|
|
32
|
+
return bridge.call(PLATFORM_BRIDGE_METHODS.FS_WRITE, [path, content])
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {string} path
|
|
37
|
+
* @returns {Promise<import('./types.ts').PlatformFilePreviewUrlResult>}
|
|
38
|
+
*/
|
|
39
|
+
export async function readPlatformFilePreviewUrl(path) {
|
|
15
40
|
return bridge.call(PLATFORM_BRIDGE_METHODS.FS_PREVIEW_URL, [{ path }])
|
|
16
41
|
}
|
|
17
42
|
|
|
@@ -75,8 +100,27 @@ export async function writePlatformFileBinary(path, base64) {
|
|
|
75
100
|
* @param {string} name
|
|
76
101
|
* @returns {Promise<{ path: string }>}
|
|
77
102
|
*/
|
|
78
|
-
export async function createPlatformFolder(parentPath, name) {
|
|
79
|
-
return bridge.call(PLATFORM_BRIDGE_METHODS.FS_CREATE_FOLDER, [
|
|
80
|
-
{ parentPath, name },
|
|
81
|
-
])
|
|
82
|
-
}
|
|
103
|
+
export async function createPlatformFolder(parentPath, name) {
|
|
104
|
+
return bridge.call(PLATFORM_BRIDGE_METHODS.FS_CREATE_FOLDER, [
|
|
105
|
+
{ parentPath, name },
|
|
106
|
+
])
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @param {string} path
|
|
111
|
+
* @param {string} name
|
|
112
|
+
* @returns {Promise<import('./types.ts').PlatformFileRenameResult>}
|
|
113
|
+
*/
|
|
114
|
+
export async function renamePlatformFile(path, name) {
|
|
115
|
+
return bridge.call(PLATFORM_BRIDGE_METHODS.FS_RENAME, [{ path, name }])
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @param {string} path
|
|
120
|
+
* @param {boolean | undefined} recursive
|
|
121
|
+
* @returns {Promise<import('./types.ts').PlatformFileDeleteResult>}
|
|
122
|
+
*/
|
|
123
|
+
export async function deletePlatformFile(path, recursive) {
|
|
124
|
+
const request = recursive === undefined ? { path } : { path, recursive }
|
|
125
|
+
return bridge.call(PLATFORM_BRIDGE_METHODS.FS_DELETE, [request])
|
|
126
|
+
}
|
package/src/bridge/fs.test.ts
CHANGED
|
@@ -1,9 +1,30 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
3
|
+
|
|
4
|
+
const bridgeCall = vi.hoisted(() => vi.fn())
|
|
5
|
+
|
|
6
|
+
vi.mock('./client.mjs', () => ({
|
|
7
|
+
bridge: {
|
|
8
|
+
call: bridgeCall,
|
|
9
|
+
},
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
dataUrlFromFileBinary,
|
|
14
|
+
deletePlatformFile,
|
|
15
|
+
listPlatformFiles,
|
|
16
|
+
readPlatformTextFile,
|
|
17
|
+
renamePlatformFile,
|
|
18
|
+
writePlatformTextFile,
|
|
19
|
+
} from './fs.mjs'
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
bridgeCall.mockReset()
|
|
23
|
+
})
|
|
3
24
|
|
|
4
|
-
describe('dataUrlFromFileBinary', () => {
|
|
5
|
-
it('builds a data URL from bridge binary result', () => {
|
|
6
|
-
expect(
|
|
25
|
+
describe('dataUrlFromFileBinary', () => {
|
|
26
|
+
it('builds a data URL from bridge binary result', () => {
|
|
27
|
+
expect(
|
|
7
28
|
dataUrlFromFileBinary({
|
|
8
29
|
path: '/tmp/image.png',
|
|
9
30
|
mimeType: 'image/png',
|
|
@@ -11,6 +32,59 @@ describe('dataUrlFromFileBinary', () => {
|
|
|
11
32
|
truncated: false,
|
|
12
33
|
byteLength: 3,
|
|
13
34
|
}),
|
|
14
|
-
).toBe('data:image/png;base64,abc123')
|
|
15
|
-
})
|
|
16
|
-
})
|
|
35
|
+
).toBe('data:image/png;base64,abc123')
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
describe('filesystem bridge helpers', () => {
|
|
40
|
+
it('lists files using the shell request object shape', async () => {
|
|
41
|
+
bridgeCall.mockResolvedValue({ entries: [] })
|
|
42
|
+
|
|
43
|
+
await listPlatformFiles('/tmp')
|
|
44
|
+
|
|
45
|
+
expect(bridgeCall).toHaveBeenCalledWith(PLATFORM_BRIDGE_METHODS.FS_LIST, [
|
|
46
|
+
{ rootPath: '/tmp' },
|
|
47
|
+
])
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('reads text files using the shell path argument shape', async () => {
|
|
51
|
+
bridgeCall.mockResolvedValue('hello')
|
|
52
|
+
|
|
53
|
+
await readPlatformTextFile('/tmp/a.md')
|
|
54
|
+
|
|
55
|
+
expect(bridgeCall).toHaveBeenCalledWith(PLATFORM_BRIDGE_METHODS.FS_READ, [
|
|
56
|
+
'/tmp/a.md',
|
|
57
|
+
])
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('writes text files using the shell path and content argument shape', async () => {
|
|
61
|
+
bridgeCall.mockResolvedValue({ ok: true })
|
|
62
|
+
|
|
63
|
+
await writePlatformTextFile('/tmp/a.md', 'hello')
|
|
64
|
+
|
|
65
|
+
expect(bridgeCall).toHaveBeenCalledWith(PLATFORM_BRIDGE_METHODS.FS_WRITE, [
|
|
66
|
+
'/tmp/a.md',
|
|
67
|
+
'hello',
|
|
68
|
+
])
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('renames files using the shell request object shape', async () => {
|
|
72
|
+
bridgeCall.mockResolvedValue({ path: '/tmp/b.md' })
|
|
73
|
+
|
|
74
|
+
await renamePlatformFile('/tmp/a.md', 'b.md')
|
|
75
|
+
|
|
76
|
+
expect(bridgeCall).toHaveBeenCalledWith(PLATFORM_BRIDGE_METHODS.FS_RENAME, [
|
|
77
|
+
{ path: '/tmp/a.md', name: 'b.md' },
|
|
78
|
+
])
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('deletes files using the shell request object shape', async () => {
|
|
82
|
+
bridgeCall.mockResolvedValue({ ok: true })
|
|
83
|
+
|
|
84
|
+
await deletePlatformFile('/tmp/a.md', true)
|
|
85
|
+
|
|
86
|
+
expect(bridgeCall).toHaveBeenCalledWith(PLATFORM_BRIDGE_METHODS.FS_DELETE, [
|
|
87
|
+
{ path: '/tmp/a.md', recursive: true },
|
|
88
|
+
])
|
|
89
|
+
})
|
|
90
|
+
})
|
package/src/bridge/fs.ts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
|
-
export {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
export {
|
|
2
|
+
createPlatformFolder,
|
|
3
|
+
dataUrlFromFileBinary,
|
|
4
|
+
deletePlatformFile,
|
|
5
|
+
listPlatformFiles,
|
|
6
|
+
readPlatformFileBinary,
|
|
7
|
+
readPlatformFileBinaryDataUrl,
|
|
8
|
+
readPlatformFilePreview,
|
|
9
|
+
readPlatformFilePreviewUrl,
|
|
10
|
+
readPlatformTextFile,
|
|
11
|
+
renamePlatformFile,
|
|
12
|
+
writePlatformFileBinary,
|
|
13
|
+
writePlatformTextFile,
|
|
14
|
+
PLATFORM_FILE_BINARY_PREVIEW_MAX_BYTES,
|
|
15
|
+
PLATFORM_FILE_TEXT_PREVIEW_MAX_BYTES,
|
|
16
|
+
} from './fs.mjs'
|
|
17
|
+
|
|
18
|
+
export type {
|
|
19
|
+
PlatformFileCreateFolderResult,
|
|
20
|
+
PlatformFileDeleteResult,
|
|
21
|
+
PlatformFileEntry,
|
|
22
|
+
PlatformFileListResult,
|
|
23
|
+
PlatformFilePreviewUrlResult,
|
|
24
|
+
PlatformFileReadBinaryResult,
|
|
25
|
+
PlatformFileReadPreviewResult,
|
|
26
|
+
PlatformFileRenameResult,
|
|
27
|
+
PlatformFileWriteResult,
|
|
28
|
+
} from './types.js'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface PlatformNetworkFetchRequest {
|
|
2
|
+
url: string
|
|
3
|
+
method?: string
|
|
4
|
+
headers?: Record<string, string>
|
|
5
|
+
body?: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface PlatformNetworkFetchResponse {
|
|
9
|
+
status: number
|
|
10
|
+
ok: boolean
|
|
11
|
+
headers: Record<string, string>
|
|
12
|
+
body: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export declare function networkFetch(
|
|
16
|
+
request: PlatformNetworkFetchRequest,
|
|
17
|
+
): Promise<PlatformNetworkFetchResponse>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { bridge } from './client.mjs'
|
|
2
|
+
import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fetch an HTTP(S) resource through the shell network bridge.
|
|
6
|
+
*
|
|
7
|
+
* @param {{
|
|
8
|
+
* url: string,
|
|
9
|
+
* method?: string,
|
|
10
|
+
* headers?: Record<string, string>,
|
|
11
|
+
* body?: string,
|
|
12
|
+
* }} request
|
|
13
|
+
* @returns {Promise<{
|
|
14
|
+
* status: number,
|
|
15
|
+
* ok: boolean,
|
|
16
|
+
* headers: Record<string, string>,
|
|
17
|
+
* body: string,
|
|
18
|
+
* }>}
|
|
19
|
+
*/
|
|
20
|
+
export async function networkFetch(request) {
|
|
21
|
+
return bridge.call(PLATFORM_BRIDGE_METHODS.NETWORK_FETCH, [request])
|
|
22
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface PlatformStorageJsonRequest {
|
|
2
|
+
appSlug: string
|
|
3
|
+
fileName: string
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface PlatformStorageJsonReadResult {
|
|
7
|
+
path: string
|
|
8
|
+
value: unknown | null
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface PlatformStorageJsonWriteRequest
|
|
12
|
+
extends PlatformStorageJsonRequest {
|
|
13
|
+
value: unknown
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface PlatformStorageJsonWriteResult {
|
|
17
|
+
path: string
|
|
18
|
+
ok: true
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export declare function readPlatformStorageJson(
|
|
22
|
+
request: PlatformStorageJsonRequest,
|
|
23
|
+
): Promise<PlatformStorageJsonReadResult>
|
|
24
|
+
|
|
25
|
+
export declare function writePlatformStorageJson(
|
|
26
|
+
request: PlatformStorageJsonWriteRequest,
|
|
27
|
+
): Promise<PlatformStorageJsonWriteResult>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { bridge } from './client.mjs'
|
|
2
|
+
import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {{ appSlug: string, fileName: string }} request
|
|
6
|
+
* @returns {Promise<{ path: string, value: unknown | null }>}
|
|
7
|
+
*/
|
|
8
|
+
export async function readPlatformStorageJson(request) {
|
|
9
|
+
return bridge.call(PLATFORM_BRIDGE_METHODS.STORAGE_READ_JSON, [request])
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {{ appSlug: string, fileName: string, value: unknown }} request
|
|
14
|
+
* @returns {Promise<{ path: string, ok: true }>}
|
|
15
|
+
*/
|
|
16
|
+
export async function writePlatformStorageJson(request) {
|
|
17
|
+
return bridge.call(PLATFORM_BRIDGE_METHODS.STORAGE_WRITE_JSON, [request])
|
|
18
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { PLATFORM_BRIDGE_METHODS } from './methods.mjs'
|
|
3
|
+
|
|
4
|
+
const bridgeCall = vi.hoisted(() => vi.fn())
|
|
5
|
+
|
|
6
|
+
vi.mock('./client.mjs', () => ({
|
|
7
|
+
bridge: {
|
|
8
|
+
call: bridgeCall,
|
|
9
|
+
},
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
readPlatformStorageJson,
|
|
14
|
+
writePlatformStorageJson,
|
|
15
|
+
} from './storage.mjs'
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
bridgeCall.mockReset()
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
describe('storage bridge helpers', () => {
|
|
22
|
+
it('reads JSON storage using the shell request object shape', async () => {
|
|
23
|
+
const request = { appSlug: 'puretasks', fileName: 'tasks.json' }
|
|
24
|
+
bridgeCall.mockResolvedValue({ path: '/tmp/tasks.json', value: null })
|
|
25
|
+
|
|
26
|
+
await readPlatformStorageJson(request)
|
|
27
|
+
|
|
28
|
+
expect(bridgeCall).toHaveBeenCalledWith(
|
|
29
|
+
PLATFORM_BRIDGE_METHODS.STORAGE_READ_JSON,
|
|
30
|
+
[request],
|
|
31
|
+
)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('writes JSON storage using the shell request object shape', async () => {
|
|
35
|
+
const request = {
|
|
36
|
+
appSlug: 'puretasks',
|
|
37
|
+
fileName: 'tasks.json',
|
|
38
|
+
value: { tasks: [] },
|
|
39
|
+
}
|
|
40
|
+
bridgeCall.mockResolvedValue({ path: '/tmp/tasks.json', ok: true })
|
|
41
|
+
|
|
42
|
+
await writePlatformStorageJson(request)
|
|
43
|
+
|
|
44
|
+
expect(bridgeCall).toHaveBeenCalledWith(
|
|
45
|
+
PLATFORM_BRIDGE_METHODS.STORAGE_WRITE_JSON,
|
|
46
|
+
[request],
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
})
|
package/src/bridge/types.ts
CHANGED
|
@@ -255,31 +255,64 @@ export interface PlatformAppInstallState {
|
|
|
255
255
|
pluginRoot?: string
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
-
export interface PlatformFileReadPreviewResult {
|
|
259
|
-
path: string
|
|
260
|
-
content: string | null
|
|
261
|
-
truncated: boolean
|
|
262
|
-
encoding: 'utf-8'
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
export interface
|
|
266
|
-
path: string
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
258
|
+
export interface PlatformFileReadPreviewResult {
|
|
259
|
+
path: string
|
|
260
|
+
content: string | null
|
|
261
|
+
truncated: boolean
|
|
262
|
+
encoding: 'utf-8'
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export interface PlatformFileEntry {
|
|
266
|
+
path: string
|
|
267
|
+
name: string
|
|
268
|
+
extension: string
|
|
269
|
+
kind: PlatformFileKind
|
|
270
|
+
mimeType: string
|
|
271
|
+
byteLength: number
|
|
272
|
+
modifiedAt: string
|
|
273
|
+
isDirectory: boolean
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export interface PlatformFileListResult {
|
|
277
|
+
rootPath: string
|
|
278
|
+
parentPath: string | null
|
|
279
|
+
entries: PlatformFileEntry[]
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export interface PlatformFileReadBinaryResult {
|
|
283
|
+
path: string
|
|
284
|
+
mimeType: string
|
|
285
|
+
base64: string
|
|
286
|
+
truncated: boolean
|
|
287
|
+
byteLength: number
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export interface PlatformFilePreviewUrlResult {
|
|
291
|
+
path: string
|
|
292
|
+
url: string
|
|
293
|
+
mimeType: string
|
|
294
|
+
byteLength: number
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export interface PlatformFileCreateFolderResult {
|
|
298
|
+
path: string
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export interface PlatformFileRenameResult {
|
|
302
|
+
path: string
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export interface PlatformFileWriteResult {
|
|
306
|
+
ok: true
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export interface PlatformFileDeleteResult {
|
|
310
|
+
ok: true
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/** Minimal file entry fields required for inline preview in plugin iframes. */
|
|
314
|
+
export interface PlatformFilePreviewEntry {
|
|
315
|
+
path: string
|
|
283
316
|
name: string
|
|
284
317
|
extension: string
|
|
285
318
|
kind: PlatformFileKind
|