@dolphy-app/extension-sdk 0.4.0 → 0.5.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/README.md +28 -14
- package/dist/client.d.ts +40 -0
- package/dist/client.js +67 -0
- package/dist/define-entry-BTz2F3qv.js +22 -0
- package/dist/define-entry-lsuxzKdD.d.ts +77 -0
- package/dist/index-I_CXC6Lj.d.ts +1958 -0
- package/dist/index.d.ts +7 -111
- package/dist/index.js +5 -86
- package/dist/react.d.ts +51 -0
- package/dist/react.js +112 -0
- package/dist/rpc.d.ts +28 -0
- package/dist/rpc.js +37 -0
- package/dist/testing.d.ts +184 -241
- package/dist/testing.js +574 -464
- package/docs/debugging.md +82 -64
- package/docs/no-build.md +84 -48
- package/docs/quick-start.md +78 -56
- package/docs/recipe-command-panel.md +262 -118
- package/docs/recipe-event-storage.md +188 -128
- package/docs/recipe-exercise-type.md +271 -183
- package/docs/recipe-hooks.md +158 -0
- package/docs/recipe-import-export.md +48 -53
- package/docs/recipe-mountable.md +322 -0
- package/docs/recipe-react.md +352 -0
- package/docs/recipe-rpc-and-app.md +366 -0
- package/docs/recipe-settings.md +122 -100
- package/docs/recipe-theme.md +72 -40
- package/docs/recipe-when-dependencies.md +188 -82
- package/package.json +29 -7
- package/dist/answer-element-BOQcuxYh.js +0 -114
- package/dist/answer-view-D6wnyThb.d.ts +0 -28
- package/dist/runtime.d.ts +0 -17
- package/dist/runtime.js +0 -24
- package/docs/recipe-ui-kit.md +0 -172
package/docs/debugging.md
CHANGED
|
@@ -6,32 +6,42 @@ check to the running app. Commands are those of a generated project; see the
|
|
|
6
6
|
|
|
7
7
|
## 1. Reproduce it in a test
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
Node, with a debugger and `console.log` available.
|
|
11
|
-
shape, a setting read before it is set, a handler
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
methods to see what
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
the
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
9
|
+
`createTestServer` and `createTestClient` of `@dolphy-app/extension-sdk/testing`
|
|
10
|
+
run your entries in plain Node, with a debugger and `console.log` available.
|
|
11
|
+
Most mistakes (a wrong result shape, a setting read before it is set, a handler
|
|
12
|
+
that throws, an id without the extension prefix) show up there.
|
|
13
|
+
|
|
14
|
+
- `createTestServer(server, { extensionId, logger })` takes a `logger` option:
|
|
15
|
+
pass an object with `debug`, `info`, `warn` and `error` methods to see what
|
|
16
|
+
`server.logger` receives.
|
|
17
|
+
- With `extensionId` set the harness checks that every id you register is the
|
|
18
|
+
extension id or starts with `<id>.`, the way the host does. It also checks what
|
|
19
|
+
the host checks about a result: the shape of a verdict, a grade of 1–5 or
|
|
20
|
+
`null`, a command result (`notify` text of 1–500 characters, a JSON value of
|
|
21
|
+
at most 64 KiB), an importer's or exporter's result. A message from the harness
|
|
22
|
+
usually names the rule.
|
|
23
|
+
- An error in `server` fails `createTestServer` itself, as it fails the load in
|
|
24
|
+
the app: nothing is registered. A handler's failure is not swallowed but
|
|
25
|
+
rejects the promise.
|
|
26
|
+
- The harness does not count the host's time limits, so a test that passes does
|
|
27
|
+
not prove a handler is fast enough: an event handler gets 2 seconds, a command
|
|
28
|
+
or a schedule handler 10, an importer or an exporter 30, and the registration
|
|
29
|
+
(`server`) 10.
|
|
24
30
|
|
|
25
31
|
## 2. Run the checks
|
|
26
32
|
|
|
27
33
|
```sh
|
|
28
|
-
pnpm typecheck #
|
|
34
|
+
pnpm typecheck # tsc
|
|
29
35
|
pnpm validate # the manifest the way the app parses it
|
|
30
36
|
pnpm lint # metadata and bundle findings the catalog review also sees
|
|
31
37
|
```
|
|
32
38
|
|
|
33
39
|
`pnpm validate` parses the built manifest with the same code as the app and
|
|
34
|
-
exits with code 1 on a problem
|
|
40
|
+
exits with code 1 on a problem; a key the manifest does not have (a command, a
|
|
41
|
+
setting, a panel written into `extension.json`) is one: the manifest holds the
|
|
42
|
+
identity of the extension, and the code registers everything else. The build
|
|
43
|
+
also fails when `server` imports `vue`, `vuetify` or a component, or `client`
|
|
44
|
+
imports a `node:*` module, and names the file.
|
|
35
45
|
`pnpm lint` prints `warning <id> <RULE> <field>: <message>` lines; a rule that
|
|
36
46
|
looks wrong for your code (for example `eval` in a bundled dependency) is a hint
|
|
37
47
|
for the reviewer, not a failure.
|
|
@@ -66,8 +76,9 @@ If you prefer to run the two parts yourself, start `pnpm dev`
|
|
|
66
76
|
(`dolphy-ext build --watch`) and start Dolphy with
|
|
67
77
|
`DOLPHY_DEV_EXTENSIONS=<project>/dist-ext`; from a checkout of the Dolphy
|
|
68
78
|
repository that is `DOLPHY_DEV_EXTENSIONS=<project>/dist-ext pnpm dev`. The app
|
|
69
|
-
rereads the extensions on every file change and applies the change live
|
|
70
|
-
|
|
79
|
+
rereads the extensions on every file change and applies the change live: the
|
|
80
|
+
extension host runs `server` again and the window loads `client.mjs` again, and
|
|
81
|
+
the window itself does not reload. Things to know:
|
|
71
82
|
|
|
72
83
|
- The app has one instance. If Dolphy is already running, a second start exits
|
|
73
84
|
at once and the variable is lost. `dolphy-ext dev` notices an app that quits
|
|
@@ -78,8 +89,29 @@ to know:
|
|
|
78
89
|
extension instead of the extension working: start with that text.
|
|
79
90
|
- If the id is also in the bundled set or installed from the catalog, the
|
|
80
91
|
development copy wins.
|
|
81
|
-
-
|
|
82
|
-
|
|
92
|
+
- The components of extensions in development are redrawn on a change, so their
|
|
93
|
+
state can be lost.
|
|
94
|
+
|
|
95
|
+
### `load-failed`
|
|
96
|
+
|
|
97
|
+
When `server` throws, registers something invalid (an id that is taken or does
|
|
98
|
+
not carry the extension prefix, a bad `when`, an invalid setting definition), or
|
|
99
|
+
does not finish in 10 seconds, the extension host registers
|
|
100
|
+
nothing from it. Registration is all or nothing: the commands, settings and
|
|
101
|
+
event handlers `server` managed to add before the failure are removed too. The
|
|
102
|
+
extension row in Settings → Extensions shows the diagnostic "Could not load the
|
|
103
|
+
extension: {reason}" with the message of the error, and the log has the entry
|
|
104
|
+
`extension registration failed` with the cause (`activation-failed`, or
|
|
105
|
+
`activation-timeout` for the 10 seconds). `server` is called once per load, so
|
|
106
|
+
do slow work (a network request, a big file) in a handler and not in `server`
|
|
107
|
+
itself.
|
|
108
|
+
|
|
109
|
+
The client part has its own failure. When `client.mjs` does not import, `client`
|
|
110
|
+
throws, or a registration is refused (an id that is taken, a bad injection
|
|
111
|
+
target), the window shows "The extension client part failed to load" on the
|
|
112
|
+
extension and keeps no contribution of the client part; the other extensions
|
|
113
|
+
and the server part of this one keep working. The reason is in the DevTools
|
|
114
|
+
console of section 4. After you fix the file, the next rebuild loads it again.
|
|
83
115
|
|
|
84
116
|
## 4. DevTools
|
|
85
117
|
|
|
@@ -88,33 +120,35 @@ build of the app, including an installed one, these keys toggle the DevTools of
|
|
|
88
120
|
the main window: `F12`, `Cmd+Alt+I` (macOS) and `Ctrl+Shift+I`. Without the
|
|
89
121
|
variable the keys do nothing and an installed app has no DevTools.
|
|
90
122
|
|
|
91
|
-
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
123
|
+
- Panels, injected components, answer views and markdown blocks of an extension
|
|
124
|
+
are Vue components in the page of the app window itself. "Elements" shows
|
|
125
|
+
their markup in the page and the Vue DevTools show the component tree; the
|
|
126
|
+
console evaluates in the same page as the app and shows what the client part
|
|
127
|
+
and its components print with `console`.
|
|
95
128
|
- `dolphy-ext dev` and `dolphy-ext build --watch` put an inline source map
|
|
96
129
|
(`//# sourceMappingURL=data:application/json…`) into every bundle, so
|
|
97
|
-
"Sources" shows your TypeScript (`src/
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
- The code that runs in the extension
|
|
102
|
-
|
|
130
|
+
"Sources" shows your TypeScript (`src/client.ts` and the files it imports)
|
|
131
|
+
for the client part: set a breakpoint there, `debugger;` works too. A plain
|
|
132
|
+
`dolphy-ext build` (`pnpm build`) and the catalog build never write source
|
|
133
|
+
maps, and the catalog check rejects a submission that has one.
|
|
134
|
+
- The code that runs in the extension host (`main.mjs`: `server`, command and
|
|
135
|
+
event handlers, schedules, importers and exporters) is not in this window: see
|
|
136
|
+
section 6 and the log.
|
|
103
137
|
|
|
104
138
|
## 5. The log
|
|
105
139
|
|
|
106
|
-
`
|
|
140
|
+
`server.logger` has `debug`, `info`, `warn` and `error`; each takes an object of
|
|
107
141
|
fields and an optional message:
|
|
108
142
|
|
|
109
143
|
```text
|
|
110
|
-
|
|
144
|
+
s.logger.info({ id: change.id, value: change.value }, 'setting changed');
|
|
111
145
|
```
|
|
112
146
|
|
|
113
147
|
The output goes to the log of the app, not to a console of the window. Log
|
|
114
148
|
structured fields, not secrets or the learner's answers. The host writes to the
|
|
115
149
|
same log: an exception in a handler, a handler that outlives its time limit, an
|
|
116
|
-
event dropped from a full queue, and
|
|
117
|
-
|
|
150
|
+
event dropped from a full queue, and the failure of a registration. The client
|
|
151
|
+
part has no logger: use `console` and the DevTools.
|
|
118
152
|
|
|
119
153
|
### Reading the log in the app
|
|
120
154
|
|
|
@@ -138,7 +172,7 @@ The labels the dialog shows, with the keys of the app's messages (ru and en):
|
|
|
138
172
|
| -------------------------- | -------------------------------- | ----------------------------- | ------------------------------------------ |
|
|
139
173
|
| Settings section | Extensions | Расширения | `settings.extensions.title` |
|
|
140
174
|
| Origin of a dev extension | Development | Разработка | `settings.extensions.origin.dev` |
|
|
141
|
-
|
|
|
175
|
+
| Load failure of the client part | The extension client part failed to load | Клиентская часть расширения не загрузилась | `settings.extensions.clientFailed.title` |
|
|
142
176
|
| Block with the log button | Diagnostics | Диагностика | `settings.extensions.support.title` |
|
|
143
177
|
| Button of the block | Log | Журнал | `settings.extensions.support.openLog` |
|
|
144
178
|
| Action in an extension row | Log | Журнал | `settings.extensions.log.rowAction` |
|
|
@@ -154,18 +188,12 @@ The labels the dialog shows, with the keys of the app's messages (ru and en):
|
|
|
154
188
|
| Reread the log | Refresh | Обновить | `settings.extensions.log.refresh` |
|
|
155
189
|
| Filters match nothing | No entries match the filters. | Нет записей, подходящих под условия. | `settings.extensions.log.empty` |
|
|
156
190
|
|
|
157
|
-
### Output of the
|
|
191
|
+
### Output of the extension host
|
|
158
192
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
`console` only for a quick look. The output is limited so that one extension
|
|
164
|
-
cannot flood the log: at most 64 KiB in 60 seconds per extension; the rest is
|
|
165
|
-
dropped and one entry "output truncated" with `droppedBytes` closes the window.
|
|
166
|
-
A process that sends a message larger than 1 MiB or more than 200 messages in
|
|
167
|
-
a second is stopped, with an `error` entry whose reason is `ipc-size` or
|
|
168
|
-
`ipc-rate`.
|
|
193
|
+
What `server` and its handlers print with `console.log`, `console.error` or an
|
|
194
|
+
uncaught error goes to the log as `warn` entries of the extension host in
|
|
195
|
+
"Details". Use `s.logger` for anything you want to filter by level (its entries
|
|
196
|
+
carry the extension id); use `console` only for a quick look.
|
|
169
197
|
|
|
170
198
|
### The file
|
|
171
199
|
|
|
@@ -177,34 +205,24 @@ relevant lines, or the text of "Copy diagnostics" in the "Diagnostics" block (it
|
|
|
177
205
|
has no paths of your home folder, library content or learning data), to a bug
|
|
178
206
|
report.
|
|
179
207
|
|
|
180
|
-
## 6.
|
|
208
|
+
## 6. Reading a stack trace
|
|
181
209
|
|
|
182
|
-
|
|
183
|
-
restricted process, and what its `permissions` do not declare is unavailable:
|
|
184
|
-
`ctx.library` throws `PermissionError` without `library.read`; spawning a
|
|
185
|
-
process, a worker thread or a native module fails with `ERR_ACCESS_DENIED`.
|
|
186
|
-
Test helpers do not reproduce this, so a feature that needs a permission must be
|
|
187
|
-
tried in the app. Extensions in development get the permissions their manifest
|
|
188
|
-
declares. To debug without the restrictions, turn on "Trust (no isolation)" for
|
|
189
|
-
the extension in Settings → Extensions; turn it off again before you release,
|
|
190
|
-
because your users will not have it on.
|
|
191
|
-
|
|
192
|
-
## 7. Reading a stack trace
|
|
193
|
-
|
|
194
|
-
The code of the extension process is `dist-ext/<id>/main.mjs`, readable and not
|
|
210
|
+
The code of the extension host is `dist-ext/<id>/main.mjs`, readable and not
|
|
195
211
|
minified. A watch build (`dolphy-ext dev`, `dolphy-ext build --watch`) appends
|
|
196
212
|
an inline source map to it, but the app does not turn on source maps for that
|
|
197
213
|
process, so a stack trace in the log still points to lines of `main.mjs`: open
|
|
198
214
|
that file to find the place and search it for the name from the trace. The
|
|
199
|
-
map is for the browser
|
|
215
|
+
map is for the browser file of section 4. A plain `dolphy-ext build` writes no
|
|
200
216
|
maps at all.
|
|
201
217
|
|
|
202
218
|
## Which limit did I hit?
|
|
203
219
|
|
|
204
220
|
| Symptom | Limit |
|
|
205
221
|
| ----------------------------------------------- | -------------------------------------------------------- |
|
|
206
|
-
|
|
|
222
|
+
| the extension shows `load-failed` with a timeout | `server` must finish in 10 seconds |
|
|
207
223
|
| an event handler stops mid-way | 2 seconds per event; the queue holds 100 events |
|
|
224
|
+
| a command or a schedule handler stops mid-way | 10 seconds |
|
|
225
|
+
| an importer or an exporter stops mid-way | 30 seconds |
|
|
208
226
|
| `StorageQuotaError` | key 128 characters, value 64 KiB, 256 keys, 1 MiB total |
|
|
209
227
|
| a command result is rejected | `notify` text 1–500 characters; a result up to 64 KiB |
|
|
210
|
-
| a panel
|
|
228
|
+
| a panel or a view fails while it draws | the card "Retry" replaces it; the window stays up |
|
package/docs/no-build.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Without a build
|
|
2
2
|
|
|
3
|
-
An extension is a directory with an `extension.json` and, if it has code,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
An extension is a directory with an `extension.json` and, if it has code, one or
|
|
4
|
+
two ES modules: `main.mjs` for the `server` entry and `client.mjs` for the
|
|
5
|
+
`client` entry. `dolphy-ext build` only produces such a directory from a
|
|
6
|
+
TypeScript project; you can write it by hand. You do not need TypeScript, a
|
|
7
|
+
`package.json` or `dolphy-ext` for that. This page shows the smallest case: one
|
|
8
|
+
palette command and a panel, three hand-written files. Use it for a quick
|
|
9
|
+
experiment or when the code is a few lines; switch to the
|
|
10
|
+
[quick start](quick-start.md) layout when you want types, tests and bundling.
|
|
9
11
|
|
|
10
12
|
## The files
|
|
11
13
|
|
|
@@ -16,44 +18,78 @@ File `extension.json` (no build):
|
|
|
16
18
|
"id": "acme.plain",
|
|
17
19
|
"version": "0.1.0",
|
|
18
20
|
"apiVersion": 1,
|
|
21
|
+
"main": "./main.mjs",
|
|
22
|
+
"client": "./client.mjs",
|
|
19
23
|
"name": "Plain hello",
|
|
20
|
-
"description": "A palette command written by hand, without a build step.",
|
|
24
|
+
"description": "A palette command and a panel written by hand, without a build step.",
|
|
21
25
|
"author": "your-github-login",
|
|
22
|
-
"tags": ["productivity"]
|
|
23
|
-
"contributes": {
|
|
24
|
-
"commands": [{ "id": "acme.plain.hello", "title": "Say hello" }]
|
|
25
|
-
}
|
|
26
|
+
"tags": ["productivity"]
|
|
26
27
|
}
|
|
27
28
|
```
|
|
28
29
|
|
|
29
30
|
File `main.mjs` (no build):
|
|
30
31
|
|
|
31
32
|
```js
|
|
32
|
-
export
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
})
|
|
37
|
-
}
|
|
33
|
+
export const server = (s) => {
|
|
34
|
+
s.registerCommand({
|
|
35
|
+
id: 'acme.plain.hello',
|
|
36
|
+
title: 'Say hello',
|
|
37
|
+
run: () => ({ notify: `Hello from ${s.extensionId}!` }),
|
|
38
|
+
});
|
|
39
|
+
s.registerCommand({
|
|
40
|
+
id: 'acme.plain.open',
|
|
41
|
+
title: 'Open the plain panel',
|
|
42
|
+
run: () => ({ openPanel: 'acme.plain.view' }),
|
|
43
|
+
});
|
|
38
44
|
};
|
|
39
45
|
```
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
File `client.mjs` (no build):
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
// `vue` is the app's own instance: the window gives it through globalThis.__dolphy
|
|
51
|
+
const { defineComponent, h } = await globalThis.__dolphy.require('vue');
|
|
52
|
+
|
|
53
|
+
export const client = (c) => {
|
|
54
|
+
c.addPanel({
|
|
55
|
+
id: 'acme.plain.view',
|
|
56
|
+
title: 'Plain hello',
|
|
57
|
+
component: defineComponent({
|
|
58
|
+
setup: () => () => h('p', 'Hello from a panel'),
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- `main` and `client` are written in the manifest: nothing fills them in. A part
|
|
65
|
+
that is left out (`null` or no key) does not exist, so an extension may have
|
|
66
|
+
only `main.mjs` or only `client.mjs`. Each is a path inside the directory that
|
|
67
|
+
ends with `.mjs`.
|
|
68
|
+
- The contract of `main.mjs` is `export const server = (s) => { … }`, the same
|
|
69
|
+
function `defineServer` takes in a project; `s` is the `ServerContext`
|
|
70
|
+
(`registerCommand`, `registerSettings`, `on`, `storage`, `logger`, …). The
|
|
71
|
+
contract of `client.mjs` is `export const client = (c) => { … }`
|
|
72
|
+
(`addPanel`, `addInjection`, `addAnswerView`, `addMarkdownRenderer`,
|
|
73
|
+
`addTheme`, `addCommand`). Either may return a cleanup function. `async`
|
|
74
|
+
functions work. `server` is called when the host loads the extension; if it
|
|
75
|
+
throws or takes more than 10 seconds the extension shows `load-failed` and
|
|
76
|
+
registers nothing.
|
|
77
|
+
- Without a build there is no `import 'vue'`: `client.mjs` reads `vue` (and
|
|
78
|
+
`vuetify`, `vuetify/components`, `vuetify/directives`) from
|
|
79
|
+
`globalThis.__dolphy.require(name)`, which resolves to the app's own instance.
|
|
80
|
+
Write the components with `h` or a render function: there is no template
|
|
81
|
+
compiler. `main.mjs` never needs `vue`.
|
|
46
82
|
- There are no helpers, so a command returns the result object itself:
|
|
47
|
-
`{ notify: text }` is what `notify(text)` makes
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
83
|
+
`{ notify: text }` is what `notify(text)` makes and `{ openPanel: id, props }`
|
|
84
|
+
is what `openPanel(id, props)` makes. Ids are written in the code and must be
|
|
85
|
+
the extension id or start with `<id>.`.
|
|
86
|
+
- The modules must be plain JavaScript that the app runs as it is: no
|
|
87
|
+
TypeScript, no bare imports of packages (nothing is installed next to them),
|
|
88
|
+
and no `node:*` imports in `client.mjs`.
|
|
53
89
|
|
|
54
90
|
## Check and try
|
|
55
91
|
|
|
56
|
-
Put
|
|
92
|
+
Put the files into a directory named exactly as the extension id,
|
|
57
93
|
`acme.plain/` (the app takes the id from the directory name and rejects a
|
|
58
94
|
manifest that disagrees), and check it:
|
|
59
95
|
|
|
@@ -61,14 +97,15 @@ manifest that disagrees), and check it:
|
|
|
61
97
|
npx --package @dolphy-app/extension-tools dolphy-ext validate ./acme.plain
|
|
62
98
|
```
|
|
63
99
|
|
|
64
|
-
`validate` parses the manifest the way the app does
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
directory
|
|
69
|
-
picked up without a restart when you use
|
|
100
|
+
`validate` parses the manifest the way the app does, checks that `main` and
|
|
101
|
+
`client` are files, and exits with code 1 on a problem. To try the extension,
|
|
102
|
+
put the directory into a folder and start the app with `DOLPHY_DEV_EXTENSIONS`
|
|
103
|
+
pointing at that folder (the folder, not the extension directory: it holds one
|
|
104
|
+
directory per extension), or copy the directory to `<userData>/extensions/` and
|
|
105
|
+
restart the app. Edits to the files are picked up without a restart when you use
|
|
106
|
+
`DOLPHY_DEV_EXTENSIONS`.
|
|
70
107
|
|
|
71
|
-
To test the module without the app,
|
|
108
|
+
To test the server module without the app, run its entry with the SDK helper:
|
|
72
109
|
|
|
73
110
|
```sh
|
|
74
111
|
npm install --save-dev @dolphy-app/extension-sdk vitest
|
|
@@ -77,23 +114,22 @@ npm install --save-dev @dolphy-app/extension-sdk vitest
|
|
|
77
114
|
<!-- fragment -->
|
|
78
115
|
|
|
79
116
|
```js
|
|
80
|
-
import {
|
|
81
|
-
import
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
console.log(await commands.run('acme.plain.hello'));
|
|
87
|
-
// { kind: 'notify', text: 'Hello from …!' }
|
|
117
|
+
import { createTestServer } from '@dolphy-app/extension-sdk/testing';
|
|
118
|
+
import { server } from './main.mjs';
|
|
119
|
+
|
|
120
|
+
const running = await createTestServer(server, { extensionId: 'acme.plain' });
|
|
121
|
+
console.log(await running.commands.run('acme.plain.hello'));
|
|
122
|
+
// { kind: 'notify', text: 'Hello from acme.plain!' }
|
|
88
123
|
```
|
|
89
124
|
|
|
90
|
-
`
|
|
91
|
-
shape of a
|
|
125
|
+
`createTestServer` accepts the export of the module as it is, because it has the
|
|
126
|
+
shape of a server entry. `createTestClient(client, { extensionId })` does the
|
|
127
|
+
same for `client.mjs` and lists the panels it added.
|
|
92
128
|
|
|
93
129
|
## Publishing
|
|
94
130
|
|
|
95
131
|
The extension catalog reviews a project, not a bare directory: it requires a
|
|
96
|
-
`package.json` with a lock file and a `README.md` that explains what
|
|
97
|
-
|
|
132
|
+
`package.json` with a lock file and a `README.md` that explains what the
|
|
133
|
+
extension does (`dolphy-ext catalog check`). A hand-written directory is for
|
|
98
134
|
yourself or for handing a folder to someone. To publish, generate a project with
|
|
99
135
|
`create-dolphy-extension` and move the code into it.
|