pinokiod 7.2.15 → 7.2.17

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": "7.2.15",
3
+ "version": "7.2.17",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -22,8 +22,6 @@
22
22
  drawerItemId: "",
23
23
  drawerTab: "preview"
24
24
  };
25
- let pendingRegistryImport = null;
26
-
27
25
  function resolveNotificationSound() {
28
26
  try {
29
27
  const raw = localStorage.getItem(SOUND_PREF_STORAGE_KEY);
@@ -1251,68 +1249,6 @@
1251
1249
  }
1252
1250
  }
1253
1251
 
1254
- function writeRegistryPopup(popup, message) {
1255
- try {
1256
- if (!popup || popup.closed || !popup.document) {
1257
- return;
1258
- }
1259
- popup.document.title = "Pinokio draft import";
1260
- popup.document.body.innerHTML = `<div style="font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;padding:24px;color:#111827;">${String(message || "").replace(/[&<>"]/g, (ch) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" }[ch]))}</div>`;
1261
- } catch (_) {
1262
- }
1263
- }
1264
-
1265
- async function completeRegistryDraftImport(pending, payload) {
1266
- const response = await fetch("/registry/draft-import/complete", {
1267
- method: "POST",
1268
- headers: {
1269
- "Content-Type": "application/json"
1270
- },
1271
- body: JSON.stringify({
1272
- draft: pending.draftId,
1273
- token: payload.token,
1274
- registry: payload.registry,
1275
- app: payload.app || ""
1276
- })
1277
- });
1278
- const data = await response.json().catch(() => null);
1279
- if (!response.ok || !data || !data.editUrl) {
1280
- const detail = data && data.status ? ` (${data.status})` : "";
1281
- throw new Error(((data && data.error) || "Import failed.") + detail);
1282
- }
1283
- if (pending.popup && !pending.popup.closed) {
1284
- pending.popup.postMessage({
1285
- type: "pinokio:draft-import-result",
1286
- ok: true,
1287
- editUrl: data.editUrl
1288
- }, pending.registryOrigin);
1289
- } else {
1290
- window.location.href = data.editUrl;
1291
- }
1292
- }
1293
-
1294
- window.addEventListener("message", (event) => {
1295
- const payload = event.data || {};
1296
- if (!payload || payload.type !== "pinokio:draft-import-token" || !payload.token || !payload.registry) {
1297
- return;
1298
- }
1299
- const pending = pendingRegistryImport;
1300
- if (!pending || event.origin !== pending.registryOrigin) {
1301
- return;
1302
- }
1303
- pendingRegistryImport = null;
1304
- void completeRegistryDraftImport(pending, payload).catch((error) => {
1305
- const message = error && error.message ? error.message : "Import failed.";
1306
- if (pending.popup && !pending.popup.closed) {
1307
- pending.popup.postMessage({
1308
- type: "pinokio:draft-import-result",
1309
- ok: false,
1310
- error: message
1311
- }, pending.registryOrigin);
1312
- }
1313
- });
1314
- });
1315
-
1316
1252
  function closeDraftDrawer() {
1317
1253
  state.drawerItemId = "";
1318
1254
  const existing = document.getElementById("pinokio-draft-drawer-root");
@@ -1421,14 +1357,6 @@
1421
1357
  if (!item || !item.id || !canPublishToRegistry(item)) {
1422
1358
  return;
1423
1359
  }
1424
- const popup = window.open("about:blank", "_blank");
1425
- if (!popup) {
1426
- const fallback = new URL("/registry/draft-import/start", window.location.origin);
1427
- fallback.searchParams.set("draft", item.id);
1428
- window.location.href = fallback.toString();
1429
- return;
1430
- }
1431
- writeRegistryPopup(popup, "Opening registry...");
1432
1360
  try {
1433
1361
  const url = new URL("/registry/draft-import/authorize-url", window.location.origin);
1434
1362
  url.searchParams.set("draft", item.id);
@@ -1439,17 +1367,24 @@
1439
1367
  }
1440
1368
  });
1441
1369
  const data = await response.json().catch(() => null);
1442
- if (!response.ok || !data || !data.authorizeUrl || !data.registryOrigin) {
1370
+ if (!response.ok || !data || !data.authorizeUrl) {
1443
1371
  throw new Error((data && data.error) || "Unable to start registry import.");
1444
1372
  }
1445
- pendingRegistryImport = {
1446
- draftId: data.draftId || item.id,
1447
- registryOrigin: data.registryOrigin,
1448
- popup
1449
- };
1450
- popup.location.href = data.authorizeUrl;
1373
+ const openResponse = await fetch("/pinokio/open", {
1374
+ method: "POST",
1375
+ headers: {
1376
+ "Content-Type": "application/json"
1377
+ },
1378
+ body: JSON.stringify({
1379
+ url: data.authorizeUrl,
1380
+ surface: "browser"
1381
+ })
1382
+ });
1383
+ if (!openResponse.ok) {
1384
+ throw new Error("Unable to open registry.");
1385
+ }
1451
1386
  } catch (error) {
1452
- writeRegistryPopup(popup, error && error.message ? error.message : "Unable to start registry import.");
1387
+ window.alert(error && error.message ? error.message : "Unable to start registry import.");
1453
1388
  }
1454
1389
  }
1455
1390
 
@@ -45,7 +45,7 @@ function renderMessage(res, status, title, message) {
45
45
  </html>`)
46
46
  }
47
47
 
48
- function renderImportLauncher(res, { authorizeUrl, draftId, registryOrigin, autoOpen }) {
48
+ function renderImportLauncher(res, { authorizeUrl, autoOpen }) {
49
49
  res.status(200).send(`<!doctype html>
50
50
  <html>
51
51
  <head>
@@ -63,68 +63,48 @@ function renderImportLauncher(res, { authorizeUrl, draftId, registryOrigin, auto
63
63
  <body>
64
64
  <div class="box">
65
65
  <h1>Import draft</h1>
66
- <p id="status">${autoOpen ? "Opening the registry authorization window..." : "Click Open registry to authorize the import."}</p>
66
+ <p id="status">${autoOpen ? "Opening the registry authorization page in your browser..." : "Click Open registry to authorize the import."}</p>
67
67
  <button id="open" type="button">Open registry</button>
68
- <div class="muted" style="margin-top:12px;">Keep this Pinokio window open until the registry draft editor opens.</div>
68
+ <div class="muted" style="margin-top:12px;">The registry will return to Pinokio after authorization.</div>
69
69
  </div>
70
70
  <script>
71
71
  window.__PINOKIO_DRAFT_IMPORT_VERSION = "metadata-b64";
72
72
  const authorizeUrl = ${JSON.stringify(authorizeUrl)};
73
- const draftId = ${JSON.stringify(draftId)};
74
- const registryOrigin = ${JSON.stringify(registryOrigin)};
75
73
  const autoOpen = ${JSON.stringify(Boolean(autoOpen))};
76
74
  const statusEl = document.getElementById("status");
77
75
  const openButton = document.getElementById("open");
78
- let registryWindow = null;
79
76
 
80
77
  function setStatus(message) {
81
78
  statusEl.textContent = message;
82
79
  }
83
80
 
84
- function openRegistry() {
85
- registryWindow = window.open(authorizeUrl, "_blank");
86
- if (!registryWindow) {
87
- setStatus("The registry window was blocked. Click Open registry to continue.");
88
- } else {
89
- setStatus("Authorize the import in the registry window.");
90
- }
91
- }
92
-
93
- async function completeImport(payload) {
94
- setStatus("Uploading draft to the registry...");
95
- const response = await fetch("/registry/draft-import/complete", {
81
+ async function openRegistry() {
82
+ setStatus("Opening registry in your browser...");
83
+ const response = await fetch("/pinokio/open", {
96
84
  method: "POST",
97
85
  headers: { "Content-Type": "application/json" },
98
86
  body: JSON.stringify({
99
- draft: draftId,
100
- token: payload.token,
101
- registry: payload.registry,
102
- app: payload.app || ""
87
+ url: authorizeUrl,
88
+ surface: "browser"
103
89
  })
104
90
  });
105
- const data = await response.json().catch(() => null);
106
- if (!response.ok || !data || !data.editUrl) {
107
- const detail = data && data.status ? " (" + data.status + ")" : "";
108
- throw new Error(((data && data.error) || "Import failed.") + detail);
91
+ if (!response.ok) {
92
+ throw new Error("Unable to open registry.");
109
93
  }
110
- try {
111
- if (registryWindow && !registryWindow.closed) registryWindow.close();
112
- } catch (_) {}
113
- window.location.href = data.editUrl;
94
+ setStatus("Authorize the import in your browser.");
114
95
  }
115
96
 
116
- window.addEventListener("message", (event) => {
117
- if (event.origin !== registryOrigin) return;
118
- const payload = event.data || {};
119
- if (payload.type !== "pinokio:draft-import-token" || !payload.token || !payload.registry) return;
120
- completeImport(payload).catch((error) => {
121
- setStatus(error && error.message ? error.message : "Import failed.");
97
+ openButton.addEventListener("click", () => {
98
+ openRegistry().catch((error) => {
99
+ setStatus(error && error.message ? error.message : "Unable to open registry.");
122
100
  });
123
101
  });
124
-
125
- openButton.addEventListener("click", openRegistry);
126
102
  if (autoOpen) {
127
- window.setTimeout(openRegistry, 100);
103
+ window.setTimeout(() => {
104
+ openRegistry().catch((error) => {
105
+ setStatus(error && error.message ? error.message : "Unable to open registry.");
106
+ });
107
+ }, 100);
128
108
  }
129
109
  </script>
130
110
  </body>
@@ -150,6 +130,21 @@ function requestOrigin(req) {
150
130
  return `${req.protocol || "http"}://${host}`
151
131
  }
152
132
 
133
+ function buildDraftImportReturnUrl(req, item, bundle) {
134
+ const returnUrl = new URL("/registry/draft-import/callback", requestOrigin(req))
135
+ returnUrl.searchParams.set("draft", item.id)
136
+ if (bundle.appSlug) returnUrl.searchParams.set("app", bundle.appSlug)
137
+ return returnUrl.toString()
138
+ }
139
+
140
+ function buildAuthorizeUrl(req, registryBase, item, bundle) {
141
+ const authorizeUrl = new URL("/draft-import/authorize", registryBase)
142
+ authorizeUrl.searchParams.set("handoff", "callback")
143
+ authorizeUrl.searchParams.set("return", buildDraftImportReturnUrl(req, item, bundle))
144
+ if (bundle.appSlug) authorizeUrl.searchParams.set("app", bundle.appSlug)
145
+ return authorizeUrl
146
+ }
147
+
153
148
  async function findDraftById(drafts, id) {
154
149
  const normalized = String(id || "").trim()
155
150
  if (!normalized) return null
@@ -312,16 +307,11 @@ function registerDraftImportRoutes(app, options = {}) {
312
307
  if (!registryBase) {
313
308
  return res.status(400).json({ error: "The registry URL is invalid." })
314
309
  }
315
- const authorizeUrl = new URL("/draft-import/authorize", registryBase)
316
- authorizeUrl.searchParams.set("handoff", "post_message")
317
- authorizeUrl.searchParams.set("origin", requestOrigin(req))
318
- authorizeUrl.searchParams.set("wait", "1")
319
- if (bundle.appSlug) authorizeUrl.searchParams.set("app", bundle.appSlug)
310
+ const authorizeUrl = buildAuthorizeUrl(req, registryBase, item, bundle)
320
311
  res.setHeader("Cache-Control", "no-store")
321
312
  return res.json({
322
313
  draftId: item.id,
323
- authorizeUrl: authorizeUrl.toString(),
324
- registryOrigin: new URL(registryBase).origin
314
+ authorizeUrl: authorizeUrl.toString()
325
315
  })
326
316
  }))
327
317
 
@@ -339,16 +329,11 @@ function registerDraftImportRoutes(app, options = {}) {
339
329
  if (!registryBase) {
340
330
  return renderMessage(res, 400, "Registry unavailable", "The registry URL is invalid.")
341
331
  }
342
- const authorizeUrl = new URL("/draft-import/authorize", registryBase)
343
- authorizeUrl.searchParams.set("handoff", "post_message")
344
- authorizeUrl.searchParams.set("origin", requestOrigin(req))
345
- if (bundle.appSlug) authorizeUrl.searchParams.set("app", bundle.appSlug)
332
+ const authorizeUrl = buildAuthorizeUrl(req, registryBase, item, bundle)
346
333
  res.setHeader("Cache-Control", "no-store")
347
334
  res.setHeader("Cross-Origin-Opener-Policy", "unsafe-none")
348
335
  return renderImportLauncher(res, {
349
336
  authorizeUrl: authorizeUrl.toString(),
350
- draftId: item.id,
351
- registryOrigin: new URL(registryBase).origin,
352
337
  autoOpen: req.query.auto === "1"
353
338
  })
354
339
  }))