pinokiod 6.0.63 → 6.0.65
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 +1 -1
- package/server/index.js +70 -0
- package/server/lib/inject_router.js +88 -3
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -3539,6 +3539,68 @@ class Server {
|
|
|
3539
3539
|
|
|
3540
3540
|
async renderMenu(req, uri, name, config, pathComponents, indexPath) {
|
|
3541
3541
|
if (config.menu) {
|
|
3542
|
+
const normalizeMenuInjectList = (value) => {
|
|
3543
|
+
if (!value) {
|
|
3544
|
+
return []
|
|
3545
|
+
}
|
|
3546
|
+
const values = Array.isArray(value) ? value : [value]
|
|
3547
|
+
const normalized = []
|
|
3548
|
+
const seen = new Set()
|
|
3549
|
+
for (const entry of values) {
|
|
3550
|
+
if (typeof entry !== "string") {
|
|
3551
|
+
continue
|
|
3552
|
+
}
|
|
3553
|
+
const raw = entry.trim()
|
|
3554
|
+
if (!raw) {
|
|
3555
|
+
continue
|
|
3556
|
+
}
|
|
3557
|
+
const parts = raw.split(",").map((item) => item.trim()).filter(Boolean)
|
|
3558
|
+
for (const part of parts) {
|
|
3559
|
+
if (part.length > 1024) {
|
|
3560
|
+
continue
|
|
3561
|
+
}
|
|
3562
|
+
if (seen.has(part)) {
|
|
3563
|
+
continue
|
|
3564
|
+
}
|
|
3565
|
+
seen.add(part)
|
|
3566
|
+
normalized.push(part)
|
|
3567
|
+
}
|
|
3568
|
+
}
|
|
3569
|
+
return normalized
|
|
3570
|
+
}
|
|
3571
|
+
const appendInjectQueryParam = (href, injectList) => {
|
|
3572
|
+
if (typeof href !== "string") {
|
|
3573
|
+
return href
|
|
3574
|
+
}
|
|
3575
|
+
const trimmedHref = href.trim()
|
|
3576
|
+
if (!trimmedHref || !injectList.length) {
|
|
3577
|
+
return href
|
|
3578
|
+
}
|
|
3579
|
+
let parsed
|
|
3580
|
+
let isAbsolute = false
|
|
3581
|
+
try {
|
|
3582
|
+
if (/^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(trimmedHref)) {
|
|
3583
|
+
isAbsolute = true
|
|
3584
|
+
parsed = new URL(trimmedHref)
|
|
3585
|
+
} else {
|
|
3586
|
+
parsed = new URL(trimmedHref, "http://localhost")
|
|
3587
|
+
}
|
|
3588
|
+
} catch (_) {
|
|
3589
|
+
return href
|
|
3590
|
+
}
|
|
3591
|
+
const seen = new Set(parsed.searchParams.getAll("__pinokio_inject"))
|
|
3592
|
+
for (const entry of injectList) {
|
|
3593
|
+
if (seen.has(entry)) {
|
|
3594
|
+
continue
|
|
3595
|
+
}
|
|
3596
|
+
seen.add(entry)
|
|
3597
|
+
parsed.searchParams.append("__pinokio_inject", entry)
|
|
3598
|
+
}
|
|
3599
|
+
if (isAbsolute) {
|
|
3600
|
+
return parsed.toString()
|
|
3601
|
+
}
|
|
3602
|
+
return `${parsed.pathname}${parsed.search}${parsed.hash}`
|
|
3603
|
+
}
|
|
3542
3604
|
|
|
3543
3605
|
// config.menu = [{
|
|
3544
3606
|
// base: "/",
|
|
@@ -3630,6 +3692,14 @@ class Server {
|
|
|
3630
3692
|
if (menuitem.href && menuitem.params) {
|
|
3631
3693
|
menuitem.href = menuitem.href + "?" + new URLSearchParams(menuitem.params).toString();
|
|
3632
3694
|
}
|
|
3695
|
+
if (menuitem.href) {
|
|
3696
|
+
const injectList = normalizeMenuInjectList(menuitem.inject)
|
|
3697
|
+
if (injectList.length > 0) {
|
|
3698
|
+
const hrefWithInject = appendInjectQueryParam(menuitem.href, injectList)
|
|
3699
|
+
menuitem.href = hrefWithInject
|
|
3700
|
+
config.menu[i].href = hrefWithInject
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3633
3703
|
|
|
3634
3704
|
|
|
3635
3705
|
if (menuitem.shell) {
|
|
@@ -80,6 +80,54 @@ const matchesInjectPattern = (pattern, targetUrl) => {
|
|
|
80
80
|
return candidates.some((candidate) => expression.test(candidate))
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
const normalizeInjectHrefList = (value) => {
|
|
84
|
+
if (!value) {
|
|
85
|
+
return []
|
|
86
|
+
}
|
|
87
|
+
const values = Array.isArray(value) ? value : [value]
|
|
88
|
+
const normalized = []
|
|
89
|
+
const seen = new Set()
|
|
90
|
+
for (const entry of values) {
|
|
91
|
+
if (typeof entry !== "string") {
|
|
92
|
+
continue
|
|
93
|
+
}
|
|
94
|
+
const raw = entry.trim()
|
|
95
|
+
if (!raw) {
|
|
96
|
+
continue
|
|
97
|
+
}
|
|
98
|
+
const parts = raw.split(",").map((item) => item.trim()).filter(Boolean)
|
|
99
|
+
for (const part of parts) {
|
|
100
|
+
if (part.length > 1024) {
|
|
101
|
+
continue
|
|
102
|
+
}
|
|
103
|
+
if (seen.has(part)) {
|
|
104
|
+
continue
|
|
105
|
+
}
|
|
106
|
+
seen.add(part)
|
|
107
|
+
normalized.push(part)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return normalized
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const parseFrameInjectEntries = (frameUrl) => {
|
|
114
|
+
if (typeof frameUrl !== "string") {
|
|
115
|
+
return []
|
|
116
|
+
}
|
|
117
|
+
const value = frameUrl.trim()
|
|
118
|
+
if (!value) {
|
|
119
|
+
return []
|
|
120
|
+
}
|
|
121
|
+
let parsed
|
|
122
|
+
try {
|
|
123
|
+
parsed = new URL(value)
|
|
124
|
+
} catch (_) {
|
|
125
|
+
return []
|
|
126
|
+
}
|
|
127
|
+
const entries = parsed.searchParams.getAll("__pinokio_inject")
|
|
128
|
+
return normalizeInjectHrefList(entries)
|
|
129
|
+
}
|
|
130
|
+
|
|
83
131
|
const resolveInjectLaunchUrl = async ({ workspace, workspaceRoot, launcher, hrefRaw }) => {
|
|
84
132
|
let hrefPath = hrefRaw
|
|
85
133
|
let querySuffix = ""
|
|
@@ -94,7 +142,14 @@ const resolveInjectLaunchUrl = async ({ workspace, workspaceRoot, launcher, href
|
|
|
94
142
|
|
|
95
143
|
let launchPath
|
|
96
144
|
if (hrefPath.startsWith("/")) {
|
|
97
|
-
|
|
145
|
+
const normalized = hrefPath.trim()
|
|
146
|
+
if (normalized.startsWith("/api/")) {
|
|
147
|
+
launchPath = `/raw/${normalized.slice("/api/".length)}`
|
|
148
|
+
} else if (normalized.startsWith("/_api/")) {
|
|
149
|
+
launchPath = `/raw/${normalized.slice("/_api/".length)}`
|
|
150
|
+
} else {
|
|
151
|
+
launchPath = normalized
|
|
152
|
+
}
|
|
98
153
|
} else {
|
|
99
154
|
const launcherRoot = launcher.launcher_root
|
|
100
155
|
? path.resolve(workspaceRoot, launcher.launcher_root)
|
|
@@ -120,7 +175,7 @@ const resolveInjectLaunchUrl = async ({ workspace, workspaceRoot, launcher, href
|
|
|
120
175
|
if (routeSegments.length === 0) {
|
|
121
176
|
return null
|
|
122
177
|
}
|
|
123
|
-
launchPath = `/
|
|
178
|
+
launchPath = `/raw/${encodeURIComponent(workspace)}/${routeSegments.join("/")}`
|
|
124
179
|
}
|
|
125
180
|
|
|
126
181
|
const queryParams = new URLSearchParams(querySuffix)
|
|
@@ -179,6 +234,37 @@ const createInjectRouter = ({ kernel }) => {
|
|
|
179
234
|
}
|
|
180
235
|
}
|
|
181
236
|
|
|
237
|
+
const frameUrl = typeof context.frameUrl === "string" ? context.frameUrl : ""
|
|
238
|
+
const frameInjectEntries = parseFrameInjectEntries(frameUrl)
|
|
239
|
+
if (frameInjectEntries.length > 0) {
|
|
240
|
+
const scripts = []
|
|
241
|
+
for (const hrefRaw of frameInjectEntries) {
|
|
242
|
+
const launchUrl = await resolveInjectLaunchUrl({
|
|
243
|
+
workspace,
|
|
244
|
+
workspaceRoot,
|
|
245
|
+
launcher,
|
|
246
|
+
hrefRaw
|
|
247
|
+
})
|
|
248
|
+
if (!launchUrl) {
|
|
249
|
+
continue
|
|
250
|
+
}
|
|
251
|
+
scripts.push(launchUrl)
|
|
252
|
+
}
|
|
253
|
+
const uniqueScripts = [...new Set(scripts)]
|
|
254
|
+
if (uniqueScripts.length > 0) {
|
|
255
|
+
return {
|
|
256
|
+
status: 200,
|
|
257
|
+
body: {
|
|
258
|
+
ok: true,
|
|
259
|
+
matched: true,
|
|
260
|
+
workspace,
|
|
261
|
+
scripts: uniqueScripts,
|
|
262
|
+
source: "frame_query"
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
182
268
|
let injectConfig = launcher.script.inject
|
|
183
269
|
if (typeof injectConfig === "function") {
|
|
184
270
|
if (injectConfig.constructor.name === "AsyncFunction") {
|
|
@@ -201,7 +287,6 @@ const createInjectRouter = ({ kernel }) => {
|
|
|
201
287
|
}
|
|
202
288
|
}
|
|
203
289
|
|
|
204
|
-
const frameUrl = typeof context.frameUrl === "string" ? context.frameUrl : ""
|
|
205
290
|
const scripts = []
|
|
206
291
|
for (const entry of entries) {
|
|
207
292
|
if (!entry.match.some((pattern) => matchesInjectPattern(pattern, frameUrl))) {
|