@citisen/dsh-font 0.1.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/LICENSE +21 -0
- package/README.md +241 -0
- package/README.zh.md +165 -0
- package/cordis.patch.yml +20 -0
- package/lib/client.js +847 -0
- package/lib/index.js +239 -0
- package/package.json +76 -0
- package/scripts/build-client.mjs +297 -0
- package/scripts/verify-client.mjs +410 -0
- package/scripts/verify-host.mjs +187 -0
- package/scripts/verify-profile.mjs +146 -0
- package/src/client.js +838 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end profile composition check.
|
|
3
|
+
*
|
|
4
|
+
* Loads the real `web` profile through dsh's own profile loader and asserts the
|
|
5
|
+
* composed entry list contains this bundle's row. This is the check that
|
|
6
|
+
* catches the failure modes a browser never explains: a bundle the loader
|
|
7
|
+
* cannot resolve, a patch file with the wrong shape, or a row that never made
|
|
8
|
+
* it into `dsh.profile.bundles`.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node scripts/verify-profile.mjs [profile-name]
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { readFileSync, statSync } from 'node:fs'
|
|
15
|
+
import { createRequire } from 'node:module'
|
|
16
|
+
import { dirname, join } from 'node:path'
|
|
17
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
18
|
+
|
|
19
|
+
/** The dsh installation whose own loader and composition rules this check uses. */
|
|
20
|
+
const DSH_ROOT =
|
|
21
|
+
process.env.DSH_CHECKOUT ??
|
|
22
|
+
join(
|
|
23
|
+
process.env.LOCALAPPDATA ?? 'C:/Users/Administrator/AppData/Local',
|
|
24
|
+
'npm-cache/_npx/1e7f6d9597241db0/node_modules/@deepseek-ai',
|
|
25
|
+
)
|
|
26
|
+
const INSTALL_ANCHOR = `${DSH_ROOT}/dsh/package.json`
|
|
27
|
+
|
|
28
|
+
const profileName = process.argv[2] ?? 'web'
|
|
29
|
+
|
|
30
|
+
const { loadProfile, composeEntries } = await import(
|
|
31
|
+
pathToFileURL(`${DSH_ROOT}/dsh-app-boot/lib/index.js`).href
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
const profile = loadProfile('dsh', profileName, INSTALL_ANCHOR)
|
|
35
|
+
|
|
36
|
+
/** This plugin's package name, as declared by its own manifest. */
|
|
37
|
+
const OWN_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
38
|
+
const PACKAGE_NAME = JSON.parse(readFileSync(join(OWN_ROOT, 'package.json'), 'utf8')).name
|
|
39
|
+
|
|
40
|
+
const layers = profile.layers.map((layer) => layer.packageName)
|
|
41
|
+
console.log(`verify-profile: profile "${profileName}" at ${profile.dir}`)
|
|
42
|
+
console.log(`verify-profile: layers = ${layers.join(' -> ')}`)
|
|
43
|
+
|
|
44
|
+
const index = layers.indexOf(PACKAGE_NAME)
|
|
45
|
+
if (index === -1) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`verify-profile: "${PACKAGE_NAME}" is not a profile layer. Add it to dsh.profile.bundles in ${profile.dir} (or install it with \`dsh plugin --profile ${profileName} add ${PACKAGE_NAME}\`)`,
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
if (index !== layers.length - 1) {
|
|
51
|
+
console.warn(
|
|
52
|
+
`verify-profile: warning — ${PACKAGE_NAME} is layer ${String(index)} of ${String(layers.length - 1)}; later layers override it`,
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const own = profile.layers[index]
|
|
57
|
+
console.log(`verify-profile: ${PACKAGE_NAME} patch = ${own.patchPath}`)
|
|
58
|
+
if (own.patches.length === 0) {
|
|
59
|
+
throw new Error(`verify-profile: the ${PACKAGE_NAME} patch layer contributed no entries`)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// The composed entry list is what the loader will actually mount.
|
|
63
|
+
const warnings = []
|
|
64
|
+
const entries = composeEntries(
|
|
65
|
+
[...profile.layers.map((layer) => layer.patches), profile.patches],
|
|
66
|
+
(message) => warnings.push(message),
|
|
67
|
+
)
|
|
68
|
+
const row = entries.find((entry) => entry.id === 'font')
|
|
69
|
+
if (row === undefined) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`verify-profile: the composed entry list has no "font" row; got [${entries.map((entry) => entry.id).join(', ')}]`,
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
if (row.name !== PACKAGE_NAME) {
|
|
75
|
+
throw new Error(`verify-profile: row "font" names "${String(row.name)}", expected "${PACKAGE_NAME}"`)
|
|
76
|
+
}
|
|
77
|
+
if (row.disabled === true) {
|
|
78
|
+
throw new Error('verify-profile: row "font" is disabled')
|
|
79
|
+
}
|
|
80
|
+
if (warnings.length > 0) {
|
|
81
|
+
console.warn(`verify-profile: loader patch warnings: ${warnings.join('; ')}`)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log(`verify-profile: OK — ${String(entries.length)} composed entries, "font" -> ${row.name}`)
|
|
85
|
+
|
|
86
|
+
// ── the browser roster ──────────────────────────────────────────────────────
|
|
87
|
+
// `dsh-client-modules` composes the browser roster from the same loader entries
|
|
88
|
+
// by reading each package's `dsh.client` and `exports["./client"]`. Reproduce
|
|
89
|
+
// that resolution here, because a mistake in either field fails only in the
|
|
90
|
+
// browser, as a bare 404 on a combo URL.
|
|
91
|
+
const profileDir = profile.dir
|
|
92
|
+
const require_ = createRequire(join(profileDir, 'package.json'))
|
|
93
|
+
|
|
94
|
+
let manifestPath
|
|
95
|
+
try {
|
|
96
|
+
// Resolve the way the loader resolves the row: from the profile directory,
|
|
97
|
+
// where pnpm materialized the dependency.
|
|
98
|
+
manifestPath = require_.resolve(`${PACKAGE_NAME}/package.json`)
|
|
99
|
+
} catch (error) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`verify-profile: cannot resolve ${PACKAGE_NAME}/package.json from ${profileDir}: ${String(error)}`,
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
|
|
106
|
+
const decl = manifest.dsh?.client
|
|
107
|
+
if (decl === undefined) throw new Error(`verify-profile: ${PACKAGE_NAME} declares no dsh.client`)
|
|
108
|
+
if (decl.platform !== 'web') {
|
|
109
|
+
throw new Error(`verify-profile: dsh.client.platform is "${String(decl.platform)}", expected "web"`)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const clientExport = manifest.exports?.['./client']
|
|
113
|
+
const clientRelative =
|
|
114
|
+
typeof clientExport === 'string' ? clientExport : clientExport?.default
|
|
115
|
+
if (typeof clientRelative !== 'string') {
|
|
116
|
+
throw new Error('verify-profile: exports["./client"] must be a string or an object with a string default')
|
|
117
|
+
}
|
|
118
|
+
const clientPath = join(dirname(manifestPath), clientRelative)
|
|
119
|
+
try {
|
|
120
|
+
statSync(clientPath)
|
|
121
|
+
} catch {
|
|
122
|
+
throw new Error(
|
|
123
|
+
`verify-profile: client bundle not found at ${clientPath} — run \`npm run build\` before launching`,
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// The bundle id must equal the package name the roster keys on.
|
|
128
|
+
const bundleSource = readFileSync(clientPath, 'utf8')
|
|
129
|
+
const declaredId = /__ModuleLoader__\.load\(\{\s*id:\s*"([^"]+)"/.exec(bundleSource)?.[1]
|
|
130
|
+
if (declaredId !== manifest.name) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`verify-profile: lib/client.js registers id "${String(declaredId)}" but the package is "${String(manifest.name)}"`,
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const inject = decl.inject ?? []
|
|
137
|
+
for (const dependency of inject) {
|
|
138
|
+
if (dependency === manifest.name) {
|
|
139
|
+
throw new Error('verify-profile: dsh.client.inject must not name the package itself')
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
console.log(
|
|
144
|
+
`verify-profile: OK — client roster entry id=${String(declaredId)} inject=[${inject.join(', ')}] immediately=${String(decl.immediately === true)}`,
|
|
145
|
+
)
|
|
146
|
+
console.log(`verify-profile: client bundle ${clientPath} (${String(bundleSource.length)} bytes)`)
|