@pmate/cli 0.34.1 → 0.35.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/dist/index.js CHANGED
@@ -17612,7 +17612,7 @@ async function buildDesktop(args) {
17612
17612
  files: ["**/*"],
17613
17613
  asar: true,
17614
17614
  artifactName: "${productName}-${version}-${arch}.${ext}",
17615
- mac: { icon, target: args.dir ? ["dir"] : ["dmg", "zip"], category: "public.app-category.social-networking", hardenedRuntime: args.signed, extendInfo: { NSMicrophoneUsageDescription: `${c.productName} uses your microphone only when you record a voice message.` }, ...args.signed ? {} : { identity: "-", notarize: false } },
17615
+ mac: { icon, target: args.dir ? ["dir"] : ["dmg", "zip"], category: "public.app-category.social-networking", hardenedRuntime: args.signed, extendInfo: { NSMicrophoneUsageDescription: `${c.productName} uses your microphone for voice calls and voice messages.` }, ...args.signed ? {} : { identity: "-", notarize: false } },
17616
17616
  forceCodeSigning: args.signed
17617
17617
  };
17618
17618
  const configPath = import_node_path23.default.join(staging, "builder.json");
@@ -1,6 +1,7 @@
1
- const { app, BrowserWindow, session, shell, Menu } = require('electron')
1
+ const { app, BrowserWindow, session, shell, Menu, desktopCapturer } = require('electron')
2
2
  const path = require('node:path')
3
3
  const { createResourceHandler } = require('./resources.cjs')
4
+ const { installMediaPermissions } = require('./media.cjs')
4
5
  const config = require('./desktop-config.json')
5
6
  const manifest = require('./resource-manifest.json')
6
7
  app.setName(config.productName)
@@ -44,12 +45,7 @@ else {
44
45
  }
45
46
  return resources(request) ?? desktopSession.fetch(request, { bypassCustomProtocolHandlers: true })
46
47
  })
47
- desktopSession.setPermissionRequestHandler((contents, permission, callback, details) => {
48
- let trusted = false
49
- try { trusted = !!contents && new URL(contents.getURL()).origin === config.origin } catch {}
50
- callback(Boolean(trusted && permission === 'media' && details.mediaTypes?.length && details.mediaTypes.every(type => type === 'audio')))
51
- })
52
- desktopSession.setPermissionCheckHandler((_contents, permission, origin, details) => origin === config.origin && permission === 'media' && details.mediaType === 'audio')
48
+ installMediaPermissions(desktopSession, { origin: config.origin, getWindow: () => mainWindow, desktopCapturer, Menu })
53
49
  Menu.setApplicationMenu(Menu.buildFromTemplate([
54
50
  { role: 'appMenu' }, { role: 'editMenu' }, { role: 'viewMenu' }, { role: 'windowMenu' },
55
51
  { label: config.productName, submenu: [{ label: 'Back to app', click: () => { if (!mainWindow) createWindow(); else void mainWindow.loadURL(config.origin) } }] },
@@ -0,0 +1,38 @@
1
+ function installMediaPermissions(desktopSession, { origin, getWindow, desktopCapturer, Menu }) {
2
+ const sameOrigin = raw => { try { return new URL(raw).origin === origin } catch { return false } }
3
+ const trusted = contents => {
4
+ const window = getWindow()
5
+ return !!window && !window.isDestroyed() && contents === window.webContents && sameOrigin(contents.getURL())
6
+ }
7
+ desktopSession.setPermissionRequestHandler((contents, permission, callback, details) => {
8
+ const allowed = trusted(contents) && details.isMainFrame === true && sameOrigin(details.requestingUrl)
9
+ callback(Boolean(allowed && (permission === 'display-capture' || (permission === 'media' && details.mediaTypes?.length && details.mediaTypes.every(type => type === 'audio')))))
10
+ })
11
+ desktopSession.setPermissionCheckHandler((contents, permission, requestingOrigin, details) => {
12
+ return Boolean(trusted(contents) && sameOrigin(requestingOrigin) && details.isMainFrame === true && (permission === 'display-capture' || (permission === 'media' && details.mediaType === 'audio')))
13
+ })
14
+ desktopSession.setDisplayMediaRequestHandler(async (request, callback) => {
15
+ const window = getWindow()
16
+ const valid = () => window && !window.isDestroyed() && trusted(window.webContents) && request.frame && request.frame === window.webContents.mainFrame && sameOrigin(request.securityOrigin)
17
+ if (!valid() || !request.userGesture || !request.videoRequested || request.audioRequested) return callback(null)
18
+ let completed = false
19
+ const finish = source => {
20
+ if (completed) return
21
+ completed = true
22
+ try { callback(source && valid() ? { video: source } : null) } catch { /* Request frame was closed or navigated. */ }
23
+ }
24
+ try {
25
+ const sources = await desktopCapturer.getSources({ types: ['screen', 'window'], thumbnailSize: { width: 0, height: 0 } })
26
+ if (!valid() || !sources.length) return finish(null)
27
+ // Older macOS versions have no system picker. Native menu selection remains explicit.
28
+ const menu = Menu.buildFromTemplate([
29
+ { label: 'Choose a screen or window to share', enabled: false },
30
+ { type: 'separator' },
31
+ ...sources.map(source => ({ label: source.name.replace(/&/g, '&&'), click: () => finish(source) })),
32
+ { type: 'separator' }, { label: 'Cancel', click: () => finish(null) },
33
+ ])
34
+ menu.popup({ window, callback: () => finish(null) })
35
+ } catch { finish(null) }
36
+ }, { useSystemPicker: true })
37
+ }
38
+ module.exports = { installMediaPermissions }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pmate/cli",
3
- "version": "0.34.1",
3
+ "version": "0.35.0",
4
4
  "description": "CLI utilities for the pMate project",
5
5
  "license": "MIT",
6
6
  "bin": {