@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/src/digest.ts ADDED
@@ -0,0 +1,115 @@
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
+
11
+ // CRC-32, IEEE 802.3, the same polynomial zlib uses. Four bits at a time,
12
+ // which keeps the table at sixteen entries.
13
+ const CRC_POLY = 0xedb88320;
14
+
15
+ const CRC_TABLE = (() => {
16
+ const t = new Uint32Array(16);
17
+ for (let i = 0; i < 16; i++) {
18
+ let c = i;
19
+ for (let k = 0; k < 4; k++) c = c & 1 ? (CRC_POLY ^ (c >>> 1)) >>> 0 : c >>> 1;
20
+ t[i] = c;
21
+ }
22
+ return t;
23
+ })();
24
+
25
+ /** Running CRC-32, for a transfer that arrives in pieces. */
26
+ export class Crc32 {
27
+ private state = 0xffffffff;
28
+
29
+ /** Fold more bytes into the running checksum, and return this so calls chain. */
30
+ update(data: Uint8Array): this {
31
+ let c = this.state;
32
+ for (let i = 0; i < data.length; i++) {
33
+ c = (c ^ data[i]!) >>> 0;
34
+ c = (CRC_TABLE[c & 0xf]! ^ (c >>> 4)) >>> 0;
35
+ c = (CRC_TABLE[c & 0xf]! ^ (c >>> 4)) >>> 0;
36
+ }
37
+ this.state = c;
38
+ return this;
39
+ }
40
+
41
+ /** The checksum over every slice folded in so far. */
42
+ finish(): number {
43
+ return (this.state ^ 0xffffffff) >>> 0;
44
+ }
45
+ }
46
+
47
+ /** CRC-32 of one slice. */
48
+ export function crc32(data: Uint8Array): number {
49
+ return new Crc32().update(data).finish();
50
+ }
51
+
52
+ const K = new Uint32Array([
53
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
54
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
55
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
56
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
57
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
58
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
59
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
60
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
61
+ ]);
62
+
63
+ /** SHA-256 of one slice, as thirty two bytes. */
64
+ export function sha256(data: Uint8Array): Uint8Array {
65
+ const h = new Uint32Array([
66
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
67
+ ]);
68
+ // Message, a one bit, zeros, then the length in bits as a 64 bit count.
69
+ const bitLength = BigInt(data.length) * 8n;
70
+ const padded = new Uint8Array(((data.length + 9 + 63) >> 6) << 6);
71
+ padded.set(data);
72
+ padded[data.length] = 0x80;
73
+ new DataView(padded.buffer).setBigUint64(padded.length - 8, bitLength, false);
74
+
75
+ const w = new Uint32Array(64);
76
+ const block = new DataView(padded.buffer);
77
+ for (let at = 0; at < padded.length; at += 64) {
78
+ for (let i = 0; i < 16; i++) w[i] = block.getUint32(at + i * 4, false);
79
+ for (let i = 16; i < 64; i++) {
80
+ const a = w[i - 15]!;
81
+ const b = w[i - 2]!;
82
+ const s0 = (rotr(a, 7) ^ rotr(a, 18) ^ (a >>> 3)) >>> 0;
83
+ const s1 = (rotr(b, 17) ^ rotr(b, 19) ^ (b >>> 10)) >>> 0;
84
+ w[i] = (w[i - 16]! + s0 + w[i - 7]! + s1) >>> 0;
85
+ }
86
+ let [a, b, c, d, e, f, g, hh] = h as unknown as number[];
87
+ for (let i = 0; i < 64; i++) {
88
+ const s1 = (rotr(e!, 6) ^ rotr(e!, 11) ^ rotr(e!, 25)) >>> 0;
89
+ const ch = ((e! & f!) ^ (~e! & g!)) >>> 0;
90
+ const t1 = (hh! + s1 + ch + K[i]! + w[i]!) >>> 0;
91
+ const s0 = (rotr(a!, 2) ^ rotr(a!, 13) ^ rotr(a!, 22)) >>> 0;
92
+ const maj = ((a! & b!) ^ (a! & c!) ^ (b! & c!)) >>> 0;
93
+ const t2 = (s0 + maj) >>> 0;
94
+ hh = g;
95
+ g = f;
96
+ f = e;
97
+ e = (d! + t1) >>> 0;
98
+ d = c;
99
+ c = b;
100
+ b = a;
101
+ a = (t1 + t2) >>> 0;
102
+ }
103
+ const round = [a!, b!, c!, d!, e!, f!, g!, hh!];
104
+ for (let i = 0; i < 8; i++) h[i] = (h[i]! + round[i]!) >>> 0;
105
+ }
106
+
107
+ const out = new Uint8Array(32);
108
+ const view = new DataView(out.buffer);
109
+ for (let i = 0; i < 8; i++) view.setUint32(i * 4, h[i]!, false);
110
+ return out;
111
+ }
112
+
113
+ function rotr(x: number, n: number): number {
114
+ return ((x >>> n) | (x << (32 - n))) >>> 0;
115
+ }
package/src/index.ts ADDED
@@ -0,0 +1,103 @@
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
+
28
+ export * as protocol from "./protocol.ts";
29
+
30
+ export {
31
+ CAPABILITIES,
32
+ CAPABILITIES_HIGH,
33
+ DeviceInfo,
34
+ EMBED_SCALE,
35
+ FILL,
36
+ GAIN_BY_CODE,
37
+ Invalid,
38
+ MODES,
39
+ NAME_MAX_COMPOSED,
40
+ NAME_PREFIX,
41
+ NO_ENCODER_ID,
42
+ OPCODES,
43
+ PRODUCT_NAME,
44
+ ProtocolError,
45
+ RATE_BY_CODE,
46
+ Reserved,
47
+ SERVICE,
48
+ Truncated,
49
+ VERSION,
50
+ buildHead,
51
+ composeName,
52
+ continuity,
53
+ decodeHead,
54
+ decodeModelInterval,
55
+ decodeNameParts,
56
+ decodePacket,
57
+ displayNames,
58
+ evaluateHead,
59
+ microvolts,
60
+ nameFits,
61
+ quantizeEmbedding,
62
+ uuid,
63
+ } from "./protocol.ts";
64
+
65
+ export type {
66
+ CapabilityHighName,
67
+ CapabilityName,
68
+ Continuity,
69
+ ModeName,
70
+ ModelInterval,
71
+ Envelope,
72
+ HeadBlob,
73
+ HeadEntry,
74
+ OpcodeName,
75
+ Packet,
76
+ Prediction,
77
+ Refusal,
78
+ Request,
79
+ Response,
80
+ Status,
81
+ UpdateResponse,
82
+ } from "./protocol.ts";
83
+
84
+ export { Batch, NoDeviceInfo, NotCapable, Session, SessionError } from "./session.ts";
85
+ export type { Command, Event, Gap } from "./session.ts";
86
+
87
+ export { Exchange, MAX_SKEW_PPM, MAX_SKEW_STDERR_PPM, Timebase } from "./timebase.ts";
88
+ export type { Fit } from "./timebase.ts";
89
+
90
+ export {
91
+ ChecksumMismatch,
92
+ OffsetMismatch,
93
+ Refused,
94
+ Rejected,
95
+ Transfer,
96
+ TransferError,
97
+ Unexpected,
98
+ activate,
99
+ } from "./transfer.ts";
100
+ export type { Step } from "./transfer.ts";
101
+
102
+ export { Connection, NoBluetooth, connect, hostClock, requestAndConnect, requestDevice } from "./web-bluetooth.ts";
103
+ export type { ConnectOptions, RequestOptions } from "./web-bluetooth.ts";