dsh-edge 0.1.3 → 0.2.0-alpha.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.
- package/README.i18n.yaml +6 -6
- package/README.md +25 -10
- package/README.zh.md +25 -10
- package/THIRD_PARTY_NOTICES.md +10019 -187
- package/dist/index.html +1 -1
- package/dist/plugins/@deepseek-ai/dsh-client-locale/client.js +7 -7
- package/dist/plugins/@deepseek-ai/dsh-client-ui-agent-preset/client.js +61 -61
- package/dist/plugins/@deepseek-ai/dsh-client-ui-commands/client.js +14 -14
- package/dist/plugins/@deepseek-ai/dsh-client-ui-conversation/client.js +287 -287
- package/dist/plugins/@deepseek-ai/dsh-client-ui-deliverables/client.js +10 -10
- package/dist/plugins/@deepseek-ai/dsh-client-ui-input-trigger/client.js +11 -11
- package/dist/plugins/@deepseek-ai/dsh-client-ui-jobs/client.js +15 -15
- package/dist/plugins/@deepseek-ai/dsh-client-ui-layout/client.js +8 -8
- package/dist/plugins/@deepseek-ai/dsh-client-ui-model-selection/client.js +27 -27
- package/dist/plugins/@deepseek-ai/dsh-client-ui-permission-presets/client.js +8 -8
- package/dist/plugins/@deepseek-ai/dsh-client-ui-settings-general/client.js +31 -31
- package/dist/plugins/@deepseek-ai/dsh-client-ui-sidebar/client.js +23 -23
- package/dist/plugins/@deepseek-ai/dsh-client-ui-skill/client.js +19 -19
- package/dist/plugins/@deepseek-ai/dsh-client-ui-subagent/client.js +29 -29
- package/dist/plugins/@deepseek-ai/dsh-client-ui-theme/client.js +7 -7
- package/dist/plugins/@deepseek-ai/dsh-client-ui-tool/client.js +64 -64
- package/dist/plugins/@deepseek-ai/dsh-client-ui-trajectory/client.js +183 -183
- package/dist/plugins/@deepseek-ai/dsh-client-ui-user-questions/client.js +44 -44
- package/dist/plugins/@deepseek-ai/dsh-client-ui-workflow-run/client.js +24 -24
- package/dist/plugins/@deepseek-ai/dsh-client-ui-workspace/client.js +79 -79
- package/dist/plugins/dsh-edge-client-ui/client.js +68 -53
- package/package.json +22 -22
- package/scripts/activation.d.mts +34 -0
- package/scripts/activation.mjs +133 -0
- package/scripts/cli.d.mts +9 -0
- package/scripts/cli.mjs +66 -3
- package/scripts/dev.mjs +38 -0
- package/scripts/install.d.mts +8 -0
- package/scripts/install.mjs +95 -4
- package/scripts/legal-files.d.mts +23 -0
- package/scripts/legal-files.mjs +222 -40
- package/scripts/pnpm-invocation.d.mts +14 -0
- package/scripts/pnpm-invocation.mjs +25 -0
- package/scripts/publish.d.mts +25 -0
- package/scripts/publish.mjs +145 -0
- package/scripts/smoke-installed.mjs +27 -22
- package/scripts/verify-packed.mjs +8 -0
- package/scripts/wrangler-config-core.mjs +107 -0
- package/scripts/wrangler-config.d.mts +2 -0
- package/scripts/wrangler-config.mjs +9 -78
- package/worker/direct/index.js +1136 -1139
- package/worker/isolated/index.js +872 -875
- package/scripts/assemble-web.mjs +0 -230
- package/scripts/bundle.mjs +0 -86
package/scripts/assemble-web.mjs
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
/** Assemble the upstream Web shell and client-plugin graph as Worker assets. */
|
|
2
|
-
|
|
3
|
-
import { createHash } from 'node:crypto'
|
|
4
|
-
import {
|
|
5
|
-
cp,
|
|
6
|
-
mkdir,
|
|
7
|
-
readFile,
|
|
8
|
-
readdir,
|
|
9
|
-
rm,
|
|
10
|
-
stat,
|
|
11
|
-
writeFile,
|
|
12
|
-
} from 'node:fs/promises'
|
|
13
|
-
import { dirname, join, relative, resolve } from 'node:path'
|
|
14
|
-
import { fileURLToPath } from 'node:url'
|
|
15
|
-
|
|
16
|
-
const appRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
17
|
-
const repoRoot = resolve(appRoot, '../..')
|
|
18
|
-
const shellDist = join(repoRoot, 'apps/web/dist')
|
|
19
|
-
const outputRoot = join(appRoot, 'dist')
|
|
20
|
-
const deploymentPatches = [
|
|
21
|
-
join(repoRoot, 'packages/bundle/base/cordis.patch.yml'),
|
|
22
|
-
join(repoRoot, 'packages/bundle/web-app/cordis.patch.yml'),
|
|
23
|
-
]
|
|
24
|
-
// Deployment-owned browser features use the same client-plugin contract but
|
|
25
|
-
// intentionally stay out of upstream's generic Web composition.
|
|
26
|
-
const edgeClientPackages = ['dsh-edge-client-ui']
|
|
27
|
-
|
|
28
|
-
// HMR is useful only when the upstream Node host also runs its bundle watcher.
|
|
29
|
-
// Edge deploys immutable, content-addressed static assets instead.
|
|
30
|
-
const edgeExcludedPackages = new Set([
|
|
31
|
-
// Requires the upstream Node-side bundle watcher.
|
|
32
|
-
'@deepseek-ai/dsh-client-hmr',
|
|
33
|
-
// These surfaces depend on generated Host remotes or writable Host settings
|
|
34
|
-
// that the minimal Edge ApiProxy does not advertise yet. Keeping them out of
|
|
35
|
-
// the graph is capability negotiation at assembly time; their upstream code
|
|
36
|
-
// remains unchanged and can be restored with the matching server domain.
|
|
37
|
-
'@deepseek-ai/dsh-cordis-client-runner',
|
|
38
|
-
'@deepseek-ai/dsh-client-ui-cordis',
|
|
39
|
-
'@deepseek-ai/dsh-client-ui-goal',
|
|
40
|
-
'@deepseek-ai/dsh-client-ui-message-feedback',
|
|
41
|
-
'@deepseek-ai/dsh-client-ui-plan',
|
|
42
|
-
'@deepseek-ai/dsh-client-ui-settings-models',
|
|
43
|
-
'@deepseek-ai/dsh-client-ui-settings-plugin-inventory',
|
|
44
|
-
'@deepseek-ai/dsh-client-ui-settings-plugins',
|
|
45
|
-
// Its header action calls the session.export endpoint, which Edge does not
|
|
46
|
-
// implement. Keep the unavailable action out of the assembled browser.
|
|
47
|
-
'@deepseek-ai/dsh-session-log-export',
|
|
48
|
-
])
|
|
49
|
-
const shellStaticPackages = new Set(['@deepseek-ai/dsh-client-ui-primitives'])
|
|
50
|
-
const assetSecurityHeaders = `/*
|
|
51
|
-
Content-Security-Policy: frame-ancestors 'none'
|
|
52
|
-
X-Frame-Options: DENY
|
|
53
|
-
`
|
|
54
|
-
|
|
55
|
-
function shortHash(input) {
|
|
56
|
-
return createHash('sha1').update(input).digest('hex').slice(0, 12)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async function isDirectory(path) {
|
|
60
|
-
try {
|
|
61
|
-
return (await stat(path)).isDirectory()
|
|
62
|
-
} catch {
|
|
63
|
-
return false
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async function findPackageJsonFiles(root) {
|
|
68
|
-
const found = []
|
|
69
|
-
const visit = async (directory) => {
|
|
70
|
-
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
71
|
-
if (entry.name === 'node_modules' || entry.name === 'lib') continue
|
|
72
|
-
const path = join(directory, entry.name)
|
|
73
|
-
if (entry.isDirectory()) {
|
|
74
|
-
await visit(path)
|
|
75
|
-
} else if (entry.name === 'package.json') {
|
|
76
|
-
found.push(path)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
await visit(root)
|
|
81
|
-
return found
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async function removeSourceMaps(root) {
|
|
85
|
-
for (const entry of await readdir(root, { withFileTypes: true })) {
|
|
86
|
-
const path = join(root, entry.name)
|
|
87
|
-
if (entry.isDirectory()) {
|
|
88
|
-
await removeSourceMaps(path)
|
|
89
|
-
} else if (entry.name.endsWith('.map')) {
|
|
90
|
-
await rm(path)
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function deploymentPackageNames(patch) {
|
|
96
|
-
const names = []
|
|
97
|
-
for (const match of patch.matchAll(/^\s+name:\s+'([^']+)'\s*$/gm)) {
|
|
98
|
-
if (!edgeExcludedPackages.has(match[1])) names.push(match[1])
|
|
99
|
-
}
|
|
100
|
-
return names
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function clientBundleRelativePath(pkg) {
|
|
104
|
-
const client = pkg.exports?.['./client']
|
|
105
|
-
if (typeof client === 'string') return client
|
|
106
|
-
if (client !== null && typeof client === 'object' && typeof client.default === 'string') {
|
|
107
|
-
return client.default
|
|
108
|
-
}
|
|
109
|
-
throw new Error(`${pkg.name} is in the Web roster but exports no ./client bundle.`)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function injectBootManifest(html, graph) {
|
|
113
|
-
const json = JSON.stringify(graph).replaceAll('<', '\\u003c')
|
|
114
|
-
const script = `<script>window.__DSH_BOOT__ = ${json}</script>`
|
|
115
|
-
const head = html.indexOf('<head>')
|
|
116
|
-
return head === -1
|
|
117
|
-
? `${script}${html}`
|
|
118
|
-
: `${html.slice(0, head + 6)}${script}${html.slice(head + 6)}`
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function injectOwnerSessionGuard(html) {
|
|
122
|
-
const script = `<script>(() => {
|
|
123
|
-
const originalFetch = window.fetch.bind(window)
|
|
124
|
-
let redirecting = false
|
|
125
|
-
window.fetch = async (...args) => {
|
|
126
|
-
const input = args[0]
|
|
127
|
-
const href = input instanceof Request ? input.url : String(input)
|
|
128
|
-
const target = new URL(href, window.location.href)
|
|
129
|
-
const response = await originalFetch(...args)
|
|
130
|
-
if (!redirecting
|
|
131
|
-
&& response.status === 401
|
|
132
|
-
&& response.headers.get('www-authenticate') === 'DshEdgeOwner'
|
|
133
|
-
&& target.origin === window.location.origin
|
|
134
|
-
&& target.pathname.startsWith('/api/')) {
|
|
135
|
-
redirecting = true
|
|
136
|
-
window.location.replace('/login')
|
|
137
|
-
}
|
|
138
|
-
return response
|
|
139
|
-
}
|
|
140
|
-
})()</script>`
|
|
141
|
-
const head = html.indexOf('<head>')
|
|
142
|
-
return head === -1
|
|
143
|
-
? `${script}${html}`
|
|
144
|
-
: `${html.slice(0, head + 6)}${script}${html.slice(head + 6)}`
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
async function copyBundle(pkgPath, pkg, entries) {
|
|
148
|
-
const declaration = pkg.dsh?.client
|
|
149
|
-
if (declaration?.platform !== 'web') {
|
|
150
|
-
throw new Error(`${pkg.name} is in the upstream Web roster but has no web dsh.client declaration.`)
|
|
151
|
-
}
|
|
152
|
-
const source = resolve(dirname(pkgPath), clientBundleRelativePath(pkg))
|
|
153
|
-
const contents = await readFile(source)
|
|
154
|
-
const rev = shortHash(contents)
|
|
155
|
-
const destination = join(outputRoot, 'plugins', pkg.name, 'client.js')
|
|
156
|
-
await mkdir(dirname(destination), { recursive: true })
|
|
157
|
-
await writeFile(destination, contents)
|
|
158
|
-
|
|
159
|
-
entries.push({
|
|
160
|
-
id: pkg.name,
|
|
161
|
-
url: `/plugins/${pkg.name}/client.js?rev=${rev}`,
|
|
162
|
-
rev,
|
|
163
|
-
...(Array.isArray(declaration.inject) ? { inject: declaration.inject } : {}),
|
|
164
|
-
...(declaration.immediately === true ? { immediately: true } : {}),
|
|
165
|
-
})
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
async function main() {
|
|
169
|
-
if (!await isDirectory(shellDist)) {
|
|
170
|
-
throw new Error('Upstream Web shell is not built. Run `pnpm --workspace-root run build:web` first.')
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const packagesByName = new Map()
|
|
174
|
-
for (const pkgPath of await findPackageJsonFiles(join(repoRoot, 'packages'))) {
|
|
175
|
-
const pkg = JSON.parse(await readFile(pkgPath, 'utf8'))
|
|
176
|
-
if (typeof pkg.name === 'string') packagesByName.set(pkg.name, { path: pkgPath, pkg })
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const declared = []
|
|
180
|
-
for (const patchPath of deploymentPatches) {
|
|
181
|
-
declared.push(...deploymentPackageNames(await readFile(patchPath, 'utf8')))
|
|
182
|
-
}
|
|
183
|
-
declared.push(...edgeClientPackages)
|
|
184
|
-
const roster = []
|
|
185
|
-
const seen = new Set()
|
|
186
|
-
for (const name of declared) {
|
|
187
|
-
if (seen.has(name)) continue
|
|
188
|
-
const record = packagesByName.get(name)
|
|
189
|
-
// Vendor entries and package subpaths have no workspace package root; only
|
|
190
|
-
// workspace packages can declare the client bundles assembled here.
|
|
191
|
-
if (record === undefined) continue
|
|
192
|
-
if (record.pkg.dsh?.client?.platform !== 'web') continue
|
|
193
|
-
seen.add(name)
|
|
194
|
-
roster.push(name)
|
|
195
|
-
}
|
|
196
|
-
await rm(outputRoot, { recursive: true, force: true })
|
|
197
|
-
await cp(shellDist, outputRoot, { recursive: true })
|
|
198
|
-
// Match the published upstream Web package: production assets do not ship
|
|
199
|
-
// source maps, keeping the Worker upload compact without changing runtime JS.
|
|
200
|
-
await removeSourceMaps(outputRoot)
|
|
201
|
-
|
|
202
|
-
const entries = []
|
|
203
|
-
for (const name of roster) {
|
|
204
|
-
const record = packagesByName.get(name)
|
|
205
|
-
if (record === undefined) throw new Error(`Cannot resolve upstream Web package ${name}.`)
|
|
206
|
-
await copyBundle(record.path, record.pkg, entries)
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const selected = new Set(entries.map(entry => entry.id))
|
|
210
|
-
for (const entry of entries) {
|
|
211
|
-
for (const dependency of entry.inject ?? []) {
|
|
212
|
-
if (!selected.has(dependency) && !shellStaticPackages.has(dependency)) {
|
|
213
|
-
throw new Error(`${entry.id} injects missing Edge Web package ${dependency}.`)
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const graph = { rev: shortHash(JSON.stringify(entries)), entries }
|
|
219
|
-
const indexPath = join(outputRoot, 'index.html')
|
|
220
|
-
const index = await readFile(indexPath, 'utf8')
|
|
221
|
-
await writeFile(indexPath, injectOwnerSessionGuard(injectBootManifest(index, graph)))
|
|
222
|
-
// Cloudflare may serve index.html and SPA fallbacks without invoking the
|
|
223
|
-
// Worker. Apply the framing boundary at the asset layer so every alias of
|
|
224
|
-
// the executable shell receives the same policy while immutable assets can
|
|
225
|
-
// still bypass Worker execution.
|
|
226
|
-
await writeFile(join(outputRoot, '_headers'), assetSecurityHeaders)
|
|
227
|
-
console.log(`Assembled ${entries.length} upstream client plugins in ${relative(repoRoot, outputRoot)} (rev ${graph.rev}).`)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
await main()
|
package/scripts/bundle.mjs
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'node:module'
|
|
2
|
-
import { lstat, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { tmpdir } from 'node:os'
|
|
4
|
-
import { join } from 'node:path'
|
|
5
|
-
import { fileURLToPath } from 'node:url'
|
|
6
|
-
import { execa } from 'execa'
|
|
7
|
-
import edgePackage from '../package.json' with { type: 'json' }
|
|
8
|
-
import { requireGzipBudget } from './bundle-size.mjs'
|
|
9
|
-
import {
|
|
10
|
-
workerArtifactPath,
|
|
11
|
-
writeSourceModeWranglerConfig,
|
|
12
|
-
} from './wrangler-config.mjs'
|
|
13
|
-
|
|
14
|
-
const DIRECT_GZIP_BUDGET_BYTES = 900 * 1024
|
|
15
|
-
const appDirectory = fileURLToPath(new URL('..', import.meta.url))
|
|
16
|
-
const require = createRequire(import.meta.url)
|
|
17
|
-
const wranglerCli = require.resolve('wrangler')
|
|
18
|
-
const mode = process.argv[2]
|
|
19
|
-
|
|
20
|
-
if (mode !== 'direct' && mode !== 'isolated') {
|
|
21
|
-
process.stderr.write('Usage: node scripts/bundle.mjs <direct|isolated>\n')
|
|
22
|
-
process.exitCode = 2
|
|
23
|
-
} else {
|
|
24
|
-
const directory = await mkdtemp(join(tmpdir(), `dsh-edge-${mode}-bundle-`))
|
|
25
|
-
try {
|
|
26
|
-
const configFile = join(directory, 'wrangler.json')
|
|
27
|
-
const outputDirectory = join(directory, 'worker')
|
|
28
|
-
await writeSourceModeWranglerConfig(mode, configFile)
|
|
29
|
-
const result = await execa(process.execPath, [
|
|
30
|
-
wranglerCli,
|
|
31
|
-
'deploy',
|
|
32
|
-
'--config', configFile,
|
|
33
|
-
'--env', mode === 'direct' ? '' : 'isolated',
|
|
34
|
-
'--define',
|
|
35
|
-
`__DSH_EDGE_DEPLOYMENT_ID__:${JSON.stringify(`dsh-edge@${edgePackage.version}/${mode}`)}`,
|
|
36
|
-
'--dry-run',
|
|
37
|
-
'--outdir', outputDirectory,
|
|
38
|
-
], {
|
|
39
|
-
cwd: appDirectory,
|
|
40
|
-
reject: false,
|
|
41
|
-
all: true,
|
|
42
|
-
})
|
|
43
|
-
const output = result.all ?? `${result.stdout}\n${result.stderr}`
|
|
44
|
-
process.stdout.write(output.endsWith('\n') ? output : `${output}\n`)
|
|
45
|
-
if (result.exitCode !== 0) {
|
|
46
|
-
process.exitCode = result.exitCode
|
|
47
|
-
} else {
|
|
48
|
-
if (mode === 'direct') {
|
|
49
|
-
const bytes = requireGzipBudget(output, DIRECT_GZIP_BUDGET_BYTES)
|
|
50
|
-
process.stdout.write(
|
|
51
|
-
`Direct Worker gzip budget: ${bytes}/${DIRECT_GZIP_BUDGET_BYTES} bytes.\n`,
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
await publishArtifact(mode, join(outputDirectory, 'index.js'))
|
|
55
|
-
}
|
|
56
|
-
} catch (error) {
|
|
57
|
-
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`)
|
|
58
|
-
process.exitCode = 1
|
|
59
|
-
} finally {
|
|
60
|
-
await rm(directory, { recursive: true, force: true })
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async function publishArtifact(runtimeMode, source) {
|
|
65
|
-
const destination = workerArtifactPath(runtimeMode)
|
|
66
|
-
const destinationDirectory = fileURLToPath(new URL(`../worker/${runtimeMode}`, import.meta.url))
|
|
67
|
-
await removeGeneratedDirectory(destinationDirectory)
|
|
68
|
-
await mkdir(destinationDirectory, { recursive: true, mode: 0o755 })
|
|
69
|
-
const bundle = (await readFile(source, 'utf8'))
|
|
70
|
-
.replace(/\n\/\/# sourceMappingURL=index\.js\.map\s*$/u, '\n')
|
|
71
|
-
await writeFile(destination, bundle, { encoding: 'utf8', mode: 0o644, flag: 'wx' })
|
|
72
|
-
process.stdout.write(`Wrote ${runtimeMode} Worker artifact to ${destination}.\n`)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function removeGeneratedDirectory(directory) {
|
|
76
|
-
try {
|
|
77
|
-
const entry = await lstat(directory)
|
|
78
|
-
if (!entry.isDirectory() || entry.isSymbolicLink()) {
|
|
79
|
-
throw new Error(`Refusing to replace non-directory Worker artifact path: ${directory}`)
|
|
80
|
-
}
|
|
81
|
-
} catch (error) {
|
|
82
|
-
if (error?.code === 'ENOENT') return
|
|
83
|
-
throw error
|
|
84
|
-
}
|
|
85
|
-
await rm(directory, { recursive: true })
|
|
86
|
-
}
|