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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "6.0.63",
3
+ "version": "6.0.65",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
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
- launchPath = hrefPath
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 = `/api/${encodeURIComponent(workspace)}/${routeSegments.join("/")}`
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))) {