agnostics 0.0.3 → 0.0.4
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/lib/bases/_BaseOnCall.js +41 -0
- package/lib/bases/_BasePrompt.js +33 -0
- package/lib/bases/_BaseRemote.js +118 -0
- package/lib/bases/index.js +12 -0
- package/lib/helpers/_Yargs.js +15 -49
- package/lib/index.js +3 -0
- package/lib/loaders/_Loaders.js +62 -0
- package/lib/loaders/index.js +9 -0
- package/lib/specification/_Properties.js +15 -8
- package/lib/targets/_InquirerTarget.js +15 -0
- package/lib/targets/_WebviewTarget.js +182 -0
- package/lib/targets/index.js +9 -0
- package/lib/workers/_AutoRunner.js +67 -0
- package/lib/workers/_AutoWorker.js +136 -0
- package/lib/workers/index.js +9 -0
- package/package.json +3 -3
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//////////////////////////////////////////
|
|
2
|
+
// //
|
|
3
|
+
// //
|
|
4
|
+
// BASE //
|
|
5
|
+
// //
|
|
6
|
+
// //
|
|
7
|
+
//////////////////////////////////////////
|
|
8
|
+
|
|
9
|
+
import { CreateLogger } from 'agnostics/logger'
|
|
10
|
+
const { ERR } = CreateLogger( import.meta.url )
|
|
11
|
+
|
|
12
|
+
export class BaseOnCall {
|
|
13
|
+
|
|
14
|
+
className = 'Base'
|
|
15
|
+
|
|
16
|
+
$listenerCbs = {}
|
|
17
|
+
|
|
18
|
+
constructor() {}
|
|
19
|
+
|
|
20
|
+
$call( name, res ) {
|
|
21
|
+
const alls = ['all', '*']
|
|
22
|
+
const includesKey = Object.keys(this.$listenerCbs).includes(name)
|
|
23
|
+
if (!includesKey) return ERR(`NONEXISTENT:`, name)
|
|
24
|
+
for (const callback of this.$listenerCbs[name]) callback(res)
|
|
25
|
+
for (const all of alls) {
|
|
26
|
+
if (this.$listenerCbs[all]) {
|
|
27
|
+
for (const callback of this.$listenerCbs[all]) callback(name, res)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
on( name, callback ) {
|
|
34
|
+
const isAll = name === 'all' || name === '*'
|
|
35
|
+
const includesKey = Object.keys(this.$listenerCbs).includes(name)
|
|
36
|
+
if (!includesKey && !isAll) return ERR(`NONEXISTENT:`, name)
|
|
37
|
+
if (!this.$listenerCbs[name]) this.$listenerCbs[name] = []
|
|
38
|
+
this.$listenerCbs[name].push(callback)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//////////////////////////////////////////
|
|
2
|
+
// //
|
|
3
|
+
// //
|
|
4
|
+
// BASE PROMPT //
|
|
5
|
+
// //
|
|
6
|
+
// //
|
|
7
|
+
//////////////////////////////////////////
|
|
8
|
+
|
|
9
|
+
import { CreateLogger } from 'agnostics/logger'
|
|
10
|
+
const { SAY, HMM, ERR, YAY } = CreateLogger( import.meta.url )
|
|
11
|
+
|
|
12
|
+
import { BaseOnCall } from './_BaseOnCall.js'
|
|
13
|
+
|
|
14
|
+
export class BasePrompt extends BaseOnCall {
|
|
15
|
+
|
|
16
|
+
className = 'BasePrompt:BaseOnCall'
|
|
17
|
+
|
|
18
|
+
constructor( ) {
|
|
19
|
+
super()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
ask( config = { message: '', schema: {} } ) {
|
|
23
|
+
|
|
24
|
+
HMM('ASK NOT IMPLEMENTED:', this.className)
|
|
25
|
+
const { message, schema } = config
|
|
26
|
+
return new Promise( resolve => {
|
|
27
|
+
const res = {}
|
|
28
|
+
for (const [key,value] of Object.entries(schema)) res[key] = true
|
|
29
|
+
resolve(res)
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
//////////////////////////////////////////
|
|
2
|
+
// //
|
|
3
|
+
// //
|
|
4
|
+
// BASE REMOTE //
|
|
5
|
+
// //
|
|
6
|
+
// //
|
|
7
|
+
//////////////////////////////////////////
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
|
|
11
|
+
CLASSES MUST HAVE:
|
|
12
|
+
|
|
13
|
+
1) single config on constructor
|
|
14
|
+
2) some way to post / receive
|
|
15
|
+
3)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { CreateLogger } from 'agnostics/logger'
|
|
21
|
+
const { SAY, ERR, YAY, HMM, HUH } = CreateLogger( import.meta.url )
|
|
22
|
+
|
|
23
|
+
import { BaseOnCall } from './_BaseOnCall.js'
|
|
24
|
+
|
|
25
|
+
export class BaseRemote extends BaseOnCall {
|
|
26
|
+
|
|
27
|
+
className = 'BaseRemote:BaseOnCall'
|
|
28
|
+
|
|
29
|
+
$methodReqs = {
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
constructor() {
|
|
33
|
+
super()
|
|
34
|
+
this.isIniting = true
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
construct() {}
|
|
38
|
+
|
|
39
|
+
getMethodListenerNames() {
|
|
40
|
+
let methodNames = new Set()
|
|
41
|
+
let current = this
|
|
42
|
+
const exclude = ['getMethodListenerNames', 'construct', 'on']
|
|
43
|
+
|
|
44
|
+
do {
|
|
45
|
+
Object.getOwnPropertyNames(current).forEach(prop => {
|
|
46
|
+
if (prop === 'constructor') return
|
|
47
|
+
const desc = Object.getOwnPropertyDescriptor(current, prop)
|
|
48
|
+
if (!desc || prop[0] === '$' || exclude.includes(prop)) return
|
|
49
|
+
if (
|
|
50
|
+
typeof desc.value === 'function' ||
|
|
51
|
+
typeof desc.get === 'function' ||
|
|
52
|
+
typeof desc.set === 'function'
|
|
53
|
+
) {
|
|
54
|
+
methodNames.add(prop)
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
current = Object.getPrototypeOf(current)
|
|
59
|
+
} while (current !== null && current !== Object.prototype)
|
|
60
|
+
|
|
61
|
+
methodNames = [...methodNames].sort()
|
|
62
|
+
const listenerNames = Object.keys(this.$listenerCbs || {})
|
|
63
|
+
return { methodNames, listenerNames }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
$initMethodsAndListeners( methodNames, listenerNames ) {
|
|
67
|
+
|
|
68
|
+
// ========= METHODS =========
|
|
69
|
+
|
|
70
|
+
for (const name of methodNames) {
|
|
71
|
+
this.$methodReqs[name] = []
|
|
72
|
+
|
|
73
|
+
this[name] = (...req) => {
|
|
74
|
+
|
|
75
|
+
const type = 'method'
|
|
76
|
+
const index = this.$methodReqs[name].length
|
|
77
|
+
this.$sendRequest( type, name, req, index )
|
|
78
|
+
return new Promise( resolve => {
|
|
79
|
+
this.$methodReqs[name].push( resolve )
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ========= CALLBACKS =========
|
|
85
|
+
|
|
86
|
+
for (const listenerCb of listenerNames) {
|
|
87
|
+
this.$listenerCbs[listenerCb] = []
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ========= READY =========
|
|
91
|
+
|
|
92
|
+
YAY('REMOTE:', this.className)
|
|
93
|
+
|
|
94
|
+
HUH('➔ METHODS:', methodNames.join(' '))
|
|
95
|
+
HUH('➔ LISTENERS:', listenerNames.join(' '))
|
|
96
|
+
this.isIniting = false
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
$handleResponse( type, index, name, res ) {
|
|
100
|
+
|
|
101
|
+
if (type === 'method') {
|
|
102
|
+
const resolver = this.$methodReqs[name]?.[index]
|
|
103
|
+
if (!resolver) {
|
|
104
|
+
ERR(`REMOTE NO RESOLVER:`, name, index)
|
|
105
|
+
} else {
|
|
106
|
+
this.$methodReqs[name][index](res)
|
|
107
|
+
this.$methodReqs[name][index] = null
|
|
108
|
+
const allDone = this.$methodReqs[name].every(item => item === null)
|
|
109
|
+
if (allDone) this.$methodReqs[name] = []
|
|
110
|
+
}
|
|
111
|
+
} else if (type === 'listener') {
|
|
112
|
+
this.$call( name, res )
|
|
113
|
+
} else {
|
|
114
|
+
HMM(`UNKNOWN RESPONSE:`, {type,name})
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
}
|
package/lib/helpers/_Yargs.js
CHANGED
|
@@ -10,45 +10,17 @@ import { Obj, isArr, isNum, isBool } from '../inputs/index.js'
|
|
|
10
10
|
import { NormaliseAccept } from './_Parsers.js'
|
|
11
11
|
|
|
12
12
|
import { CreateLogger } from '../logger/index.js'
|
|
13
|
+
import path from 'path'
|
|
13
14
|
const { SAY, ERR, HMM, HUH } = CreateLogger( import.meta.url )
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
async function LoadYargs() {
|
|
17
|
-
|
|
18
|
-
if (!globalThis.yargsLib || !globalThis.yargsHideBin) {
|
|
19
|
-
try {
|
|
20
|
-
globalThis.yargsLib = (await import ('yargs')).default
|
|
21
|
-
globalThis.yargsHideBin = (await import ('yargs/helpers')).hideBin
|
|
22
|
-
return true
|
|
23
|
-
} catch(err) {
|
|
24
|
-
return ERR(`YARGS UNAVAILABLE`, err)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function LoadGlobby() {
|
|
30
|
-
|
|
31
|
-
if (!globalThis.globbyLib || !globalThis.pathExtname) {
|
|
32
|
-
try {
|
|
33
|
-
globalThis.globbyLib = (await import ('globby')).globby
|
|
34
|
-
globalThis.pathExtname = (await import ('path')).extname
|
|
35
|
-
return true
|
|
36
|
-
} catch(err) {
|
|
37
|
-
return ERR(`GLOBS UNAVAILABLE`, err)
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
17
|
|
|
42
18
|
async function GetYargsFiles( value, extensions ) {
|
|
43
19
|
|
|
44
20
|
try {
|
|
45
|
-
|
|
46
|
-
if (!(await LoadGlobby())) return []
|
|
47
|
-
|
|
48
|
-
|
|
49
21
|
const anything = (extensions.length === 0 || extensions.includes('*'))
|
|
50
22
|
|
|
51
|
-
const found = await globalThis.
|
|
23
|
+
const found = await globalThis.Yargs(value, {
|
|
52
24
|
onlyFiles: true,
|
|
53
25
|
expandDirectories: false,
|
|
54
26
|
caseSensitiveMatch: false
|
|
@@ -56,7 +28,7 @@ async function GetYargsFiles( value, extensions ) {
|
|
|
56
28
|
|
|
57
29
|
const exts = extensions.map( ext => ext.toLowerCase().replaceAll('.',''))
|
|
58
30
|
const files = anything ? found : found.filter(file => {
|
|
59
|
-
const ext =
|
|
31
|
+
const ext = path.extname(file).replaceAll('.','')
|
|
60
32
|
return exts.includes(ext)
|
|
61
33
|
})
|
|
62
34
|
|
|
@@ -111,14 +83,17 @@ export function ConvertYargsProperty( def, override = {} ) {
|
|
|
111
83
|
|
|
112
84
|
const array = def.gui == 'files' || isArr(def.type)
|
|
113
85
|
|
|
114
|
-
|
|
86
|
+
const yargsDef = Object.assign({
|
|
115
87
|
array,
|
|
116
88
|
describe: def.description,
|
|
117
89
|
type: GetYargsType(def.type),
|
|
118
|
-
coerce: def.
|
|
90
|
+
coerce: def.onsend,
|
|
119
91
|
default: def.default,
|
|
120
|
-
accept: NormaliseAccept( def.accept )
|
|
92
|
+
accept: NormaliseAccept( def.accept ),
|
|
93
|
+
choices: def.enum
|
|
121
94
|
}, override)
|
|
95
|
+
|
|
96
|
+
return yargsDef
|
|
122
97
|
}
|
|
123
98
|
|
|
124
99
|
|
|
@@ -136,7 +111,7 @@ export function YargsProcessWorkaround() {
|
|
|
136
111
|
|
|
137
112
|
export class YargsCommand {
|
|
138
113
|
|
|
139
|
-
command =
|
|
114
|
+
command = null
|
|
140
115
|
description = 'N/A'
|
|
141
116
|
version = 'N/A'
|
|
142
117
|
positionals = {}
|
|
@@ -148,7 +123,6 @@ export class YargsCommand {
|
|
|
148
123
|
|
|
149
124
|
constructor( { positionals, options = {}, description = 'N/A', version = 'N/A' } ) {
|
|
150
125
|
|
|
151
|
-
|
|
152
126
|
this.description = description
|
|
153
127
|
this.version = version
|
|
154
128
|
|
|
@@ -189,15 +163,12 @@ export class YargsCommand {
|
|
|
189
163
|
|
|
190
164
|
async run( runCallback = async yargsData => {} ) {
|
|
191
165
|
|
|
192
|
-
if (!(await LoadYargs())) return
|
|
193
166
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const args = globalThis.yargsHideBin( process.argv )
|
|
197
|
-
const instance = globalThis.yargsLib( args )
|
|
167
|
+
const args = globalThis.YargsBin( process.argv )
|
|
168
|
+
const instance = globalThis.Yargs( args )
|
|
198
169
|
|
|
199
170
|
instance.command(
|
|
200
|
-
this.command,
|
|
171
|
+
'$0 '+ this.command + ' [run]', // hack
|
|
201
172
|
this.description,
|
|
202
173
|
yargsData => {
|
|
203
174
|
const positionals = Object.entries(this.positionals)
|
|
@@ -270,13 +241,8 @@ export class YargsCLI {
|
|
|
270
241
|
|
|
271
242
|
async run( runCallback = async (cmdKey, yargsData) => {} ) {
|
|
272
243
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
// YargsProcessWorkaround()
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const args = globalThis.yargsHideBin( process.argv )
|
|
279
|
-
const instance = globalThis.yargsLib( args )
|
|
244
|
+
const args = globalThis.YargsBin( process.argv )
|
|
245
|
+
const instance = globalThis.Yargs( args )
|
|
280
246
|
|
|
281
247
|
for (const [cmdKey, cmdObj] of Object.entries(this.$commands)) {
|
|
282
248
|
|
package/lib/index.js
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
//////////////////////////////////////////
|
|
2
|
+
// //
|
|
3
|
+
// //
|
|
4
|
+
// LOADERS //
|
|
5
|
+
// //
|
|
6
|
+
// //
|
|
7
|
+
//////////////////////////////////////////
|
|
8
|
+
|
|
9
|
+
import { CreateLogger } from 'agnostics/logger'
|
|
10
|
+
const { YAY, ERR, SAY } = CreateLogger( import.meta.url )
|
|
11
|
+
|
|
12
|
+
import path from 'path'
|
|
13
|
+
import fs from 'fs/promises'
|
|
14
|
+
import { pathToFileURL } from 'node:url'
|
|
15
|
+
|
|
16
|
+
export async function LoadDep( name, url ) {
|
|
17
|
+
|
|
18
|
+
const [ base, stem ] = url.split('.')
|
|
19
|
+
let mod
|
|
20
|
+
|
|
21
|
+
if (!globalThis[base]) {
|
|
22
|
+
try {
|
|
23
|
+
mod = (await import (base))
|
|
24
|
+
} catch(err) {
|
|
25
|
+
try {
|
|
26
|
+
const pkgDir = path.join(process.cwd(), 'node_modules', base)
|
|
27
|
+
const pkgJsonPath = path.join(pkgDir, 'package.json')
|
|
28
|
+
const pkgJson = JSON.parse(await fs.readFile(pkgJsonPath))
|
|
29
|
+
let entry = pkgJson.main || pkgJson.module || 'index.js'
|
|
30
|
+
if (pkgJson.exports && pkgJson.exports['.']) {
|
|
31
|
+
const exportIndex = pkgJson.exports['.']?.index || pkgJson.exports['.']
|
|
32
|
+
entry = exportIndex.replace(/^\.\//, '')
|
|
33
|
+
}
|
|
34
|
+
const fullEntryPath = path.join(pkgDir, entry)
|
|
35
|
+
const entryUrl = pathToFileURL(fullEntryPath).href
|
|
36
|
+
mod = (await import (entryUrl))
|
|
37
|
+
} catch(err) {
|
|
38
|
+
return ERR(`FAIL:`, name, err.message)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (stem) mod = mod[stem]
|
|
42
|
+
globalThis[name] = mod
|
|
43
|
+
YAY(`LOADED:`, name)
|
|
44
|
+
return globalThis[name]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function LoadWebview() {
|
|
49
|
+
return await LoadDep('Webview', '@webviewjs/webview.Application')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function LoadYargs() {
|
|
53
|
+
|
|
54
|
+
const YargsLib = await LoadDep('Yargs', 'yargs.default')
|
|
55
|
+
const YargsBin = await LoadDep('YargsBin', 'yargs/helpers.hideBin')
|
|
56
|
+
|
|
57
|
+
return { YargsLib, YargsBin }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function LoadGlobby() {
|
|
61
|
+
return await LoadDep('Globby', 'globby.globby')
|
|
62
|
+
}
|
|
@@ -8,6 +8,21 @@
|
|
|
8
8
|
|
|
9
9
|
export const Properties = {
|
|
10
10
|
|
|
11
|
+
// --------- EVENTS ---------
|
|
12
|
+
|
|
13
|
+
onsend: {
|
|
14
|
+
description: 'callback for checking value before sending',
|
|
15
|
+
matches: [ 'oncheck', 'validate', 'coerce', 'check']
|
|
16
|
+
},
|
|
17
|
+
onreceive: {
|
|
18
|
+
description: 'callback for checking value when received',
|
|
19
|
+
matches: [ 'onreceive', 'validate', 'coerce', 'check']
|
|
20
|
+
},
|
|
21
|
+
onupdate: {
|
|
22
|
+
description: 'callback for updated value',
|
|
23
|
+
matches: [ 'onupdate', 'update', 'change', 'onchange']
|
|
24
|
+
},
|
|
25
|
+
|
|
11
26
|
// --------- DEFINITION ---------
|
|
12
27
|
|
|
13
28
|
type: {
|
|
@@ -68,14 +83,6 @@ export const Properties = {
|
|
|
68
83
|
description: 'property can only be read',
|
|
69
84
|
matches: ['readonly', 'ro']
|
|
70
85
|
},
|
|
71
|
-
oncheck: {
|
|
72
|
-
description: 'callback for checking value',
|
|
73
|
-
matches: [ 'oncheck', 'validate', 'coerce', 'check']
|
|
74
|
-
},
|
|
75
|
-
onupdate: {
|
|
76
|
-
description: 'callback for updated value',
|
|
77
|
-
matches: [ 'onupdate', 'update', 'change', 'onchange']
|
|
78
|
-
},
|
|
79
86
|
|
|
80
87
|
// --------- STRUCTURAL ---------
|
|
81
88
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
// @inquirer/prompts
|
|
4
|
+
|
|
5
|
+
async function LoadInquirer() {
|
|
6
|
+
|
|
7
|
+
if (!globalThis.inquirerLib) {
|
|
8
|
+
try {
|
|
9
|
+
globalThis.inquirerLib = (await import ('inquirer')).inquirer
|
|
10
|
+
return true
|
|
11
|
+
} catch(err) {
|
|
12
|
+
return ERR(`GLOBS UNAVAILABLE`, err)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
//////////////////////////////////////////
|
|
2
|
+
// //
|
|
3
|
+
// //
|
|
4
|
+
// WINDOW TARGET //
|
|
5
|
+
// //
|
|
6
|
+
// //
|
|
7
|
+
//////////////////////////////////////////
|
|
8
|
+
|
|
9
|
+
import { CreateLogger } from 'agnostics/logger'
|
|
10
|
+
const { SAY, ERR, YAY, HUH, HMM } = CreateLogger( import.meta.url )
|
|
11
|
+
import fs from 'node:fs'
|
|
12
|
+
|
|
13
|
+
import { BaseRemote } from '../bases/_BaseRemote.js'
|
|
14
|
+
|
|
15
|
+
export const WebviewConfig = {
|
|
16
|
+
|
|
17
|
+
app: {
|
|
18
|
+
controlFlow: 0, // Poll | WaitUntil | Exit | ExitWithCode
|
|
19
|
+
waitTime: 0, // ms for WaitUntil
|
|
20
|
+
exitCode: 0, // for ExitWithCode
|
|
21
|
+
},
|
|
22
|
+
browser: {
|
|
23
|
+
resizable: true,
|
|
24
|
+
title: 'Hello World',
|
|
25
|
+
width: 800,
|
|
26
|
+
height: 600,
|
|
27
|
+
x: null,
|
|
28
|
+
y: null,
|
|
29
|
+
contentProtection: false,
|
|
30
|
+
alwaysOnTop: false,
|
|
31
|
+
alwaysOnBottom: false,
|
|
32
|
+
visible: true,
|
|
33
|
+
decorations: true, // false = borderless/frameless
|
|
34
|
+
transparent: false, // needs CSS background: transparent
|
|
35
|
+
visibleOnAllWorkspaces: false,
|
|
36
|
+
maximized: false,
|
|
37
|
+
maximizable: true,
|
|
38
|
+
minimizable: true,
|
|
39
|
+
focused: true,
|
|
40
|
+
fullscreen: null // Exclusive | Borderless | null
|
|
41
|
+
},
|
|
42
|
+
webview: {
|
|
43
|
+
enableDevtools: true,
|
|
44
|
+
incognito: false,
|
|
45
|
+
userAgent: null,
|
|
46
|
+
child: false,
|
|
47
|
+
preload: null,
|
|
48
|
+
hotkeysZoom: false,
|
|
49
|
+
theme: 2, // Light | Dark | System
|
|
50
|
+
clipboard: false,
|
|
51
|
+
autoplay: false,
|
|
52
|
+
backForwardNavigationGestures: false
|
|
53
|
+
},
|
|
54
|
+
showDevTools: false
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const PreloadScript = `
|
|
58
|
+
|
|
59
|
+
console.log('[PRELOAD] safe ipc')
|
|
60
|
+
|
|
61
|
+
globalThis.gt = globalThis
|
|
62
|
+
|
|
63
|
+
gt.postMessage = gt.webkit.messageHandlers.ipc.postMessage || gt.ipc.postMessage || gt.chrome.webview.postMessage
|
|
64
|
+
|
|
65
|
+
`
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
export class WebviewTarget extends BaseRemote {
|
|
69
|
+
|
|
70
|
+
className = 'WebviewTarget:BaseRemote:BaseOnCall'
|
|
71
|
+
|
|
72
|
+
$instance = null
|
|
73
|
+
|
|
74
|
+
constructor( source, config = {} ) {
|
|
75
|
+
|
|
76
|
+
super()
|
|
77
|
+
|
|
78
|
+
if (!source) throw Error('NO SOURCE')
|
|
79
|
+
|
|
80
|
+
config = { ...WebviewConfig, ...(config || {})}
|
|
81
|
+
|
|
82
|
+
const clean = obj => Object.fromEntries(
|
|
83
|
+
Object.entries(obj).filter(([, v]) => v != null))
|
|
84
|
+
|
|
85
|
+
const isUrl = source.startsWith('http') || source.startsWith('www')
|
|
86
|
+
const isPath = source.startsWith('/')||source.startsWith('.')
|
|
87
|
+
const isHtml = source.trim().startsWith('<')
|
|
88
|
+
|
|
89
|
+
if (isUrl) {
|
|
90
|
+
config.webview.url = source
|
|
91
|
+
} else if (isPath && !isHtml) {
|
|
92
|
+
config.webview.html = fs.readFileSync(source, 'utf8')
|
|
93
|
+
SAY('READ HTML:', source)
|
|
94
|
+
} else {
|
|
95
|
+
config.webview.html = source
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const appOpts = clean({...WebviewConfig.app, ...config.app})
|
|
99
|
+
const browserOpts = clean({...WebviewConfig.browser, ...config.browser})
|
|
100
|
+
const webviewOpts = clean({...WebviewConfig.webview, ...config.webview})
|
|
101
|
+
|
|
102
|
+
webviewOpts.preload = PreloadScript
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
const app = new globalThis.Webview( appOpts )
|
|
106
|
+
const browser = app.createBrowserWindow( browserOpts )
|
|
107
|
+
const webview = browser.createWebview( webviewOpts )
|
|
108
|
+
|
|
109
|
+
if (config.showDevTools && !webview.isDevtoolsOpen()) webview.openDevtools()
|
|
110
|
+
if (!config.showDevTools && webview.isDevtoolsOpen()) webview.closeDevtools()
|
|
111
|
+
|
|
112
|
+
app.onEvent(event => {
|
|
113
|
+
|
|
114
|
+
if (event === 0) {
|
|
115
|
+
SAY('WINDOW CLOSE REQ:', event)
|
|
116
|
+
this.$call('closing', 0)
|
|
117
|
+
browser.close()
|
|
118
|
+
} else if (event === 1) {
|
|
119
|
+
SAY('APP CLOSE REQ:', event)
|
|
120
|
+
this.$call('closing', 1)
|
|
121
|
+
app.close()
|
|
122
|
+
} else {
|
|
123
|
+
SAY('MISC EVENT:', event)
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
webview.onIpcMessage( message => {
|
|
128
|
+
SAY('WEBVIEW MESSAGE:', message)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
this.$instance = { app, browser, webview }
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
construct( ...constructArguments ) {
|
|
136
|
+
|
|
137
|
+
const { app, browser, webview } = this.$instance
|
|
138
|
+
|
|
139
|
+
const args = constructArguments.map( arg => JSON.stringify(arg) ).join(', ')
|
|
140
|
+
|
|
141
|
+
SAY('EVAL')
|
|
142
|
+
webview.evaluateScript(`
|
|
143
|
+
|
|
144
|
+
console.log('EVAL')
|
|
145
|
+
|
|
146
|
+
gt.app = new App( ${args} )
|
|
147
|
+
|
|
148
|
+
gt.onIpcMessage = async message => {
|
|
149
|
+
|
|
150
|
+
console.log('NEW MESSAGE', message)
|
|
151
|
+
// const res = await app[name](...req)
|
|
152
|
+
|
|
153
|
+
// parentPort.postMessage({
|
|
154
|
+
// type,
|
|
155
|
+
// name,
|
|
156
|
+
// index,
|
|
157
|
+
// res
|
|
158
|
+
// })
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
app.on('*', (name, res) => {
|
|
162
|
+
|
|
163
|
+
console.log('WOOOO', name, res)
|
|
164
|
+
gt.webkit.messageHandlers.ipc.postMessage('data')
|
|
165
|
+
gt.ipc.postMessage({
|
|
166
|
+
type: 'listener',
|
|
167
|
+
name,
|
|
168
|
+
res
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
`)
|
|
172
|
+
|
|
173
|
+
// ========= INIT =========
|
|
174
|
+
|
|
175
|
+
return new Promise( resolve => {
|
|
176
|
+
HMM('INITIIALISE (wait)')
|
|
177
|
+
this.resolveConstruct = resolve
|
|
178
|
+
app.run()
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//////////////////////////////////////////
|
|
2
|
+
// //
|
|
3
|
+
// //
|
|
4
|
+
// AUTO INSTANCE //
|
|
5
|
+
// //
|
|
6
|
+
// //
|
|
7
|
+
//////////////////////////////////////////
|
|
8
|
+
|
|
9
|
+
import { workerData, parentPort } from 'worker_threads'
|
|
10
|
+
const { importUrl, importName, constructArguments } = workerData
|
|
11
|
+
|
|
12
|
+
import { CreateLogger } from 'agnostics/logger'
|
|
13
|
+
const { SAY, ERR } = CreateLogger( import.meta.url )
|
|
14
|
+
import path from 'node:path'
|
|
15
|
+
|
|
16
|
+
async function RunInstance() {
|
|
17
|
+
|
|
18
|
+
// ========= INSTANTIATE =========
|
|
19
|
+
|
|
20
|
+
const cwdImportUrl = path.resolve( process.cwd(), importUrl )
|
|
21
|
+
const imported = await import(cwdImportUrl)
|
|
22
|
+
const instantiator = imported[importName]
|
|
23
|
+
if (!instantiator) return ERR('NO INSTANCE:', importUrl, importName)
|
|
24
|
+
|
|
25
|
+
// ========= INSTANCE =========
|
|
26
|
+
|
|
27
|
+
const instance = new instantiator()
|
|
28
|
+
await instance.construct( ...constructArguments )
|
|
29
|
+
|
|
30
|
+
// ========= REQ / RES =========
|
|
31
|
+
|
|
32
|
+
parentPort.on( 'message', async ({type,name,req,index}) => {
|
|
33
|
+
|
|
34
|
+
const res = await instance[name](...req)
|
|
35
|
+
|
|
36
|
+
parentPort.postMessage({
|
|
37
|
+
type,
|
|
38
|
+
name,
|
|
39
|
+
index,
|
|
40
|
+
res
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// ========= ALL EVENTS =========
|
|
45
|
+
|
|
46
|
+
instance.on('*', (name, res) => {
|
|
47
|
+
|
|
48
|
+
parentPort.postMessage({
|
|
49
|
+
type: 'listener',
|
|
50
|
+
name,
|
|
51
|
+
res
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// ========= INIT METHODS =========
|
|
56
|
+
|
|
57
|
+
const methodListenerNames = instance.getMethodListenerNames()
|
|
58
|
+
|
|
59
|
+
parentPort.postMessage({
|
|
60
|
+
name: 'methodListenerNames',
|
|
61
|
+
res: methodListenerNames
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
RunInstance()
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
//////////////////////////////////////////
|
|
2
|
+
// //
|
|
3
|
+
// //
|
|
4
|
+
// AUTO WORKER //
|
|
5
|
+
// //
|
|
6
|
+
// //
|
|
7
|
+
//////////////////////////////////////////
|
|
8
|
+
|
|
9
|
+
import { CreateLogger } from 'agnostics/logger'
|
|
10
|
+
const { SAY, ERR, YAY, HMM, HUH } = CreateLogger( import.meta.url )
|
|
11
|
+
|
|
12
|
+
import { Worker } from 'node:worker_threads'
|
|
13
|
+
import { BaseRemote } from '../bases/_BaseRemote.js'
|
|
14
|
+
|
|
15
|
+
import { fileURLToPath } from 'node:url'
|
|
16
|
+
import path from 'node:path'
|
|
17
|
+
|
|
18
|
+
// Get the directory of the CURRENT file
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
20
|
+
const _dir = path.dirname(__filename)
|
|
21
|
+
|
|
22
|
+
// We use a template literal or a joined string that Rollup
|
|
23
|
+
// can't resolve statically during the build.
|
|
24
|
+
const workerFilename = '_AutoRunner.js';
|
|
25
|
+
export const AutoRunnerPath = path.join(_dir, 'workers', workerFilename);
|
|
26
|
+
|
|
27
|
+
export class AutoWorker extends BaseRemote {
|
|
28
|
+
|
|
29
|
+
className = 'AutoWorker:BaseRemote'
|
|
30
|
+
|
|
31
|
+
$worker = null
|
|
32
|
+
|
|
33
|
+
$listenerCbs = {
|
|
34
|
+
error: [],
|
|
35
|
+
exit: [],
|
|
36
|
+
online: []
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
importUrl = null
|
|
40
|
+
importName = null
|
|
41
|
+
|
|
42
|
+
constructor( importPath ) {
|
|
43
|
+
|
|
44
|
+
super() // Base = on / $call pattern
|
|
45
|
+
|
|
46
|
+
let [ importUrl, importName ] = importPath.split('?')
|
|
47
|
+
if (importName === '') importName = 'default'
|
|
48
|
+
|
|
49
|
+
this.importUrl = importUrl
|
|
50
|
+
this.importName = importName
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
$sendRequest( type, name, req, index) {
|
|
55
|
+
|
|
56
|
+
this.$worker.postMessage({
|
|
57
|
+
type,
|
|
58
|
+
name,
|
|
59
|
+
req,
|
|
60
|
+
index
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
construct( ...constructArguments ) {
|
|
65
|
+
|
|
66
|
+
const { importUrl, importName } = this
|
|
67
|
+
|
|
68
|
+
this.className = importName + ':' + this.className
|
|
69
|
+
|
|
70
|
+
this.$worker = new Worker(
|
|
71
|
+
new URL('./_AutoRunner.js?worker', import.meta.url).pathname,
|
|
72
|
+
{
|
|
73
|
+
type: 'module',
|
|
74
|
+
workerData: {
|
|
75
|
+
importUrl,
|
|
76
|
+
importName,
|
|
77
|
+
constructArguments
|
|
78
|
+
}})
|
|
79
|
+
|
|
80
|
+
// ========= MESSAGES =========
|
|
81
|
+
|
|
82
|
+
this.$worker.on('message', message => {
|
|
83
|
+
|
|
84
|
+
// ========= INIT =========
|
|
85
|
+
|
|
86
|
+
if (message.name === 'methodListenerNames') {
|
|
87
|
+
|
|
88
|
+
const { methodNames, listenerNames } = message.res
|
|
89
|
+
this.$initMethodsAndListeners( methodNames, listenerNames )
|
|
90
|
+
|
|
91
|
+
} else {
|
|
92
|
+
|
|
93
|
+
// ========= RESPONSE =========
|
|
94
|
+
|
|
95
|
+
const { type, index, name, res } = message
|
|
96
|
+
this.$handleResponse( type, index, name, res )
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (this.finishConstruct) {
|
|
100
|
+
HUH('INITED / finishConstruct')
|
|
101
|
+
this.finishConstruct()
|
|
102
|
+
this.finishConstruct = null
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
// ========= ERROR =========
|
|
107
|
+
|
|
108
|
+
this.$worker.on('error', message => {
|
|
109
|
+
ERR('ERROR:', message)
|
|
110
|
+
this.$call( 'error', message )
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
// ========= EXIT =========
|
|
114
|
+
|
|
115
|
+
this.$worker.on('exit', message => {
|
|
116
|
+
HMM('EXIT:', message)
|
|
117
|
+
this.$call( 'exit', message )
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// ========= ONLINE =========
|
|
121
|
+
|
|
122
|
+
this.$worker.on('online', message => {
|
|
123
|
+
YAY('WORKER ONLINE')
|
|
124
|
+
this.$call( 'online', true )
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
// ========= INIT =========
|
|
128
|
+
|
|
129
|
+
return new Promise( resolve => {
|
|
130
|
+
HMM('INITIIALISE (wait)')
|
|
131
|
+
this.finishConstruct = resolve
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agnostics",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"author": "Autr <g@sinnott.cc>",
|
|
5
5
|
"description": "featherless birds",
|
|
6
|
+
"esversion": 6,
|
|
7
|
+
"type": "module",
|
|
6
8
|
"exports": {
|
|
7
9
|
".": {
|
|
8
10
|
"types": "./types/index.d.ts",
|
|
@@ -26,7 +28,5 @@
|
|
|
26
28
|
}
|
|
27
29
|
},
|
|
28
30
|
"files": [ "lib", "types" ],
|
|
29
|
-
"esversion": 6,
|
|
30
|
-
"type": "module",
|
|
31
31
|
"dependencies": {}
|
|
32
32
|
}
|