ddeck-remote 0.0.0-stage → 0.9.7-beta
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 +202 -0
- package/NOTICE +40 -0
- package/README.md +96 -2
- package/THIRD-PARTY-LICENSES.md +69 -0
- package/cordis.patch.yml +22 -0
- package/icon.svg +6 -0
- package/install.cmd +4 -0
- package/install.ps1 +119 -0
- package/install.sh +95 -0
- package/lib/admin-trust.js +64 -0
- package/lib/client.js +751 -0
- package/lib/constants.js +11 -0
- package/lib/gateway-bundle.js +7063 -0
- package/lib/gateway.js +275 -0
- package/lib/index.js +1088 -0
- package/lib/mobile/index.js +82 -0
- package/lib/mobile/skin.css +1904 -0
- package/lib/mobile/skin.js +3614 -0
- package/lib/node-forge-bundle.js +17841 -0
- package/lib/qr-bundle.js +1990 -0
- package/lib/tls.js +173 -0
- package/locale/en.json +4 -0
- package/locale/ru.json +4 -0
- package/package.json +63 -4
- package/uninstall.ps1 +60 -0
- package/uninstall.sh +31 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Our own mobile page.
|
|
3
|
+
*
|
|
4
|
+
* The document the phone opens is still the harness's own client bundle — rewriting it
|
|
5
|
+
* from scratch would mean reimplementing the whole conversation surface against DSH's
|
|
6
|
+
* API, and that is a different project. What we own is the *layer*: the layout, the
|
|
7
|
+
* labels, the sizes, the languages. The plugin injects that layer on the way out, so any
|
|
8
|
+
* client gets it — the stock plugin's mobile layer is not involved at all.
|
|
9
|
+
*
|
|
10
|
+
* This is deliberately the same layer that was measured on a real phone, moved from the
|
|
11
|
+
* app into the plugin. Keeping one copy means the phone cannot end up with two skins
|
|
12
|
+
* fighting: the app's injection recognises the plugin's marker and steps aside.
|
|
13
|
+
*
|
|
14
|
+
* @module dsh-remote/mobile
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { readFile } from 'node:fs/promises'
|
|
18
|
+
import { dirname, join } from 'node:path'
|
|
19
|
+
import { fileURLToPath } from 'node:url'
|
|
20
|
+
|
|
21
|
+
/** Where the layer's sources live beside this module. */
|
|
22
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
23
|
+
|
|
24
|
+
/** Marker the app's injection looks for before applying its own layer. */
|
|
25
|
+
export const LAYER_MARKER = 'data-dsh-remote-layer'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Read the layer's sources.
|
|
29
|
+
*
|
|
30
|
+
* Read at startup rather than inlined: the layer is plain CSS and JS, and rebuilding the
|
|
31
|
+
* gateway bundle for a colour change would be a needless step between thinking and
|
|
32
|
+
* seeing it on the phone.
|
|
33
|
+
*
|
|
34
|
+
* @returns {Promise<{ css: string, js: string }>}
|
|
35
|
+
*/
|
|
36
|
+
export async function readLayer() {
|
|
37
|
+
// Two layouts exist: sources beside this file, and the gateway bundle one directory up
|
|
38
|
+
// where `import.meta.url` no longer points into `mobile/`. Trying both keeps the layer
|
|
39
|
+
// readable whether the plugin runs from its sources or from the bundle.
|
|
40
|
+
const candidates = [here, join(here, 'mobile')]
|
|
41
|
+
for (const directory of candidates) {
|
|
42
|
+
try {
|
|
43
|
+
const [css, js] = await Promise.all([
|
|
44
|
+
readFile(join(directory, 'skin.css'), 'utf8'),
|
|
45
|
+
readFile(join(directory, 'skin.js'), 'utf8'),
|
|
46
|
+
])
|
|
47
|
+
return { css, js }
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (error?.code !== 'ENOENT') throw error
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
throw new Error('dsh-remote: mobile layer sources are missing (skin.css, skin.js)')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Put the layer into a document.
|
|
57
|
+
*
|
|
58
|
+
* The layer goes before `</head>` so the page paints with the layout already applied: a
|
|
59
|
+
* layer that arrives after the first paint shows the desktop furniture for a frame, and
|
|
60
|
+
* on a phone that frame is the thing people remember.
|
|
61
|
+
*
|
|
62
|
+
* @param {string} html - the harness document.
|
|
63
|
+
* @param {{ css: string, js: string }} layer
|
|
64
|
+
* @param {'ru' | 'en'} language
|
|
65
|
+
* @returns {string}
|
|
66
|
+
*/
|
|
67
|
+
export function injectLayer(html, layer, language) {
|
|
68
|
+
const marker = ` ${LAYER_MARKER}="${language}"`
|
|
69
|
+
const head = `<style${marker} data-dsh-remote-part="css">${layer.css}</style>`
|
|
70
|
+
const body = `<script data-dsh-remote-part="js">${layer.js}</script>`
|
|
71
|
+
let output = html
|
|
72
|
+
const headIndex = output.indexOf('</head>')
|
|
73
|
+
if (headIndex === -1) {
|
|
74
|
+
// A document without a head is not ours to reason about; prepending keeps the layer
|
|
75
|
+
// effective without guessing where a missing element would have been.
|
|
76
|
+
output = head + output
|
|
77
|
+
} else {
|
|
78
|
+
output = `${output.slice(0, headIndex)}${head}${output.slice(headIndex)}`
|
|
79
|
+
}
|
|
80
|
+
const bodyIndex = output.lastIndexOf('</body>')
|
|
81
|
+
return bodyIndex === -1 ? `${output}${body}` : `${output.slice(0, bodyIndex)}${body}${output.slice(bodyIndex)}`
|
|
82
|
+
}
|