@ham2k/extension-tools 0.10.0 → 0.12.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/h2kext-build.mjs +48 -1
- package/h2kext.mjs +18 -2
- package/package.json +1 -1
package/h2kext-build.mjs
CHANGED
|
@@ -202,6 +202,49 @@ function liquidBrowserBuild(fromDir) {
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
/// What liquidjs times its `renderLimit` with, and what it is rewritten to.
|
|
206
|
+
///
|
|
207
|
+
/// liquidjs looks for `global.performance`, then `window.performance`, and
|
|
208
|
+
/// falls back to `Date.now()`. The sandbox has neither global, and its `Date`
|
|
209
|
+
/// is the APP clock (sdk/src/appClock.ts), which time travel speeds up — so a
|
|
210
|
+
/// render limit of 250 ms is measured in travelled time, and at 1000x a
|
|
211
|
+
/// template taking a quarter of a real millisecond fails with `template render
|
|
212
|
+
/// limit exceeded`. The sandbox's own `performance` stays on real time.
|
|
213
|
+
const LIQUID_TIMER = "(typeof global === 'object' && global.performance)"
|
|
214
|
+
const LIQUID_REAL_TIMER = "(typeof performance === 'object' && performance)"
|
|
215
|
+
|
|
216
|
+
/// Points liquidjs's render timer at the real clock — see [LIQUID_TIMER].
|
|
217
|
+
///
|
|
218
|
+
/// A rewrite of that one expression in that one file, rather than a `define`
|
|
219
|
+
/// for `global` across the whole bundle: a define would quietly retarget
|
|
220
|
+
/// every other library's `typeof global` check too, which is how bundles
|
|
221
|
+
/// tell Node from a browser. Throws when the expression is not found exactly
|
|
222
|
+
/// once, so a liquidjs upgrade that changes it fails the build instead of
|
|
223
|
+
/// bringing the travelled timer back unnoticed.
|
|
224
|
+
///
|
|
225
|
+
/// Matched on the file's name, not on the path this preset aliases: an exact
|
|
226
|
+
/// path misses the same file spelled another way (a Windows drive letter's
|
|
227
|
+
/// case) or a caller's own `alias.liquidjs`, and a filter that never fires
|
|
228
|
+
/// never reaches the check either. Every unminified build carries the
|
|
229
|
+
/// expression once; a minified one fails the check, loudly.
|
|
230
|
+
function liquidRealClockPlugin() {
|
|
231
|
+
return {
|
|
232
|
+
name: "ham2k-liquid-real-clock",
|
|
233
|
+
setup(build) {
|
|
234
|
+
build.onLoad({ filter: /[\\/]liquidjs[\\/]dist[\\/]liquid\.[^\\/]+\.m?js$/ }, async (args) => {
|
|
235
|
+
const source = await readFile(args.path, "utf8")
|
|
236
|
+
const found = source.split(LIQUID_TIMER).length - 1
|
|
237
|
+
if (found !== 1) {
|
|
238
|
+
throw new BuildError(
|
|
239
|
+
`liquidjs at ${args.path}: expected its render timer \`${LIQUID_TIMER}\` once, found it ${found} times — the real-clock rewrite needs updating`,
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
return { contents: source.replace(LIQUID_TIMER, LIQUID_REAL_TIMER), loader: "js" }
|
|
243
|
+
})
|
|
244
|
+
},
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
205
248
|
/// Where the author's SDK keeps the file that stands in for the timer globals
|
|
206
249
|
/// (sdk/src/timers.ts), or null if it has none. Resolved from the CALLER's
|
|
207
250
|
/// directory for the same reason as [liquidBrowserBuild]: it must be the very
|
|
@@ -261,7 +304,11 @@ export function buildOptionsFor({ entry, outfile, manifest = {}, dir = process.c
|
|
|
261
304
|
...(liquid ? { liquidjs: liquid } : {}),
|
|
262
305
|
...alias,
|
|
263
306
|
},
|
|
264
|
-
plugins: [
|
|
307
|
+
plugins: [
|
|
308
|
+
sharedModulesPlugin({ sharedDependencies: manifest.sharedDependencies, api: manifest.api, inline }),
|
|
309
|
+
liquidRealClockPlugin(),
|
|
310
|
+
...(rest.plugins ?? []),
|
|
311
|
+
],
|
|
265
312
|
inject: [...(timersFile ? [timersFile] : []), ...(rest.inject ?? [])],
|
|
266
313
|
}
|
|
267
314
|
}
|
package/h2kext.mjs
CHANGED
|
@@ -35,14 +35,24 @@ import yazl from "yazl"
|
|
|
35
35
|
/// 6 adds the scene's `spectrum` control and `host.setRadioSpectrum`; 7 adds
|
|
36
36
|
/// `host.setRadio` (`tuneRadio` stays its alias) with power, keyer speed,
|
|
37
37
|
/// tuner, passband and antennas, the keying calls, what `readRadio` reports of
|
|
38
|
-
/// them, and the scene's host-fed `radio` values
|
|
39
|
-
|
|
38
|
+
/// them, and the scene's host-fed `radio` values; 8 adds the Developer
|
|
39
|
+
/// panel's `target: 'developer'` settings and leaves a settings panel with
|
|
40
|
+
/// nothing to show out of the Settings list; 9 hands `ctx.getQsos`'s QSOs
|
|
41
|
+
/// frozen, from the one copy of the log every extension shares, and adds the
|
|
42
|
+
/// `chasing` hook category.
|
|
43
|
+
export const H2KEXT_API_VERSION = 9
|
|
40
44
|
|
|
41
45
|
/// The first API with `host.webSocket`. A manifest declaring `webSockets`
|
|
42
46
|
/// under an older one is refused: an older app would install it and fail only
|
|
43
47
|
/// when it tried to connect.
|
|
44
48
|
export const WEB_SOCKETS_API_VERSION = 2
|
|
45
49
|
|
|
50
|
+
/// The first API that calls `chasing` hooks. A manifest promising one under an
|
|
51
|
+
/// older api is refused: an older app would install it and ignore the
|
|
52
|
+
/// program, and for an extension that does nothing else, install a bundle
|
|
53
|
+
/// that silently does nothing.
|
|
54
|
+
export const CHASING_API_VERSION = 9
|
|
55
|
+
|
|
46
56
|
/// The first API with timers. The build points a bundle's bare `setTimeout`
|
|
47
57
|
/// and friends at the SDK's only from here on: an older app's kernel hands an
|
|
48
58
|
/// extension no timers, and a bundle declaring less says it runs there.
|
|
@@ -144,6 +154,8 @@ SHARED_MODULES_BY_API[4] = SHARED_MODULES_BY_API[3]
|
|
|
144
154
|
SHARED_MODULES_BY_API[5] = SHARED_MODULES_BY_API[4]
|
|
145
155
|
SHARED_MODULES_BY_API[6] = SHARED_MODULES_BY_API[5]
|
|
146
156
|
SHARED_MODULES_BY_API[7] = SHARED_MODULES_BY_API[6]
|
|
157
|
+
SHARED_MODULES_BY_API[8] = SHARED_MODULES_BY_API[7]
|
|
158
|
+
SHARED_MODULES_BY_API[9] = SHARED_MODULES_BY_API[8]
|
|
147
159
|
|
|
148
160
|
/// What a scaffolded extension declares on day one: the eight modules the SDK
|
|
149
161
|
/// barrel itself reaches, so a project that has written no code yet still
|
|
@@ -333,6 +345,10 @@ export function validateManifest(manifest, { source = MANIFEST_ENTRY, forceName
|
|
|
333
345
|
}
|
|
334
346
|
}
|
|
335
347
|
|
|
348
|
+
if (Array.isArray(manifest.hooks) && manifest.hooks.includes("chasing") && Number.isInteger(manifest.api) && manifest.api < CHASING_API_VERSION) {
|
|
349
|
+
say(`'chasing' needs 'api' ${CHASING_API_VERSION} or later — an app older than that would install this and never ask it what a contact claims`)
|
|
350
|
+
}
|
|
351
|
+
|
|
336
352
|
// An extension with no category is CORE to the host: always enabled, and
|
|
337
353
|
// never listed in the Extensions panel. That is a status the app grants its
|
|
338
354
|
// own extensions, not one a distributed bundle may claim for itself — a user
|