@nestor-home/satellite 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +72 -2
- package/dist/body.d.ts +27 -0
- package/dist/body.d.ts.map +1 -0
- package/dist/body.js +9 -0
- package/dist/body.js.map +1 -0
- package/dist/browser.d.ts +65 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +161 -0
- package/dist/browser.js.map +1 -0
- package/dist/codes.d.ts +38 -0
- package/dist/codes.d.ts.map +1 -0
- package/dist/codes.js +67 -0
- package/dist/codes.js.map +1 -0
- package/dist/dispatch.d.ts +20 -0
- package/dist/dispatch.d.ts.map +1 -0
- package/dist/dispatch.js +67 -0
- package/dist/dispatch.js.map +1 -0
- package/dist/i18n.d.ts +33 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +61 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/locales.d.ts +10 -0
- package/dist/locales.d.ts.map +1 -0
- package/dist/locales.js +64 -0
- package/dist/locales.js.map +1 -0
- package/dist/log.d.ts +10 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +10 -0
- package/dist/log.js.map +1 -0
- package/dist/node/audio.d.ts +83 -0
- package/dist/node/audio.d.ts.map +1 -0
- package/dist/node/audio.js +168 -0
- package/dist/node/audio.js.map +1 -0
- package/dist/node/bin.d.ts +3 -0
- package/dist/node/bin.d.ts.map +1 -0
- package/dist/node/bin.js +4 -0
- package/dist/node/bin.js.map +1 -0
- package/dist/node/cli.d.ts +39 -0
- package/dist/node/cli.d.ts.map +1 -0
- package/dist/node/cli.js +183 -0
- package/dist/node/cli.js.map +1 -0
- package/dist/node/env.d.ts +26 -0
- package/dist/node/env.d.ts.map +1 -0
- package/dist/node/env.js +41 -0
- package/dist/node/env.js.map +1 -0
- package/dist/node/index.d.ts +11 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +11 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/tokens.d.ts +19 -0
- package/dist/node/tokens.d.ts.map +1 -0
- package/dist/node/tokens.js +50 -0
- package/dist/node/tokens.js.map +1 -0
- package/dist/node/voice.d.ts +7 -0
- package/dist/node/voice.d.ts.map +1 -0
- package/dist/node/voice.js +12 -0
- package/dist/node/voice.js.map +1 -0
- package/dist/node/webrtc.d.ts +50 -0
- package/dist/node/webrtc.d.ts.map +1 -0
- package/dist/node/webrtc.js +155 -0
- package/dist/node/webrtc.js.map +1 -0
- package/dist/pairing.d.ts +181 -0
- package/dist/pairing.d.ts.map +1 -0
- package/dist/pairing.js +451 -0
- package/dist/pairing.js.map +1 -0
- package/dist/protocol.d.ts +108 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +136 -0
- package/dist/protocol.js.map +1 -0
- package/dist/qr/index.d.ts +44 -0
- package/dist/qr/index.d.ts.map +1 -0
- package/dist/qr/index.js +107 -0
- package/dist/qr/index.js.map +1 -0
- package/dist/satellite.d.ts +133 -0
- package/dist/satellite.d.ts.map +1 -0
- package/dist/satellite.js +313 -0
- package/dist/satellite.js.map +1 -0
- package/dist/tokens.d.ts +72 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +150 -0
- package/dist/tokens.js.map +1 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +4 -0
- package/dist/version.js.map +1 -0
- package/dist/voice.d.ts +92 -0
- package/dist/voice.d.ts.map +1 -0
- package/dist/voice.js +220 -0
- package/dist/voice.js.map +1 -0
- package/dist/w3c.d.ts +88 -0
- package/dist/w3c.d.ts.map +1 -0
- package/dist/w3c.js +117 -0
- package/dist/w3c.js.map +1 -0
- package/dist/webrtc.d.ts +56 -0
- package/dist/webrtc.d.ts.map +1 -0
- package/dist/webrtc.js +11 -0
- package/dist/webrtc.js.map +1 -0
- package/dist/wire.d.ts +132 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +217 -0
- package/dist/wire.js.map +1 -0
- package/package.json +89 -4
- package/schemas/ack.json +41 -0
- package/schemas/hello.json +41 -0
- package/schemas/intent.beat.json +35 -0
- package/schemas/intent.behavior.json +46 -0
- package/schemas/intent.expression.json +53 -0
- package/schemas/intent.identify.json +35 -0
- package/schemas/manifest.json +96 -0
- package/schemas/observation.person.detected.json +48 -0
- package/schemas/observation.speech.activity.json +41 -0
- package/schemas/pairing.enrollment.json +26 -0
- package/schemas/pairing.error.json +39 -0
- package/schemas/pairing.request.json +36 -0
- package/schemas/pairing.state.json +40 -0
- package/schemas/pairing.ticket.json +35 -0
- package/schemas/welcome.json +52 -0
- package/src/body.ts +28 -0
- package/src/browser.ts +217 -0
- package/src/codes.ts +76 -0
- package/src/dispatch.ts +67 -0
- package/src/i18n.ts +70 -0
- package/src/index.ts +116 -0
- package/src/locales.ts +88 -0
- package/src/log.ts +17 -0
- package/src/node/audio.ts +201 -0
- package/src/node/bin.ts +4 -0
- package/src/node/cli.ts +199 -0
- package/src/node/env.ts +54 -0
- package/src/node/index.ts +36 -0
- package/src/node/tokens.ts +59 -0
- package/src/node/voice.ts +16 -0
- package/src/node/webrtc.ts +191 -0
- package/src/pairing.ts +552 -0
- package/src/protocol.ts +208 -0
- package/src/qr/index.ts +130 -0
- package/src/satellite.ts +400 -0
- package/src/tokens.ts +194 -0
- package/src/version.ts +3 -0
- package/src/voice.ts +259 -0
- package/src/w3c.ts +160 -0
- package/src/webrtc.ts +62 -0
- package/src/wire.ts +347 -0
- package/voice/LICENSE +11 -0
- package/voice/en/0.wav +0 -0
- package/voice/en/1.wav +0 -0
- package/voice/en/2.wav +0 -0
- package/voice/en/3.wav +0 -0
- package/voice/en/4.wav +0 -0
- package/voice/en/5.wav +0 -0
- package/voice/en/6.wav +0 -0
- package/voice/en/7.wav +0 -0
- package/voice/en/8.wav +0 -0
- package/voice/en/9.wav +0 -0
- package/voice/en/i-repeat.wav +0 -0
- package/voice/en/pairing-code.wav +0 -0
- package/voice/fr/0.wav +0 -0
- package/voice/fr/1.wav +0 -0
- package/voice/fr/2.wav +0 -0
- package/voice/fr/3.wav +0 -0
- package/voice/fr/4.wav +0 -0
- package/voice/fr/5.wav +0 -0
- package/voice/fr/6.wav +0 -0
- package/voice/fr/7.wav +0 -0
- package/voice/fr/8.wav +0 -0
- package/voice/fr/9.wav +0 -0
- package/voice/fr/code-d-appairage.wav +0 -0
- package/voice/fr/je-repete.wav +0 -0
- package/voice/index.json +38 -0
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a satellite says to people (its device code, a refused enrollment code, why it cannot pair),
|
|
3
|
+
* in their language. The catalogues are Fluent (`./locales.ts`); English is the fallback.
|
|
4
|
+
*
|
|
5
|
+
* The locale comes from the `locale` option, else the platform (`navigator.languages` in browsers
|
|
6
|
+
* and in Node), else English. Node's CLI reads `LC_ALL`, `LC_MESSAGES` and `LANG` itself.
|
|
7
|
+
*/
|
|
8
|
+
import { FluentBundle, FluentResource } from "@fluent/bundle";
|
|
9
|
+
import { en, fr } from "./locales.js";
|
|
10
|
+
const CATALOGUES = { en, fr };
|
|
11
|
+
export const LOCALES = Object.freeze(Object.keys(CATALOGUES));
|
|
12
|
+
/**
|
|
13
|
+
* The first supported locale among `requested` (BCP 47 tags such as `fr-FR`, or POSIX ones such as
|
|
14
|
+
* `fr_FR.UTF-8`), else English.
|
|
15
|
+
*/
|
|
16
|
+
export function negotiateLocale(requested) {
|
|
17
|
+
for (const tag of requested) {
|
|
18
|
+
const language = tag
|
|
19
|
+
?.trim()
|
|
20
|
+
.toLowerCase()
|
|
21
|
+
.split(/[-_.@]/)[0];
|
|
22
|
+
const found = LOCALES.find((locale) => locale === language);
|
|
23
|
+
if (found !== undefined)
|
|
24
|
+
return found;
|
|
25
|
+
}
|
|
26
|
+
return "en";
|
|
27
|
+
}
|
|
28
|
+
/** The platform's preferred languages, when it says (browsers, Node 21+). */
|
|
29
|
+
export function platformLanguages() {
|
|
30
|
+
const navigator = globalThis.navigator;
|
|
31
|
+
return navigator?.languages ?? (navigator?.language === undefined ? [] : [navigator.language]);
|
|
32
|
+
}
|
|
33
|
+
export class Messages {
|
|
34
|
+
locale;
|
|
35
|
+
bundle;
|
|
36
|
+
fallback;
|
|
37
|
+
/** `locale`: a tag or a list of preferred tags; by default the platform's languages. */
|
|
38
|
+
constructor(locale) {
|
|
39
|
+
const requested = locale === undefined ? platformLanguages() : typeof locale === "string" ? [locale] : locale;
|
|
40
|
+
this.locale = negotiateLocale(requested);
|
|
41
|
+
this.bundle = bundle(this.locale);
|
|
42
|
+
this.fallback = this.locale === "en" ? this.bundle : bundle("en");
|
|
43
|
+
}
|
|
44
|
+
/** The sentence `id` with its arguments, in this locale (in English when this locale lacks it). */
|
|
45
|
+
format(id, args = {}) {
|
|
46
|
+
for (const source of [this.bundle, this.fallback]) {
|
|
47
|
+
const message = source.getMessage(id);
|
|
48
|
+
if (message?.value)
|
|
49
|
+
return source.formatPattern(message.value, args);
|
|
50
|
+
}
|
|
51
|
+
return id;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function bundle(locale) {
|
|
55
|
+
const result = new FluentBundle(locale, { useIsolating: false });
|
|
56
|
+
const errors = result.addResource(new FluentResource(CATALOGUES[locale]));
|
|
57
|
+
if (errors.length > 0)
|
|
58
|
+
throw new Error(`the ${locale} catalogue is broken: ${errors.join("; ")}`);
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=i18n.js.map
|
package/dist/i18n.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,EAAE,EAAE,EAAE,EAAkB,MAAM,cAAc,CAAC;AAItD,MAAM,UAAU,GAAG,EAAE,EAAE,EAAE,EAAE,EAAW,CAAC;AAEvC,MAAM,CAAC,MAAM,OAAO,GAAsB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAa,CAAC,CAAC;AAI7F;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,SAAiD;IAC/E,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,GAAG;YAClB,EAAE,IAAI,EAAE;aACP,WAAW,EAAE;aACb,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;QAC5D,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,iBAAiB;IAC/B,MAAM,SAAS,GAAI,UAAmF,CAAC,SAAS,CAAC;IACjH,OAAO,SAAS,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;AACjG,CAAC;AAED,MAAM,OAAO,QAAQ;IACV,MAAM,CAAS;IACP,MAAM,CAAe;IACrB,QAAQ,CAAe;IAExC,wFAAwF;IACxF,YAAY,MAAmC;QAC7C,MAAM,SAAS,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC9G,IAAI,CAAC,MAAM,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpE,CAAC;IAED,mGAAmG;IACnG,MAAM,CAAC,EAAa,EAAE,OAAoB,EAAE;QAC1C,KAAK,MAAM,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClD,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YACtC,IAAI,OAAO,EAAE,KAAK;gBAAE,OAAO,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;CACF;AAED,SAAS,MAAM,CAAC,MAAc;IAC5B,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1E,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,MAAM,yBAAyB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClG,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write a Nestor satellite in TypeScript: pair with the core, stream audio over WebRTC, carry out
|
|
3
|
+
* its intents and report observations, following the `nestor.satellite/1` protocol.
|
|
4
|
+
*
|
|
5
|
+
* This entry point runs anywhere (browsers, Node, workers): it touches no platform API until a
|
|
6
|
+
* `WebRtc` adapter does. Node's adapter, audio and token file live in `@nestor-home/satellite/node`.
|
|
7
|
+
*/
|
|
8
|
+
export type { Body } from "./body.js";
|
|
9
|
+
export { type AudioContextLike, type AudioElementLike, type BrowserWebRtcOptions, browserSpeech, browserWebRtc, type SpeechSynthesisLike, webAudioSpeaker, } from "./browser.js";
|
|
10
|
+
export { DEVICE_CODE, ENROLLMENT_ALPHABET, ENROLLMENT_LENGTH, groupEnrollmentCode, normalizeEnrollmentCode, type PairingUri, parsePairingUri, readEnrollment, } from "./codes.js";
|
|
11
|
+
export { Dispatcher, type Outcome } from "./dispatch.js";
|
|
12
|
+
export { LOCALES, type Locale, type MessageArgs, type MessageId, Messages, negotiateLocale } from "./i18n.js";
|
|
13
|
+
export { type Logger, quietLogger } from "./log.js";
|
|
14
|
+
export { type CodeVoice, type EnrollOutcome, type Fetch, HttpError, type Paired, Pairing, PairingError, type PairingOptions, type PairingOutputs, } from "./pairing.js";
|
|
15
|
+
export { AUDIO_CAPTURE, AUDIO_PLAYBACK, BEHAVIORS, type Behavior, type Capability, capability, Device, type DeviceInit, ENROLLMENT_METHODS, type EnrollmentMethod, EXPRESSION, EXPRESSIONS, type Expression, HEAD_MOTION, IDENTIFY, type JsonValue, MAX_CAPABILITIES, Manifest, type ManifestJson, type ManifestOptions, PAIRING_METHODS, type PairingMethod, PERSON_DETECTION, PROTOCOL, ProtocolError, SDK, type Sdk, SPEECH_ACTIVITY, } from "./protocol.js";
|
|
16
|
+
export { CapabilityNotAllowed, type PairingSetup, pairingMethods, type QrScanner, Satellite, type SatelliteOptions, } from "./satellite.js";
|
|
17
|
+
export { type DeviceState, hashEnrollmentCode, LocalStorageTokenStore, type MaybePromise, MemoryTokenStore, type RefusedCodes, type StorageLike, type TokenStore, } from "./tokens.js";
|
|
18
|
+
export { SDK_NAME, SDK_VERSION } from "./version.js";
|
|
19
|
+
export { AHEAD_MS, announcement, type Clock, clipKey, decodeWav, resample, type Speaker, SpokenCode, type SpokenCodeOptions, type Step, type VoiceIndex, voiceMessages, } from "./voice.js";
|
|
20
|
+
export type { AudioBridge, W3cDataChannel, W3cPeerConnection, W3cPeerConnectionConstructor, W3cTrack, W3cTrackEvent, } from "./w3c.js";
|
|
21
|
+
export { W3cPeer } from "./w3c.js";
|
|
22
|
+
export type { MediaNeeds, Peer, PeerEvents, PeerOptions, SessionDescription, WebRtc } from "./webrtc.js";
|
|
23
|
+
export * as wire from "./wire.js";
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,aAAa,EACb,aAAa,EACb,KAAK,mBAAmB,EACxB,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,UAAU,EACf,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC9G,OAAO,EAAE,KAAK,MAAM,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,SAAS,EACT,KAAK,MAAM,EACX,OAAO,EACP,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,cAAc,EACd,SAAS,EACT,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,UAAU,EACV,MAAM,EACN,KAAK,UAAU,EACf,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,UAAU,EACV,WAAW,EACX,KAAK,UAAU,EACf,WAAW,EACX,QAAQ,EACR,KAAK,SAAS,EACd,gBAAgB,EAChB,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,eAAe,EACf,KAAK,aAAa,EAClB,gBAAgB,EAChB,QAAQ,EACR,aAAa,EACb,GAAG,EACH,KAAK,GAAG,EACR,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,oBAAoB,EACpB,KAAK,YAAY,EACjB,cAAc,EACd,KAAK,SAAS,EACd,SAAS,EACT,KAAK,gBAAgB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,WAAW,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,KAAK,YAAY,EACjB,gBAAgB,EAChB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,UAAU,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,KAAK,KAAK,EACV,OAAO,EACP,SAAS,EACT,QAAQ,EACR,KAAK,OAAO,EACZ,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,IAAI,EACT,KAAK,UAAU,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,4BAA4B,EAC5B,QAAQ,EACR,aAAa,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACzG,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write a Nestor satellite in TypeScript: pair with the core, stream audio over WebRTC, carry out
|
|
3
|
+
* its intents and report observations, following the `nestor.satellite/1` protocol.
|
|
4
|
+
*
|
|
5
|
+
* This entry point runs anywhere (browsers, Node, workers): it touches no platform API until a
|
|
6
|
+
* `WebRtc` adapter does. Node's adapter, audio and token file live in `@nestor-home/satellite/node`.
|
|
7
|
+
*/
|
|
8
|
+
export { browserSpeech, browserWebRtc, webAudioSpeaker, } from "./browser.js";
|
|
9
|
+
export { DEVICE_CODE, ENROLLMENT_ALPHABET, ENROLLMENT_LENGTH, groupEnrollmentCode, normalizeEnrollmentCode, parsePairingUri, readEnrollment, } from "./codes.js";
|
|
10
|
+
export { Dispatcher } from "./dispatch.js";
|
|
11
|
+
export { LOCALES, Messages, negotiateLocale } from "./i18n.js";
|
|
12
|
+
export { quietLogger } from "./log.js";
|
|
13
|
+
export { HttpError, Pairing, PairingError, } from "./pairing.js";
|
|
14
|
+
export { AUDIO_CAPTURE, AUDIO_PLAYBACK, BEHAVIORS, capability, Device, ENROLLMENT_METHODS, EXPRESSION, EXPRESSIONS, HEAD_MOTION, IDENTIFY, MAX_CAPABILITIES, Manifest, PAIRING_METHODS, PERSON_DETECTION, PROTOCOL, ProtocolError, SDK, SPEECH_ACTIVITY, } from "./protocol.js";
|
|
15
|
+
export { CapabilityNotAllowed, pairingMethods, Satellite, } from "./satellite.js";
|
|
16
|
+
export { hashEnrollmentCode, LocalStorageTokenStore, MemoryTokenStore, } from "./tokens.js";
|
|
17
|
+
export { SDK_NAME, SDK_VERSION } from "./version.js";
|
|
18
|
+
export { AHEAD_MS, announcement, clipKey, decodeWav, resample, SpokenCode, voiceMessages, } from "./voice.js";
|
|
19
|
+
export { W3cPeer } from "./w3c.js";
|
|
20
|
+
export * as wire from "./wire.js";
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAIL,aAAa,EACb,aAAa,EAEb,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EAEvB,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAgB,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,OAAO,EAAiD,QAAQ,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC9G,OAAO,EAAe,WAAW,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAIL,SAAS,EAET,OAAO,EACP,YAAY,GAGb,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,cAAc,EACd,SAAS,EAGT,UAAU,EACV,MAAM,EAEN,kBAAkB,EAElB,UAAU,EACV,WAAW,EAEX,WAAW,EACX,QAAQ,EAER,gBAAgB,EAChB,QAAQ,EAGR,eAAe,EAEf,gBAAgB,EAChB,QAAQ,EACR,aAAa,EACb,GAAG,EAEH,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,oBAAoB,EAEpB,cAAc,EAEd,SAAS,GAEV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAEL,kBAAkB,EAClB,sBAAsB,EAEtB,gBAAgB,GAIjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,QAAQ,EACR,YAAY,EAEZ,OAAO,EACP,SAAS,EACT,QAAQ,EAER,UAAU,EAIV,aAAa,GACd,MAAM,YAAY,CAAC;AASpB,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SDK's Fluent catalogues (https://projectfluent.org): every sentence a person may read or hear
|
|
3
|
+
* from a satellite. Kept as strings so the catalogue ships in every bundle, with no file to load.
|
|
4
|
+
* `test/i18n.test.ts` checks that every locale has every message.
|
|
5
|
+
*/
|
|
6
|
+
export declare const en = "\ndevice-code-log = Pairing code: { $code }. Type it in Nestor to add this device.\ndevice-code-display = Type this code in Nestor to add this device.\n# The bundled voice has a clip for each piece of text around the digits (nestor-satellite-python's\n# scripts/voice.py records them): record them again after changing this sentence.\ndevice-code-speech = Pairing code: { $digits }. I repeat: { $digits }.\nheadless-hint = This device has no screen and no voice, so the easiest way to pair it is an enrollment code. Add a satellite in Nestor, then set NESTOR_PAIRING_URI.\nenrollment-sent = Sending the enrollment code { $code } to Nestor.\nenrollment-refused = { $reason ->\n [expired] The enrollment code { $code } has expired.\n [used] The enrollment code { $code } was already used.\n [cancelled] The enrollment code { $code } was cancelled.\n *[unknown] Nestor does not know the enrollment code { $code }.\n}\nenrollment-fallback = Asking for a pairing code instead.\nenrollment-already-refused = The enrollment code { $code } was already refused. Make a new one in Nestor.\nenrollment-invalid = This is not an enrollment code. One has 8 letters and digits, like K7QF-2M9X.\nenrollment-not-pending = This device no longer waits for an enrollment code.\npaired = Paired with Nestor.\npairing-expired = The pairing code expired. Asking for a new one.\nidentify = Nestor asks this device to show itself.\ntoo-many-attempts = Too many wrong codes were tried. Trying again in { $seconds } s.\ntoo-many-pending = Too many devices are waiting to be paired. Trying again in { $seconds } s.\nprotocol-unsupported = This Nestor speaks another version of the satellite protocol. Update this device or Nestor.\ninvalid-request = Nestor refused this device's pairing request. Update this device or Nestor.\ntoken-refused = Nestor no longer knows this device. Pairing it again.\nlink-failed = The link to Nestor failed ({ $error }). Trying again.\ncamera-failed = The camera did not open, so this device cannot scan a QR code ({ $error }).\n";
|
|
7
|
+
export declare const fr = "\ndevice-code-log = Code d'appairage : { $code }. Saisissez-le dans Nestor pour ajouter cet appareil.\ndevice-code-display = Saisissez ce code dans Nestor pour ajouter cet appareil.\n# La voix fournie a un extrait pour chaque texte autour des chiffres (scripts/voice.py de\n# nestor-satellite-python les enregistre) : les r\u00E9enregistrer apr\u00E8s avoir chang\u00E9 cette phrase.\ndevice-code-speech = Code d'appairage : { $digits }. Je r\u00E9p\u00E8te : { $digits }.\nheadless-hint = Cet appareil n'a ni \u00E9cran ni voix : le plus simple est de l'appairer avec un code d'enr\u00F4lement. Ajoutez un satellite dans Nestor, puis renseignez NESTOR_PAIRING_URI.\nenrollment-sent = Envoi du code d'enr\u00F4lement { $code } \u00E0 Nestor.\nenrollment-refused = { $reason ->\n [expired] Le code d'enr\u00F4lement { $code } a expir\u00E9.\n [used] Le code d'enr\u00F4lement { $code } a d\u00E9j\u00E0 servi.\n [cancelled] Le code d'enr\u00F4lement { $code } a \u00E9t\u00E9 annul\u00E9.\n *[unknown] Nestor ne conna\u00EEt pas le code d'enr\u00F4lement { $code }.\n}\nenrollment-fallback = Je demande un code d'appairage \u00E0 la place.\nenrollment-already-refused = Le code d'enr\u00F4lement { $code } a d\u00E9j\u00E0 \u00E9t\u00E9 refus\u00E9. Cr\u00E9ez-en un nouveau dans Nestor.\nenrollment-invalid = Ce n'est pas un code d'enr\u00F4lement. Il compte 8 lettres et chiffres, comme K7QF-2M9X.\nenrollment-not-pending = Cet appareil n'attend plus de code d'enr\u00F4lement.\npaired = Appair\u00E9 avec Nestor.\npairing-expired = Le code d'appairage a expir\u00E9. J'en demande un nouveau.\nidentify = Nestor demande \u00E0 cet appareil de se signaler.\ntoo-many-attempts = Trop de codes erron\u00E9s ont \u00E9t\u00E9 essay\u00E9s. Nouvel essai dans { $seconds } s.\ntoo-many-pending = Trop d'appareils attendent d'\u00EAtre appair\u00E9s. Nouvel essai dans { $seconds } s.\nprotocol-unsupported = Ce Nestor parle une autre version du protocole des satellites. Mettez \u00E0 jour cet appareil ou Nestor.\ninvalid-request = Nestor a refus\u00E9 la demande d'appairage de cet appareil. Mettez \u00E0 jour cet appareil ou Nestor.\ntoken-refused = Nestor ne conna\u00EEt plus cet appareil. Nouvel appairage.\nlink-failed = La liaison avec Nestor a \u00E9chou\u00E9 ({ $error }). Nouvel essai.\ncamera-failed = La cam\u00E9ra ne s'est pas ouverte : cet appareil ne peut pas lire de QR code ({ $error }).\n";
|
|
8
|
+
/** The messages every catalogue has. */
|
|
9
|
+
export type MessageId = "device-code-log" | "device-code-display" | "device-code-speech" | "headless-hint" | "enrollment-sent" | "enrollment-refused" | "enrollment-fallback" | "enrollment-already-refused" | "enrollment-invalid" | "enrollment-not-pending" | "paired" | "pairing-expired" | "identify" | "too-many-attempts" | "too-many-pending" | "protocol-unsupported" | "invalid-request" | "token-refused" | "link-failed" | "camera-failed";
|
|
10
|
+
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../src/locales.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,EAAE,ggEA4Bd,CAAC;AAEF,eAAO,MAAM,EAAE,q3EA4Bd,CAAC;AAEF,wCAAwC;AACxC,MAAM,MAAM,SAAS,GACjB,iBAAiB,GACjB,qBAAqB,GACrB,oBAAoB,GACpB,eAAe,GACf,iBAAiB,GACjB,oBAAoB,GACpB,qBAAqB,GACrB,4BAA4B,GAC5B,oBAAoB,GACpB,wBAAwB,GACxB,QAAQ,GACR,iBAAiB,GACjB,UAAU,GACV,mBAAmB,GACnB,kBAAkB,GAClB,sBAAsB,GACtB,iBAAiB,GACjB,eAAe,GACf,aAAa,GACb,eAAe,CAAC"}
|
package/dist/locales.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SDK's Fluent catalogues (https://projectfluent.org): every sentence a person may read or hear
|
|
3
|
+
* from a satellite. Kept as strings so the catalogue ships in every bundle, with no file to load.
|
|
4
|
+
* `test/i18n.test.ts` checks that every locale has every message.
|
|
5
|
+
*/
|
|
6
|
+
export const en = `
|
|
7
|
+
device-code-log = Pairing code: { $code }. Type it in Nestor to add this device.
|
|
8
|
+
device-code-display = Type this code in Nestor to add this device.
|
|
9
|
+
# The bundled voice has a clip for each piece of text around the digits (nestor-satellite-python's
|
|
10
|
+
# scripts/voice.py records them): record them again after changing this sentence.
|
|
11
|
+
device-code-speech = Pairing code: { $digits }. I repeat: { $digits }.
|
|
12
|
+
headless-hint = This device has no screen and no voice, so the easiest way to pair it is an enrollment code. Add a satellite in Nestor, then set NESTOR_PAIRING_URI.
|
|
13
|
+
enrollment-sent = Sending the enrollment code { $code } to Nestor.
|
|
14
|
+
enrollment-refused = { $reason ->
|
|
15
|
+
[expired] The enrollment code { $code } has expired.
|
|
16
|
+
[used] The enrollment code { $code } was already used.
|
|
17
|
+
[cancelled] The enrollment code { $code } was cancelled.
|
|
18
|
+
*[unknown] Nestor does not know the enrollment code { $code }.
|
|
19
|
+
}
|
|
20
|
+
enrollment-fallback = Asking for a pairing code instead.
|
|
21
|
+
enrollment-already-refused = The enrollment code { $code } was already refused. Make a new one in Nestor.
|
|
22
|
+
enrollment-invalid = This is not an enrollment code. One has 8 letters and digits, like K7QF-2M9X.
|
|
23
|
+
enrollment-not-pending = This device no longer waits for an enrollment code.
|
|
24
|
+
paired = Paired with Nestor.
|
|
25
|
+
pairing-expired = The pairing code expired. Asking for a new one.
|
|
26
|
+
identify = Nestor asks this device to show itself.
|
|
27
|
+
too-many-attempts = Too many wrong codes were tried. Trying again in { $seconds } s.
|
|
28
|
+
too-many-pending = Too many devices are waiting to be paired. Trying again in { $seconds } s.
|
|
29
|
+
protocol-unsupported = This Nestor speaks another version of the satellite protocol. Update this device or Nestor.
|
|
30
|
+
invalid-request = Nestor refused this device's pairing request. Update this device or Nestor.
|
|
31
|
+
token-refused = Nestor no longer knows this device. Pairing it again.
|
|
32
|
+
link-failed = The link to Nestor failed ({ $error }). Trying again.
|
|
33
|
+
camera-failed = The camera did not open, so this device cannot scan a QR code ({ $error }).
|
|
34
|
+
`;
|
|
35
|
+
export const fr = `
|
|
36
|
+
device-code-log = Code d'appairage : { $code }. Saisissez-le dans Nestor pour ajouter cet appareil.
|
|
37
|
+
device-code-display = Saisissez ce code dans Nestor pour ajouter cet appareil.
|
|
38
|
+
# La voix fournie a un extrait pour chaque texte autour des chiffres (scripts/voice.py de
|
|
39
|
+
# nestor-satellite-python les enregistre) : les réenregistrer après avoir changé cette phrase.
|
|
40
|
+
device-code-speech = Code d'appairage : { $digits }. Je répète : { $digits }.
|
|
41
|
+
headless-hint = Cet appareil n'a ni écran ni voix : le plus simple est de l'appairer avec un code d'enrôlement. Ajoutez un satellite dans Nestor, puis renseignez NESTOR_PAIRING_URI.
|
|
42
|
+
enrollment-sent = Envoi du code d'enrôlement { $code } à Nestor.
|
|
43
|
+
enrollment-refused = { $reason ->
|
|
44
|
+
[expired] Le code d'enrôlement { $code } a expiré.
|
|
45
|
+
[used] Le code d'enrôlement { $code } a déjà servi.
|
|
46
|
+
[cancelled] Le code d'enrôlement { $code } a été annulé.
|
|
47
|
+
*[unknown] Nestor ne connaît pas le code d'enrôlement { $code }.
|
|
48
|
+
}
|
|
49
|
+
enrollment-fallback = Je demande un code d'appairage à la place.
|
|
50
|
+
enrollment-already-refused = Le code d'enrôlement { $code } a déjà été refusé. Créez-en un nouveau dans Nestor.
|
|
51
|
+
enrollment-invalid = Ce n'est pas un code d'enrôlement. Il compte 8 lettres et chiffres, comme K7QF-2M9X.
|
|
52
|
+
enrollment-not-pending = Cet appareil n'attend plus de code d'enrôlement.
|
|
53
|
+
paired = Appairé avec Nestor.
|
|
54
|
+
pairing-expired = Le code d'appairage a expiré. J'en demande un nouveau.
|
|
55
|
+
identify = Nestor demande à cet appareil de se signaler.
|
|
56
|
+
too-many-attempts = Trop de codes erronés ont été essayés. Nouvel essai dans { $seconds } s.
|
|
57
|
+
too-many-pending = Trop d'appareils attendent d'être appairés. Nouvel essai dans { $seconds } s.
|
|
58
|
+
protocol-unsupported = Ce Nestor parle une autre version du protocole des satellites. Mettez à jour cet appareil ou Nestor.
|
|
59
|
+
invalid-request = Nestor a refusé la demande d'appairage de cet appareil. Mettez à jour cet appareil ou Nestor.
|
|
60
|
+
token-refused = Nestor ne connaît plus cet appareil. Nouvel appairage.
|
|
61
|
+
link-failed = La liaison avec Nestor a échoué ({ $error }). Nouvel essai.
|
|
62
|
+
camera-failed = La caméra ne s'est pas ouverte : cet appareil ne peut pas lire de QR code ({ $error }).
|
|
63
|
+
`;
|
|
64
|
+
//# sourceMappingURL=locales.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locales.js","sourceRoot":"","sources":["../src/locales.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,EAAE,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BjB,CAAC;AAEF,MAAM,CAAC,MAAM,EAAE,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BjB,CAAC"}
|
package/dist/log.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Where the SDK says what happens; `console` fits, and so does any structured logger. */
|
|
2
|
+
export interface Logger {
|
|
3
|
+
debug(message: string): void;
|
|
4
|
+
info(message: string): void;
|
|
5
|
+
warn(message: string): void;
|
|
6
|
+
}
|
|
7
|
+
/** Warnings only, on the console: what a driver should see by default. */
|
|
8
|
+
export declare const quietLogger: Logger;
|
|
9
|
+
export declare function describe(error: unknown): string;
|
|
10
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,0EAA0E;AAC1E,eAAO,MAAM,WAAW,EAAE,MAIzB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE/C"}
|
package/dist/log.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Warnings only, on the console: what a driver should see by default. */
|
|
2
|
+
export const quietLogger = {
|
|
3
|
+
debug: () => { },
|
|
4
|
+
info: () => { },
|
|
5
|
+
warn: (message) => console.warn(`[nestor-satellite] ${message}`),
|
|
6
|
+
};
|
|
7
|
+
export function describe(error) {
|
|
8
|
+
return error instanceof Error ? error.message : String(error);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=log.js.map
|
package/dist/log.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAOA,0EAA0E;AAC1E,MAAM,CAAC,MAAM,WAAW,GAAW;IACjC,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;IACf,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC;IACd,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,sBAAsB,OAAO,EAAE,CAAC;CACjE,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio in and out of a Node satellite: 16-bit mono PCM, whatever the hardware.
|
|
3
|
+
*
|
|
4
|
+
* `AudioSource` gives the chunks to send to the core (the microphone); `AudioSink` plays what the
|
|
5
|
+
* core says (the speaker). Node has no audio API of its own: `CommandSource` and `CommandSink` run
|
|
6
|
+
* a recorder and a player (`arecord`/`aplay`, SoX, ffmpeg…) and exchange raw PCM through their
|
|
7
|
+
* pipes; the doubles serve tests and devices without one or the other.
|
|
8
|
+
*/
|
|
9
|
+
export declare const FRAME_MS = 20;
|
|
10
|
+
export interface AudioSource {
|
|
11
|
+
readonly sampleRate: number;
|
|
12
|
+
/** Open the device; nothing to open by default. Rejects clearly when it cannot. */
|
|
13
|
+
start?(): Promise<void>;
|
|
14
|
+
/** The next chunk of audio (any length, 20 ms is usual); waits for it. */
|
|
15
|
+
read(): Promise<Int16Array>;
|
|
16
|
+
close?(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export interface AudioSink {
|
|
19
|
+
readonly sampleRate: number;
|
|
20
|
+
start?(): Promise<void>;
|
|
21
|
+
/** Play audio as it arrives; must not block. */
|
|
22
|
+
write(pcm: Int16Array): void;
|
|
23
|
+
close?(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/** A device without a microphone still sends a (silent) stream: the core's turn taking expects one. */
|
|
26
|
+
export declare class SilenceSource implements AudioSource {
|
|
27
|
+
readonly sampleRate: number;
|
|
28
|
+
constructor(sampleRate?: number);
|
|
29
|
+
read(): Promise<Int16Array>;
|
|
30
|
+
}
|
|
31
|
+
/** Keeps what was played, e.g. to check a device received the core's voice. */
|
|
32
|
+
export declare class RecordingSink implements AudioSink {
|
|
33
|
+
readonly sampleRate: number;
|
|
34
|
+
readonly chunks: Int16Array[];
|
|
35
|
+
constructor(sampleRate?: number);
|
|
36
|
+
get samples(): number;
|
|
37
|
+
write(pcm: Int16Array): void;
|
|
38
|
+
}
|
|
39
|
+
/** No speaker: the core's audio is received (the link stays healthy) and dropped. */
|
|
40
|
+
export declare class DiscardSink implements AudioSink {
|
|
41
|
+
readonly sampleRate: number;
|
|
42
|
+
constructor(sampleRate?: number);
|
|
43
|
+
write(): void;
|
|
44
|
+
}
|
|
45
|
+
export interface CommandOptions {
|
|
46
|
+
readonly sampleRate?: number;
|
|
47
|
+
/** How much audio may wait before it is dropped (default: 1 s for a recorder, 500 ms for a player). */
|
|
48
|
+
readonly maxBufferMs?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A recorder whose standard output is raw s16le mono PCM, e.g.
|
|
52
|
+
* `arecord -q -t raw -f S16_LE -c 1 -r 48000`. Run by `/bin/sh -c`.
|
|
53
|
+
*/
|
|
54
|
+
export declare class CommandSource implements AudioSource {
|
|
55
|
+
readonly command: string;
|
|
56
|
+
readonly sampleRate: number;
|
|
57
|
+
private readonly maxBytes;
|
|
58
|
+
private process;
|
|
59
|
+
private buffer;
|
|
60
|
+
private waiting;
|
|
61
|
+
private failure;
|
|
62
|
+
constructor(command: string, options?: CommandOptions);
|
|
63
|
+
start(): Promise<void>;
|
|
64
|
+
read(): Promise<Int16Array>;
|
|
65
|
+
close(): Promise<void>;
|
|
66
|
+
private wake;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A player that reads raw s16le mono PCM on its standard input, e.g.
|
|
70
|
+
* `aplay -q -t raw -f S16_LE -c 1 -r 48000`. Audio the player cannot take in time is dropped
|
|
71
|
+
* rather than letting the voice lag further and further behind.
|
|
72
|
+
*/
|
|
73
|
+
export declare class CommandSink implements AudioSink {
|
|
74
|
+
readonly command: string;
|
|
75
|
+
readonly sampleRate: number;
|
|
76
|
+
private readonly maxBytes;
|
|
77
|
+
private process;
|
|
78
|
+
constructor(command: string, options?: CommandOptions);
|
|
79
|
+
start(): Promise<void>;
|
|
80
|
+
write(samples: Int16Array): void;
|
|
81
|
+
close(): Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=audio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../src/node/audio.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,eAAO,MAAM,QAAQ,KAAK,CAAC;AAE3B,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,mFAAmF;IACnF,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,0EAA0E;IAC1E,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,gDAAgD;IAChD,KAAK,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IAC7B,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED,uGAAuG;AACvG,qBAAa,aAAc,YAAW,WAAW;IACnC,QAAQ,CAAC,UAAU;gBAAV,UAAU,SAAS;IAElC,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;CAGlC;AAED,+EAA+E;AAC/E,qBAAa,aAAc,YAAW,SAAS;IAGjC,QAAQ,CAAC,UAAU;IAF/B,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,CAAM;gBAEd,UAAU,SAAS;IAExC,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,KAAK,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI;CAG7B;AAED,qFAAqF;AACrF,qBAAa,WAAY,YAAW,SAAS;IAC/B,QAAQ,CAAC,UAAU;gBAAV,UAAU,SAAS;IAExC,KAAK,IAAI,IAAI;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,uGAAuG;IACvG,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,qBAAa,aAAc,YAAW,WAAW;IAS7C,QAAQ,CAAC,OAAO,EAAE,MAAM;IAR1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,OAAO,CAAsB;gBAG1B,OAAO,EAAE,MAAM,EACxB,OAAO,GAAE,cAAmB;IAMxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IActB,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;IAc3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,OAAO,CAAC,IAAI;CAKb;AAED;;;;GAIG;AACH,qBAAa,WAAY,YAAW,SAAS;IAMzC,QAAQ,CAAC,OAAO,EAAE,MAAM;IAL1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,OAAO,CAA6B;gBAGjC,OAAO,EAAE,MAAM,EACxB,OAAO,GAAE,cAAmB;IAMxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B,KAAK,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;IAM1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAM7B"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio in and out of a Node satellite: 16-bit mono PCM, whatever the hardware.
|
|
3
|
+
*
|
|
4
|
+
* `AudioSource` gives the chunks to send to the core (the microphone); `AudioSink` plays what the
|
|
5
|
+
* core says (the speaker). Node has no audio API of its own: `CommandSource` and `CommandSink` run
|
|
6
|
+
* a recorder and a player (`arecord`/`aplay`, SoX, ffmpeg…) and exchange raw PCM through their
|
|
7
|
+
* pipes; the doubles serve tests and devices without one or the other.
|
|
8
|
+
*/
|
|
9
|
+
import { spawn } from "node:child_process";
|
|
10
|
+
export const FRAME_MS = 20;
|
|
11
|
+
/** A device without a microphone still sends a (silent) stream: the core's turn taking expects one. */
|
|
12
|
+
export class SilenceSource {
|
|
13
|
+
sampleRate;
|
|
14
|
+
constructor(sampleRate = 48_000) {
|
|
15
|
+
this.sampleRate = sampleRate;
|
|
16
|
+
}
|
|
17
|
+
async read() {
|
|
18
|
+
return new Int16Array((this.sampleRate * FRAME_MS) / 1000);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Keeps what was played, e.g. to check a device received the core's voice. */
|
|
22
|
+
export class RecordingSink {
|
|
23
|
+
sampleRate;
|
|
24
|
+
chunks = [];
|
|
25
|
+
constructor(sampleRate = 48_000) {
|
|
26
|
+
this.sampleRate = sampleRate;
|
|
27
|
+
}
|
|
28
|
+
get samples() {
|
|
29
|
+
return this.chunks.reduce((total, chunk) => total + chunk.length, 0);
|
|
30
|
+
}
|
|
31
|
+
write(pcm) {
|
|
32
|
+
this.chunks.push(pcm);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** No speaker: the core's audio is received (the link stays healthy) and dropped. */
|
|
36
|
+
export class DiscardSink {
|
|
37
|
+
sampleRate;
|
|
38
|
+
constructor(sampleRate = 48_000) {
|
|
39
|
+
this.sampleRate = sampleRate;
|
|
40
|
+
}
|
|
41
|
+
write() { }
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A recorder whose standard output is raw s16le mono PCM, e.g.
|
|
45
|
+
* `arecord -q -t raw -f S16_LE -c 1 -r 48000`. Run by `/bin/sh -c`.
|
|
46
|
+
*/
|
|
47
|
+
export class CommandSource {
|
|
48
|
+
command;
|
|
49
|
+
sampleRate;
|
|
50
|
+
maxBytes;
|
|
51
|
+
process = null;
|
|
52
|
+
buffer = Buffer.alloc(0);
|
|
53
|
+
waiting = null;
|
|
54
|
+
failure = null;
|
|
55
|
+
constructor(command, options = {}) {
|
|
56
|
+
this.command = command;
|
|
57
|
+
this.sampleRate = options.sampleRate ?? 48_000;
|
|
58
|
+
this.maxBytes = Math.round((this.sampleRate * (options.maxBufferMs ?? 1000)) / 1000) * 2;
|
|
59
|
+
}
|
|
60
|
+
async start() {
|
|
61
|
+
const child = await launch(this.command, ["ignore", "pipe", "inherit"]);
|
|
62
|
+
this.process = child;
|
|
63
|
+
child.stdout?.on("data", (data) => {
|
|
64
|
+
this.buffer = Buffer.concat([this.buffer, data]);
|
|
65
|
+
if (this.buffer.length > this.maxBytes)
|
|
66
|
+
this.buffer = this.buffer.subarray(this.buffer.length - this.maxBytes);
|
|
67
|
+
this.wake();
|
|
68
|
+
});
|
|
69
|
+
child.on("exit", (code, signal) => {
|
|
70
|
+
if (this.process === child)
|
|
71
|
+
this.failure = new Error(`the recorder stopped (${signal ?? `status ${code}`})`);
|
|
72
|
+
this.wake();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async read() {
|
|
76
|
+
const frame = ((this.sampleRate * FRAME_MS) / 1000) * 2;
|
|
77
|
+
while (this.buffer.length < frame) {
|
|
78
|
+
if (this.failure !== null)
|
|
79
|
+
throw this.failure;
|
|
80
|
+
if (this.process === null)
|
|
81
|
+
throw new Error("the recorder is not started");
|
|
82
|
+
await new Promise((resolve) => {
|
|
83
|
+
this.waiting = resolve;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const chunk = this.buffer.subarray(0, frame);
|
|
87
|
+
this.buffer = this.buffer.subarray(frame);
|
|
88
|
+
return pcm(chunk);
|
|
89
|
+
}
|
|
90
|
+
async close() {
|
|
91
|
+
const child = this.process;
|
|
92
|
+
this.process = null;
|
|
93
|
+
this.wake();
|
|
94
|
+
await stop(child);
|
|
95
|
+
}
|
|
96
|
+
wake() {
|
|
97
|
+
const waiting = this.waiting;
|
|
98
|
+
this.waiting = null;
|
|
99
|
+
waiting?.();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A player that reads raw s16le mono PCM on its standard input, e.g.
|
|
104
|
+
* `aplay -q -t raw -f S16_LE -c 1 -r 48000`. Audio the player cannot take in time is dropped
|
|
105
|
+
* rather than letting the voice lag further and further behind.
|
|
106
|
+
*/
|
|
107
|
+
export class CommandSink {
|
|
108
|
+
command;
|
|
109
|
+
sampleRate;
|
|
110
|
+
maxBytes;
|
|
111
|
+
process = null;
|
|
112
|
+
constructor(command, options = {}) {
|
|
113
|
+
this.command = command;
|
|
114
|
+
this.sampleRate = options.sampleRate ?? 48_000;
|
|
115
|
+
this.maxBytes = Math.round((this.sampleRate * (options.maxBufferMs ?? 500)) / 1000) * 2;
|
|
116
|
+
}
|
|
117
|
+
async start() {
|
|
118
|
+
this.process = await launch(this.command, ["pipe", "ignore", "inherit"]);
|
|
119
|
+
this.process.stdin?.on("error", () => { }); // a player that quits is noticed on exit
|
|
120
|
+
}
|
|
121
|
+
write(samples) {
|
|
122
|
+
const stdin = this.process?.stdin;
|
|
123
|
+
if (!stdin || stdin.destroyed || stdin.writableLength > this.maxBytes)
|
|
124
|
+
return;
|
|
125
|
+
stdin.write(Buffer.from(samples.buffer, samples.byteOffset, samples.byteLength));
|
|
126
|
+
}
|
|
127
|
+
async close() {
|
|
128
|
+
const child = this.process;
|
|
129
|
+
this.process = null;
|
|
130
|
+
child?.stdin?.end();
|
|
131
|
+
await stop(child, 1000); // let it play what it has, briefly
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function pcm(bytes) {
|
|
135
|
+
const copy = new Uint8Array(bytes.length);
|
|
136
|
+
copy.set(bytes);
|
|
137
|
+
return new Int16Array(copy.buffer);
|
|
138
|
+
}
|
|
139
|
+
function launch(command, stdio) {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
const child = spawn("/bin/sh", ["-c", `exec ${command}`], { stdio });
|
|
142
|
+
child.once("error", reject);
|
|
143
|
+
child.once("spawn", () => {
|
|
144
|
+
// `sh` starts even when the command does not exist: give it a moment to fail.
|
|
145
|
+
const early = setTimeout(() => {
|
|
146
|
+
child.off("exit", exited);
|
|
147
|
+
resolve(child);
|
|
148
|
+
}, 200);
|
|
149
|
+
const exited = (code) => {
|
|
150
|
+
clearTimeout(early);
|
|
151
|
+
reject(new Error(`\`${command}\` exited at once (status ${code}): is it installed?`));
|
|
152
|
+
};
|
|
153
|
+
child.once("exit", exited);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
/** Ends a child: after `graceMs` on its own, then SIGTERM, then SIGKILL. */
|
|
158
|
+
async function stop(child, graceMs = 0) {
|
|
159
|
+
if (child === null || child.exitCode !== null || child.signalCode !== null)
|
|
160
|
+
return;
|
|
161
|
+
const exited = new Promise((resolve) => child.once("exit", () => resolve()));
|
|
162
|
+
const term = setTimeout(() => child.kill("SIGTERM"), graceMs);
|
|
163
|
+
const kill = setTimeout(() => child.kill("SIGKILL"), graceMs + 2000);
|
|
164
|
+
await exited;
|
|
165
|
+
clearTimeout(term);
|
|
166
|
+
clearTimeout(kill);
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=audio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio.js","sourceRoot":"","sources":["../../src/node/audio.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/node/bin.ts"],"names":[],"mappings":""}
|
package/dist/node/bin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/node/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC,OAAO,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nestor-satellite run`: this machine's microphone and speaker as a satellite of a Nestor core.
|
|
3
|
+
*
|
|
4
|
+
* nestor-satellite run --core http://nestor.local:7860 --room salon
|
|
5
|
+
* NESTOR_PAIRING_URI=nestor+http://nestor.local:7860/?code=K7QF2M9X nestor-satellite run --room salon
|
|
6
|
+
*
|
|
7
|
+
* With an enrollment code (`--pairing-uri`, `--pairing-code`, or the same in `NESTOR_PAIRING_URI`,
|
|
8
|
+
* `NESTOR_PAIRING_CODE`), the first run pairs at once; without one, it says a device code to type in
|
|
9
|
+
* Nestor on its speaker (the bundled voice) and logs it. The token is then kept in `~/.config/nestor-satellite/<id>.json`. Audio goes through a recorder and a player command
|
|
10
|
+
* (`arecord`/`aplay` on Linux, SoX's `rec`/`play` on macOS) exchanging raw 48 kHz s16le mono PCM.
|
|
11
|
+
*/
|
|
12
|
+
import type { Logger } from "../log.js";
|
|
13
|
+
import { Satellite } from "../satellite.js";
|
|
14
|
+
import { type Environment } from "./env.js";
|
|
15
|
+
export declare const DEFAULT_INPUT: string;
|
|
16
|
+
export declare const DEFAULT_OUTPUT: string;
|
|
17
|
+
export interface Arguments {
|
|
18
|
+
readonly core: string;
|
|
19
|
+
readonly room: string;
|
|
20
|
+
readonly id: string;
|
|
21
|
+
readonly model: string;
|
|
22
|
+
readonly brand: string | undefined;
|
|
23
|
+
readonly tokenFile: string;
|
|
24
|
+
readonly input: string;
|
|
25
|
+
readonly output: string;
|
|
26
|
+
readonly ice: readonly string[];
|
|
27
|
+
/** The enrollment code a person configured (canonical form), if any. */
|
|
28
|
+
readonly enrollment: string | undefined;
|
|
29
|
+
readonly locale: readonly string[];
|
|
30
|
+
readonly verbose: boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare function defaultId(): string;
|
|
33
|
+
/** The arguments of `run`, then the environment; throws a usage error when they are wrong. */
|
|
34
|
+
export declare function parse(argv: readonly string[], env?: Environment): Arguments | "help" | "version";
|
|
35
|
+
export declare class UsageError extends Error {
|
|
36
|
+
}
|
|
37
|
+
export declare function build(args: Arguments, logger: Logger): Satellite;
|
|
38
|
+
export declare function main(argv: readonly string[]): Promise<number>;
|
|
39
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/node/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EAAE,KAAK,WAAW,EAAyE,MAAM,UAAU,CAAC;AAMnH,eAAO,MAAM,aAAa,QACyE,CAAC;AACpG,eAAO,MAAM,cAAc,QACuE,CAAC;AA4BnG,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,SAAS,IAAI,MAAM,CAGlC;AAED,8FAA8F;AAC9F,wBAAgB,KAAK,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,GAAE,WAAyB,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAoD7G;AAED,qBAAa,UAAW,SAAQ,KAAK;CAAG;AAExC,wBAAgB,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAmBhE;AAOD,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAsCnE"}
|