dsh-plugin-toolkit 0.9.2 → 0.9.4
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/CHANGELOG.md +26 -0
- package/client.js +35 -17
- package/lib/doctor.mjs +14 -2
- package/lib/init.mjs +11 -2
- package/lib/verify.mjs +23 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
## 0.9.4
|
|
2
|
+
|
|
3
|
+
- The client module now declares `inject: ['slots', 'locale']` and guards every
|
|
4
|
+
service it reads. Without the list the loader calls `apply()` before those
|
|
5
|
+
services exist; the throw fails the **whole web boot**, and the app then reports
|
|
6
|
+
that third-party plugins are unsupported and starts with them disabled. That is
|
|
7
|
+
what one unguarded `ctx.locale.register` did to a real profile.
|
|
8
|
+
- `verify` now calls the client module's `apply()` with a bare context and refuses
|
|
9
|
+
a face without an `inject` list, so this class of failure is caught before
|
|
10
|
+
install instead of at boot.
|
|
11
|
+
- `init` scaffolds the same guards, for the same reason.
|
|
12
|
+
|
|
13
|
+
## 0.9.3
|
|
14
|
+
|
|
15
|
+
- The panel needed one more thing than `dsh.client`: the host resolves the bundle
|
|
16
|
+
through `exports["./client"]` (`clientExportOf`), and drops the row when that
|
|
17
|
+
subpath is missing. 0.9.2 declared `dsh.client` but its `exports` map had no
|
|
18
|
+
`./client`, so the tab was still absent — this release exports `./client` and
|
|
19
|
+
`doctor` now checks the same thing the host does.
|
|
20
|
+
- `init` scaffolds `exports: { '.': './index.js', './client': './client.js' }`.
|
|
21
|
+
Every plugin generated before this release was missing it, so every generated
|
|
22
|
+
panel was invisible for the same reason.
|
|
23
|
+
- `doctor` reports a `dsh.client` whose `exports["./client"]` file does not exist,
|
|
24
|
+
and a `dsh.client` with no `./client` export at all. The `files`-list gap is now
|
|
25
|
+
caught at the manifest stage instead of at pack time.
|
|
26
|
+
|
|
1
27
|
## 0.9.2
|
|
2
28
|
|
|
3
29
|
- `doctor` reports a shipped client bundle that no `dsh.client` declares. The host
|
package/client.js
CHANGED
|
@@ -137,25 +137,43 @@ window.__ModuleLoader__.load({
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
function apply(ctx) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
140
|
+
// A panel that cannot find its services must degrade, not fail the boot:
|
|
141
|
+
// an exception here fails the whole web boot and takes every other plugin
|
|
142
|
+
// down with it. Every service below is optional for that reason.
|
|
143
|
+
try {
|
|
144
|
+
injectStyles(typeof document === 'undefined' ? undefined : document);
|
|
145
|
+
} catch {
|
|
146
|
+
// No document: the styles are cosmetic.
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
if (ctx.locale !== undefined && typeof ctx.locale.register === 'function') ctx.locale.register(NS, COPY);
|
|
150
|
+
} catch {
|
|
151
|
+
// The panel keeps its English strings.
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
if (typeof ctx.inject !== 'function') return;
|
|
155
|
+
ctx.inject(['sidebarRightTabs', 'sidebarRight'], (tabCtx) => {
|
|
156
|
+
if (tabCtx === undefined || tabCtx.slots === undefined || tabCtx.sidebarRightTabs === undefined) return;
|
|
157
|
+
tabCtx.effect(() => tabCtx.slots.inject('sidebar.right.pane.tab', () => tabCtx.slots.register({
|
|
158
|
+
name: 'sidebar.right.pane.tab',
|
|
159
|
+
key: NS,
|
|
160
|
+
locale: NS,
|
|
161
|
+
}, Panel)));
|
|
162
|
+
tabCtx.effect(() => tabCtx.sidebarRightTabs.register({
|
|
163
|
+
id: NS,
|
|
164
|
+
kind: KIND,
|
|
165
|
+
priority: 'extension',
|
|
166
|
+
title: () => 'Plugin doctor',
|
|
167
|
+
}));
|
|
168
|
+
});
|
|
169
|
+
} catch {
|
|
170
|
+
// No sidebar: the plugin still loads, it just has no place to show.
|
|
171
|
+
}
|
|
156
172
|
}
|
|
157
173
|
|
|
158
|
-
|
|
174
|
+
// The services the tab body reads. Declaring them lets the loader wait for
|
|
175
|
+
// them instead of calling apply() before they exist.
|
|
176
|
+
module.exports = { inject: ['slots', 'locale'], apply, name: 'dsh-plugin-toolkit' };
|
|
159
177
|
return module.exports;
|
|
160
178
|
},
|
|
161
179
|
});
|
package/lib/doctor.mjs
CHANGED
|
@@ -122,8 +122,20 @@ export function checkClientDeclaration(dir, manifest) {
|
|
|
122
122
|
const client = manifest.dsh?.client;
|
|
123
123
|
if (client !== undefined && client !== null) {
|
|
124
124
|
const platform = client.platform;
|
|
125
|
-
if (platform
|
|
126
|
-
|
|
125
|
+
if (platform !== undefined && platform !== 'web') {
|
|
126
|
+
return `dsh.client.platform is ${JSON.stringify(platform)}, but the harness serves client bundles on web`;
|
|
127
|
+
}
|
|
128
|
+
// The host reads the bundle path from exports["./client"] only — a
|
|
129
|
+
// declaration without that subpath makes the host drop the row.
|
|
130
|
+
const exported = manifest.exports;
|
|
131
|
+
const subpath = typeof exported === 'string' ? undefined : exportTarget(exported?.['./client']);
|
|
132
|
+
if (typeof subpath !== 'string') {
|
|
133
|
+
return 'dsh.client is declared but exports has no "./client" bundle, so the host drops the row and the panel cannot appear';
|
|
134
|
+
}
|
|
135
|
+
const file = subpath.replace(/^\.\//u, '');
|
|
136
|
+
return fs.existsSync(path.join(dir, file))
|
|
137
|
+
? null
|
|
138
|
+
: `exports["./client"] points at ${subpath}, which does not exist`;
|
|
127
139
|
}
|
|
128
140
|
const exported = manifest.exports;
|
|
129
141
|
const subpath = typeof exported === 'string' ? undefined : exportTarget(exported?.['./client']);
|
package/lib/init.mjs
CHANGED
|
@@ -33,6 +33,7 @@ function manifest({ name, title, version }) {
|
|
|
33
33
|
type: 'module',
|
|
34
34
|
engines: { node: '>=18', dsh: '>=0.2.0' },
|
|
35
35
|
main: 'index.js',
|
|
36
|
+
exports: { '.': './index.js', './client': './client.js' },
|
|
36
37
|
files: ['index.js', 'client.js', 'cordis.patch.yml', 'README.md'],
|
|
37
38
|
scripts: { test: 'node --test', doctor: 'dsh-plugin doctor .' },
|
|
38
39
|
devDependencies: {
|
|
@@ -85,10 +86,18 @@ function client({ name, title }) {
|
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
return {
|
|
89
|
+
// The services this panel reads. Declaring them makes the loader wait,
|
|
90
|
+
// and guarding them keeps a missing service from failing the whole boot.
|
|
91
|
+
inject: ['slots', 'locale'],
|
|
88
92
|
apply(ctx) {
|
|
89
|
-
|
|
93
|
+
try {
|
|
94
|
+
if (ctx.locale !== undefined && typeof ctx.locale.register === 'function') ctx.locale.register(NS, COPY);
|
|
95
|
+
} catch {
|
|
96
|
+
// keep the English strings
|
|
97
|
+
}
|
|
98
|
+
if (typeof ctx.inject !== 'function') return undefined;
|
|
90
99
|
const dispose = ctx.inject(['sidebarRightTabs', 'sidebarRight'], (tabCtx) => {
|
|
91
|
-
if (tabCtx.slots === undefined) return;
|
|
100
|
+
if (tabCtx === undefined || tabCtx.slots === undefined) return;
|
|
92
101
|
const tr = tabCtx.locale.bind(NS);
|
|
93
102
|
const offType = tabCtx.sidebarRightTabs.register({
|
|
94
103
|
id: NS,
|
package/lib/verify.mjs
CHANGED
|
@@ -165,7 +165,30 @@ export async function verify({ dir, mount = true }) {
|
|
|
165
165
|
// running out of npx's cache, whose dependencies are not the panel's.
|
|
166
166
|
const panel = await mountClient({ file: entryFile, resolveFrom: dir });
|
|
167
167
|
const text = panel.text();
|
|
168
|
+
// The web boot calls the module's apply() before every service exists. An
|
|
169
|
+
// exception there fails the whole boot and takes the other plugins down
|
|
170
|
+
// with it, so check the face and the bare-context call here.
|
|
171
|
+
const { loadBundle } = await import('./testkit/index.mjs');
|
|
172
|
+
const face = loadBundle(entryFile);
|
|
173
|
+
const faceProblems = [];
|
|
174
|
+
if (Array.isArray(face.inject) === false) {
|
|
175
|
+
faceProblems.push('the client module declares no inject list, so the loader calls apply() before its services exist');
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
face.apply({});
|
|
179
|
+
} catch (error) {
|
|
180
|
+
faceProblems.push(`apply() throws when the services are absent, which fails the web boot: ${error.message}`);
|
|
181
|
+
}
|
|
168
182
|
await panel.unmount();
|
|
183
|
+
if (faceProblems.length > 0) {
|
|
184
|
+
return {
|
|
185
|
+
ok: false,
|
|
186
|
+
stage: 'mount',
|
|
187
|
+
failures: faceProblems.map((message) => ({ check: 'boot', message })),
|
|
188
|
+
files: packed.files,
|
|
189
|
+
installed,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
169
192
|
return { ok: true, stage: 'mount', failures: [], files: packed.files, size: packed.size, installed, text };
|
|
170
193
|
} catch (error) {
|
|
171
194
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-toolkit",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
4
4
|
"description": "Preflight, release and test DeepSeek Harness plugins: checks what the host needs, waits for npm to actually serve the version, and keeps the market index honest.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"exports": {
|
|
10
10
|
".": "./index.js",
|
|
11
|
+
"./client": "./client.js",
|
|
11
12
|
"./cli": "./lib/cli.mjs",
|
|
12
13
|
"./testkit": "./lib/testkit/index.mjs"
|
|
13
14
|
},
|