@intomind/sdk 0.0.0-stage → 1.4.1
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/CLA.md +71 -0
- package/CONTRIBUTING.md +53 -0
- package/LICENSE +662 -0
- package/LICENSING.md +45 -0
- package/README.md +147 -2
- package/dist/digest.d.ts +22 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +109 -0
- package/dist/digest.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +1433 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +2227 -0
- package/dist/protocol.js.map +1 -0
- package/dist/session.d.ts +284 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +523 -0
- package/dist/session.js.map +1 -0
- package/dist/timebase.d.ts +65 -0
- package/dist/timebase.d.ts.map +1 -0
- package/dist/timebase.js +114 -0
- package/dist/timebase.js.map +1 -0
- package/dist/transfer.d.ts +139 -0
- package/dist/transfer.d.ts.map +1 -0
- package/dist/transfer.js +269 -0
- package/dist/transfer.js.map +1 -0
- package/dist/web-bluetooth.d.ts +172 -0
- package/dist/web-bluetooth.d.ts.map +1 -0
- package/dist/web-bluetooth.js +310 -0
- package/dist/web-bluetooth.js.map +1 -0
- package/package.json +74 -4
- package/src/digest.ts +115 -0
- package/src/index.ts +103 -0
- package/src/protocol.ts +2987 -0
- package/src/session.ts +675 -0
- package/src/timebase.ts +138 -0
- package/src/transfer.ts +313 -0
- package/src/web-bluetooth.ts +419 -0
package/LICENSING.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Licensing
|
|
2
|
+
|
|
3
|
+
This project is free software under the GNU Affero General Public License,
|
|
4
|
+
version 3. The full text is in `LICENSE`. It covers the code in this
|
|
5
|
+
repository.
|
|
6
|
+
|
|
7
|
+
A commercial license is also available. The two are alternatives: use
|
|
8
|
+
either one.
|
|
9
|
+
|
|
10
|
+
## What the Affero license asks of you
|
|
11
|
+
|
|
12
|
+
You may use, study, change, and share this software. If you share it, or
|
|
13
|
+
a work based on it, you pass on the same freedoms and the source. The
|
|
14
|
+
Affero clause adds one thing to the ordinary General Public License: if
|
|
15
|
+
you run a modified version as a network service, the people using that
|
|
16
|
+
service can ask you for its source.
|
|
17
|
+
|
|
18
|
+
Building your own product on top of these libraries is what they are for.
|
|
19
|
+
Running them, recording with them, and publishing what you make with them
|
|
20
|
+
are not affected at all. The license is about the software, never about
|
|
21
|
+
the data you record with it.
|
|
22
|
+
|
|
23
|
+
## When you want the commercial license instead
|
|
24
|
+
|
|
25
|
+
Take the commercial license when you want to build a closed product on
|
|
26
|
+
this code, or run a modified service without publishing your changes.
|
|
27
|
+
Write to contact@intomind.com.
|
|
28
|
+
|
|
29
|
+
IntoMind can offer both because IntoMind holds the copyright in the
|
|
30
|
+
code, which is also why contributions are covered by the agreement in
|
|
31
|
+
`CONTRIBUTING.md`.
|
|
32
|
+
|
|
33
|
+
## Contributions
|
|
34
|
+
|
|
35
|
+
The first time you contribute, you sign a contributor license agreement.
|
|
36
|
+
It says you wrote what you are contributing and that you give IntoMind
|
|
37
|
+
the rights to use it under both licenses, while you keep the copyright
|
|
38
|
+
in your own work. `CONTRIBUTING.md` has the detail and the process.
|
|
39
|
+
|
|
40
|
+
## Trademarks
|
|
41
|
+
|
|
42
|
+
IntoMind is a trademark of IntoMind, Inc. The license covers the code,
|
|
43
|
+
not the name. You may say your product works with an IntoMind device.
|
|
44
|
+
You may not call your product IntoMind or use the mark in a way that
|
|
45
|
+
suggests IntoMind made or endorsed it.
|
package/README.md
CHANGED
|
@@ -1,3 +1,148 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @intomind/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The IntoMind instrument client for JavaScript. One package, every IntoMind
|
|
4
|
+
device, in a browser and in Node.
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { requestAndConnect } from "@intomind/sdk";
|
|
8
|
+
|
|
9
|
+
const device = await requestAndConnect({
|
|
10
|
+
onEvent(event) {
|
|
11
|
+
if (event.type === "samples") plot(event.batch);
|
|
12
|
+
if (event.type === "gap") mark(event.gap);
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
await device.send(device.session.startStream());
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
It owns the protocol spoken to a device, the session that turns
|
|
19
|
+
notifications into events, the clock that puts those events on the host's
|
|
20
|
+
timeline, and one transport for the browser. It knows nothing about any
|
|
21
|
+
particular device beyond what that device tells it, and nothing about any
|
|
22
|
+
application built on top of it.
|
|
23
|
+
|
|
24
|
+
## What is in here
|
|
25
|
+
|
|
26
|
+
| | |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `src/protocol.ts` | the wire, and nothing else |
|
|
29
|
+
| `src/session.ts` | one device as a state machine: bytes in, events out |
|
|
30
|
+
| `src/timebase.ts` | device time onto host time, and what it refuses to believe |
|
|
31
|
+
| `src/web-bluetooth.ts` | the browser transport, and the only file that touches a radio |
|
|
32
|
+
| `src/index.ts` | the public surface |
|
|
33
|
+
|
|
34
|
+
The protocol, the session, and the timebase do no input and no output.
|
|
35
|
+
They take bytes that arrived and hand back bytes to send, so they run over
|
|
36
|
+
whatever Bluetooth stack you already have, on whatever runtime you already
|
|
37
|
+
use, and they can be tested without either.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { Session, protocol } from "@intomind/sdk";
|
|
41
|
+
|
|
42
|
+
const session = new Session();
|
|
43
|
+
session.onDeviceInfo(await readDeviceInfoSomehow());
|
|
44
|
+
for (const event of session.onNotification(protocol.FILL.EEG_DATA, notification)) {
|
|
45
|
+
// ...
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Capabilities are the device's answer, never this package's assumption
|
|
50
|
+
|
|
51
|
+
A device declares what it is over the protocol, and everything follows
|
|
52
|
+
from that declaration. The channel count, the converter's resolution and
|
|
53
|
+
reference, the rates it offers, whether it can detect lead-off, whether it
|
|
54
|
+
carries a model: all of it is asked and none of it is assumed.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
session.requireInfo().channels // what the device said
|
|
58
|
+
session.can("model") // a capability bit, not a version number
|
|
59
|
+
session.setLeadoff(true) // throws NotCapable if the device never claimed it
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
A table of specific hardware in this package is a defect. A capability the
|
|
63
|
+
device does not claim is not asked for, and asking anyway throws rather
|
|
64
|
+
than putting a byte on the wire the device will refuse.
|
|
65
|
+
|
|
66
|
+
## The timeline is never silently repaired
|
|
67
|
+
|
|
68
|
+
Every sample carries the device's own index and the device time of its own
|
|
69
|
+
conversion. A forward step in that index is a loss with an exact count. A
|
|
70
|
+
step that is not forward is a break whose extent is not a number, and this
|
|
71
|
+
package says so rather than returning a count that would be a fiction.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
if (event.type === "gap") {
|
|
75
|
+
event.gap.samplesLost; // a number, or null for a break
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
A gap is emitted before the samples that follow it, so a caller writing
|
|
80
|
+
samples down writes the gap down first. Nothing splices.
|
|
81
|
+
|
|
82
|
+
## The contract is tested, not assumed
|
|
83
|
+
|
|
84
|
+
`contract/conformance.json` is emitted by the firmware from the codec the
|
|
85
|
+
device itself runs. Every message this package decodes, it decodes to the
|
|
86
|
+
fields that file states, and every malformed one it refuses for the reason
|
|
87
|
+
that file states: truncated, invalid, or reserved, which are three
|
|
88
|
+
different errors because the contract treats them as three different
|
|
89
|
+
things.
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
npm test
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
No device, no network, no build step. That is the command, and there is no
|
|
96
|
+
other. It needs Node 22.18 or newer, which runs the TypeScript as it is
|
|
97
|
+
written. `npm run build` produces the JavaScript that is published, which
|
|
98
|
+
runs on Node 20 and in any current browser.
|
|
99
|
+
|
|
100
|
+
## Time
|
|
101
|
+
|
|
102
|
+
A device's clock is a different crystal from the host's. The fit between
|
|
103
|
+
them is a line, and one exchange cannot tell a clock difference from a slow
|
|
104
|
+
answer, so one exchange fixes an offset and claims no rate. A skew beyond a
|
|
105
|
+
thousand parts per million, or a slope whose standard error is worse than a
|
|
106
|
+
hundred parts per million, is refused rather than believed. The offset is
|
|
107
|
+
kept, because the offset is the part that was measured.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
await device.timeSync();
|
|
111
|
+
device.session.timebase?.fit; // skewUsed says whether the rate is real
|
|
112
|
+
device.session.hostTime(batch.deviceTime);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## The model
|
|
116
|
+
|
|
117
|
+
A device can carry an encoder that turns a window of signal into an
|
|
118
|
+
embedding, and a head that turns that embedding into a few outputs. A head
|
|
119
|
+
is weights, never code.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { buildHead, quantizeEmbedding, evaluateHead, decodeHead } from "@intomind/sdk";
|
|
123
|
+
|
|
124
|
+
const blob = buildHead(weights, bias, scale, { name: "focus" });
|
|
125
|
+
evaluateHead(decodeHead(blob), quantizeEmbedding(embedding));
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The embedding is quantized to a fixed scale that is part of the contract,
|
|
129
|
+
so what a head produces on a host is what it produces on the device,
|
|
130
|
+
because the device evaluates exactly those integers.
|
|
131
|
+
|
|
132
|
+
## The browser
|
|
133
|
+
|
|
134
|
+
`web-bluetooth.ts` is the only file that reaches `navigator.bluetooth`.
|
|
135
|
+
Web Bluetooth needs a secure context and a user gesture, so
|
|
136
|
+
`requestDevice` has to be called from a click. Everything else in this
|
|
137
|
+
package works with no browser at all, which is how the tests run.
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
Free software under the GNU Affero General Public License, version 3. A
|
|
142
|
+
commercial license is available for building a closed product on this code
|
|
143
|
+
or running a modified service without publishing the changes. Write to
|
|
144
|
+
contact@intomind.com. See `LICENSING.md`, and `CONTRIBUTING.md` before a
|
|
145
|
+
first pull request.
|
|
146
|
+
|
|
147
|
+
IntoMind is a trademark of IntoMind, Inc. The license covers the code, not
|
|
148
|
+
the name.
|
package/dist/digest.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two digests the contract names, both synchronous.
|
|
3
|
+
*
|
|
4
|
+
* The update service reports a CRC-32 over the bytes it has accepted, and a
|
|
5
|
+
* head blob carries a SHA-256 of everything before it. Both are computed
|
|
6
|
+
* here rather than through a platform interface because `crypto.subtle` is
|
|
7
|
+
* asynchronous in a browser and the codec is not, and because a decoder that
|
|
8
|
+
* has to await a digest cannot refuse a bad blob where it reads it.
|
|
9
|
+
*/
|
|
10
|
+
/** Running CRC-32, for a transfer that arrives in pieces. */
|
|
11
|
+
export declare class Crc32 {
|
|
12
|
+
private state;
|
|
13
|
+
/** Fold more bytes into the running checksum, and return this so calls chain. */
|
|
14
|
+
update(data: Uint8Array): this;
|
|
15
|
+
/** The checksum over every slice folded in so far. */
|
|
16
|
+
finish(): number;
|
|
17
|
+
}
|
|
18
|
+
/** CRC-32 of one slice. */
|
|
19
|
+
export declare function crc32(data: Uint8Array): number;
|
|
20
|
+
/** SHA-256 of one slice, as thirty two bytes. */
|
|
21
|
+
export declare function sha256(data: Uint8Array): Uint8Array;
|
|
22
|
+
//# sourceMappingURL=digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../src/digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgBH,6DAA6D;AAC7D,qBAAa,KAAK;IAChB,OAAO,CAAC,KAAK,CAAc;IAE3B,iFAAiF;IACjF,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAW9B,sDAAsD;IACtD,MAAM,IAAI,MAAM;CAGjB;AAED,2BAA2B;AAC3B,wBAAgB,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAE9C;AAaD,iDAAiD;AACjD,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CA+CnD"}
|
package/dist/digest.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two digests the contract names, both synchronous.
|
|
3
|
+
*
|
|
4
|
+
* The update service reports a CRC-32 over the bytes it has accepted, and a
|
|
5
|
+
* head blob carries a SHA-256 of everything before it. Both are computed
|
|
6
|
+
* here rather than through a platform interface because `crypto.subtle` is
|
|
7
|
+
* asynchronous in a browser and the codec is not, and because a decoder that
|
|
8
|
+
* has to await a digest cannot refuse a bad blob where it reads it.
|
|
9
|
+
*/
|
|
10
|
+
// CRC-32, IEEE 802.3, the same polynomial zlib uses. Four bits at a time,
|
|
11
|
+
// which keeps the table at sixteen entries.
|
|
12
|
+
const CRC_POLY = 0xedb88320;
|
|
13
|
+
const CRC_TABLE = (() => {
|
|
14
|
+
const t = new Uint32Array(16);
|
|
15
|
+
for (let i = 0; i < 16; i++) {
|
|
16
|
+
let c = i;
|
|
17
|
+
for (let k = 0; k < 4; k++)
|
|
18
|
+
c = c & 1 ? (CRC_POLY ^ (c >>> 1)) >>> 0 : c >>> 1;
|
|
19
|
+
t[i] = c;
|
|
20
|
+
}
|
|
21
|
+
return t;
|
|
22
|
+
})();
|
|
23
|
+
/** Running CRC-32, for a transfer that arrives in pieces. */
|
|
24
|
+
export class Crc32 {
|
|
25
|
+
state = 0xffffffff;
|
|
26
|
+
/** Fold more bytes into the running checksum, and return this so calls chain. */
|
|
27
|
+
update(data) {
|
|
28
|
+
let c = this.state;
|
|
29
|
+
for (let i = 0; i < data.length; i++) {
|
|
30
|
+
c = (c ^ data[i]) >>> 0;
|
|
31
|
+
c = (CRC_TABLE[c & 0xf] ^ (c >>> 4)) >>> 0;
|
|
32
|
+
c = (CRC_TABLE[c & 0xf] ^ (c >>> 4)) >>> 0;
|
|
33
|
+
}
|
|
34
|
+
this.state = c;
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
/** The checksum over every slice folded in so far. */
|
|
38
|
+
finish() {
|
|
39
|
+
return (this.state ^ 0xffffffff) >>> 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** CRC-32 of one slice. */
|
|
43
|
+
export function crc32(data) {
|
|
44
|
+
return new Crc32().update(data).finish();
|
|
45
|
+
}
|
|
46
|
+
const K = new Uint32Array([
|
|
47
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
48
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
49
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
50
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
51
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
52
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
53
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
54
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
55
|
+
]);
|
|
56
|
+
/** SHA-256 of one slice, as thirty two bytes. */
|
|
57
|
+
export function sha256(data) {
|
|
58
|
+
const h = new Uint32Array([
|
|
59
|
+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
|
60
|
+
]);
|
|
61
|
+
// Message, a one bit, zeros, then the length in bits as a 64 bit count.
|
|
62
|
+
const bitLength = BigInt(data.length) * 8n;
|
|
63
|
+
const padded = new Uint8Array(((data.length + 9 + 63) >> 6) << 6);
|
|
64
|
+
padded.set(data);
|
|
65
|
+
padded[data.length] = 0x80;
|
|
66
|
+
new DataView(padded.buffer).setBigUint64(padded.length - 8, bitLength, false);
|
|
67
|
+
const w = new Uint32Array(64);
|
|
68
|
+
const block = new DataView(padded.buffer);
|
|
69
|
+
for (let at = 0; at < padded.length; at += 64) {
|
|
70
|
+
for (let i = 0; i < 16; i++)
|
|
71
|
+
w[i] = block.getUint32(at + i * 4, false);
|
|
72
|
+
for (let i = 16; i < 64; i++) {
|
|
73
|
+
const a = w[i - 15];
|
|
74
|
+
const b = w[i - 2];
|
|
75
|
+
const s0 = (rotr(a, 7) ^ rotr(a, 18) ^ (a >>> 3)) >>> 0;
|
|
76
|
+
const s1 = (rotr(b, 17) ^ rotr(b, 19) ^ (b >>> 10)) >>> 0;
|
|
77
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
|
|
78
|
+
}
|
|
79
|
+
let [a, b, c, d, e, f, g, hh] = h;
|
|
80
|
+
for (let i = 0; i < 64; i++) {
|
|
81
|
+
const s1 = (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) >>> 0;
|
|
82
|
+
const ch = ((e & f) ^ (~e & g)) >>> 0;
|
|
83
|
+
const t1 = (hh + s1 + ch + K[i] + w[i]) >>> 0;
|
|
84
|
+
const s0 = (rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) >>> 0;
|
|
85
|
+
const maj = ((a & b) ^ (a & c) ^ (b & c)) >>> 0;
|
|
86
|
+
const t2 = (s0 + maj) >>> 0;
|
|
87
|
+
hh = g;
|
|
88
|
+
g = f;
|
|
89
|
+
f = e;
|
|
90
|
+
e = (d + t1) >>> 0;
|
|
91
|
+
d = c;
|
|
92
|
+
c = b;
|
|
93
|
+
b = a;
|
|
94
|
+
a = (t1 + t2) >>> 0;
|
|
95
|
+
}
|
|
96
|
+
const round = [a, b, c, d, e, f, g, hh];
|
|
97
|
+
for (let i = 0; i < 8; i++)
|
|
98
|
+
h[i] = (h[i] + round[i]) >>> 0;
|
|
99
|
+
}
|
|
100
|
+
const out = new Uint8Array(32);
|
|
101
|
+
const view = new DataView(out.buffer);
|
|
102
|
+
for (let i = 0; i < 8; i++)
|
|
103
|
+
view.setUint32(i * 4, h[i], false);
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
function rotr(x, n) {
|
|
107
|
+
return ((x >>> n) | (x << (32 - n))) >>> 0;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.js","sourceRoot":"","sources":["../src/digest.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The IntoMind instrument client, for a browser and for Node.
|
|
3
|
+
*
|
|
4
|
+
* The protocol, the session, and the timebase do no input and no output.
|
|
5
|
+
* They are handed bytes that arrived and they hand back bytes to send,
|
|
6
|
+
* which means they work over whatever Bluetooth stack you already have and
|
|
7
|
+
* can be tested without one. `web-bluetooth.ts` is the browser transport,
|
|
8
|
+
* and it is the only file in this package that touches a radio.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { requestAndConnect } from "@intomind/sdk";
|
|
12
|
+
*
|
|
13
|
+
* const device = await requestAndConnect({
|
|
14
|
+
* onEvent(event) {
|
|
15
|
+
* if (event.type === "samples") write(event.batch);
|
|
16
|
+
* // Written down, never smoothed over.
|
|
17
|
+
* if (event.type === "gap") writeGap(event.gap);
|
|
18
|
+
* },
|
|
19
|
+
* });
|
|
20
|
+
* await device.send(device.session.startStream());
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* What a device can do is what the device says it can do. Nothing here
|
|
24
|
+
* holds a table of hardware, and a capability is a bit the device reports
|
|
25
|
+
* rather than a version number this package compares against.
|
|
26
|
+
*/
|
|
27
|
+
export * as protocol from "./protocol.ts";
|
|
28
|
+
export { CAPABILITIES, CAPABILITIES_HIGH, DeviceInfo, EMBED_SCALE, FILL, GAIN_BY_CODE, Invalid, MODES, NAME_MAX_COMPOSED, NAME_PREFIX, NO_ENCODER_ID, OPCODES, PRODUCT_NAME, ProtocolError, RATE_BY_CODE, Reserved, SERVICE, Truncated, VERSION, buildHead, composeName, continuity, decodeHead, decodeModelInterval, decodeNameParts, decodePacket, displayNames, evaluateHead, microvolts, nameFits, quantizeEmbedding, uuid, } from "./protocol.ts";
|
|
29
|
+
export type { CapabilityHighName, CapabilityName, Continuity, ModeName, ModelInterval, Envelope, HeadBlob, HeadEntry, OpcodeName, Packet, Prediction, Refusal, Request, Response, Status, UpdateResponse, } from "./protocol.ts";
|
|
30
|
+
export { Batch, NoDeviceInfo, NotCapable, Session, SessionError } from "./session.ts";
|
|
31
|
+
export type { Command, Event, Gap } from "./session.ts";
|
|
32
|
+
export { Exchange, MAX_SKEW_PPM, MAX_SKEW_STDERR_PPM, Timebase } from "./timebase.ts";
|
|
33
|
+
export type { Fit } from "./timebase.ts";
|
|
34
|
+
export { ChecksumMismatch, OffsetMismatch, Refused, Rejected, Transfer, TransferError, Unexpected, activate, } from "./transfer.ts";
|
|
35
|
+
export type { Step } from "./transfer.ts";
|
|
36
|
+
export { Connection, NoBluetooth, connect, hostClock, requestAndConnect, requestDevice } from "./web-bluetooth.ts";
|
|
37
|
+
export type { ConnectOptions, RequestOptions } from "./web-bluetooth.ts";
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,IAAI,EACJ,YAAY,EACZ,OAAO,EACP,KAAK,EACL,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,OAAO,EACP,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,SAAS,EACT,OAAO,EACP,SAAS,EACT,WAAW,EACX,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,IAAI,GACL,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,UAAU,EACV,MAAM,EACN,UAAU,EACV,OAAO,EACP,OAAO,EACP,QAAQ,EACR,MAAM,EACN,cAAc,GACf,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACtF,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACtF,YAAY,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,UAAU,EACV,QAAQ,GACT,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnH,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The IntoMind instrument client, for a browser and for Node.
|
|
3
|
+
*
|
|
4
|
+
* The protocol, the session, and the timebase do no input and no output.
|
|
5
|
+
* They are handed bytes that arrived and they hand back bytes to send,
|
|
6
|
+
* which means they work over whatever Bluetooth stack you already have and
|
|
7
|
+
* can be tested without one. `web-bluetooth.ts` is the browser transport,
|
|
8
|
+
* and it is the only file in this package that touches a radio.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { requestAndConnect } from "@intomind/sdk";
|
|
12
|
+
*
|
|
13
|
+
* const device = await requestAndConnect({
|
|
14
|
+
* onEvent(event) {
|
|
15
|
+
* if (event.type === "samples") write(event.batch);
|
|
16
|
+
* // Written down, never smoothed over.
|
|
17
|
+
* if (event.type === "gap") writeGap(event.gap);
|
|
18
|
+
* },
|
|
19
|
+
* });
|
|
20
|
+
* await device.send(device.session.startStream());
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* What a device can do is what the device says it can do. Nothing here
|
|
24
|
+
* holds a table of hardware, and a capability is a bit the device reports
|
|
25
|
+
* rather than a version number this package compares against.
|
|
26
|
+
*/
|
|
27
|
+
export * as protocol from "./protocol.js";
|
|
28
|
+
export { CAPABILITIES, CAPABILITIES_HIGH, DeviceInfo, EMBED_SCALE, FILL, GAIN_BY_CODE, Invalid, MODES, NAME_MAX_COMPOSED, NAME_PREFIX, NO_ENCODER_ID, OPCODES, PRODUCT_NAME, ProtocolError, RATE_BY_CODE, Reserved, SERVICE, Truncated, VERSION, buildHead, composeName, continuity, decodeHead, decodeModelInterval, decodeNameParts, decodePacket, displayNames, evaluateHead, microvolts, nameFits, quantizeEmbedding, uuid, } from "./protocol.js";
|
|
29
|
+
export { Batch, NoDeviceInfo, NotCapable, Session, SessionError } from "./session.js";
|
|
30
|
+
export { Exchange, MAX_SKEW_PPM, MAX_SKEW_STDERR_PPM, Timebase } from "./timebase.js";
|
|
31
|
+
export { ChecksumMismatch, OffsetMismatch, Refused, Rejected, Transfer, TransferError, Unexpected, activate, } from "./transfer.js";
|
|
32
|
+
export { Connection, NoBluetooth, connect, hostClock, requestAndConnect, requestDevice } from "./web-bluetooth.js";
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,IAAI,EACJ,YAAY,EACZ,OAAO,EACP,KAAK,EACL,iBAAiB,EACjB,WAAW,EACX,aAAa,EACb,OAAO,EACP,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,SAAS,EACT,OAAO,EACP,SAAS,EACT,WAAW,EACX,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,IAAI,GACL,MAAM,eAAe,CAAC;AAqBvB,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGtF,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGtF,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,UAAU,EACV,QAAQ,GACT,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|