@cero-base/cero 1.2.0 → 1.3.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/package.json +2 -2
- package/src/bluetooth.js +28 -10
- package/src/index.js +11 -3
- package/types/bluetooth.d.ts +2 -1
- package/types/index.d.ts +6 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cero-base/cero",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "The ideal p2p API — everything is a handle, handles contain refs, refs contain rows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"test:bare": "npx bare test/bare-smoke.js"
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
|
-
"@cero-base/core": "^1.
|
|
89
|
+
"@cero-base/core": "^1.3.0",
|
|
90
90
|
"b4a": "^1.8.1",
|
|
91
91
|
"bare-abort-controller": "^1.1.2",
|
|
92
92
|
"bare-crypto": "^1.15.3",
|
package/src/bluetooth.js
CHANGED
|
@@ -48,6 +48,7 @@ export class Bluetooth extends ReadyResource {
|
|
|
48
48
|
this._backend = backend || null
|
|
49
49
|
this._autoStart = autoStart === true
|
|
50
50
|
this._transport = null
|
|
51
|
+
this._name = null
|
|
51
52
|
this._announces = new Set()
|
|
52
53
|
/** @type {'unsupported'|'unauthorized'|'off'|'waiting'|'starting'|'on'} */
|
|
53
54
|
this.state = 'off'
|
|
@@ -114,9 +115,18 @@ export class Bluetooth extends ReadyResource {
|
|
|
114
115
|
*
|
|
115
116
|
* @returns {Promise<void>}
|
|
116
117
|
*/
|
|
117
|
-
async start() {
|
|
118
|
+
async start({ name } = {}) {
|
|
119
|
+
if (name !== undefined) this._name = name
|
|
118
120
|
if (this.state === 'unsupported') return
|
|
119
|
-
if (this._transport)
|
|
121
|
+
if (this._transport) {
|
|
122
|
+
// reuse one transport across toggles — recreating leaks iOS CoreBluetooth
|
|
123
|
+
// managers (can't destroy()) and their stale GATT service
|
|
124
|
+
this._transport.name = this._name || ''
|
|
125
|
+
this._transport.resume()
|
|
126
|
+
this.state = this._transport.state
|
|
127
|
+
this.emit('update')
|
|
128
|
+
return
|
|
129
|
+
}
|
|
120
130
|
const handle = this._handle
|
|
121
131
|
|
|
122
132
|
this._transport = new BluetoothTransport({
|
|
@@ -127,7 +137,8 @@ export class Bluetooth extends ReadyResource {
|
|
|
127
137
|
uuid: handle.network.channel
|
|
128
138
|
? Buffer.from(handle.network.channel)
|
|
129
139
|
: handle.identity.publicKey,
|
|
130
|
-
nodeId: handle.identity.publicKey
|
|
140
|
+
nodeId: handle.identity.publicKey,
|
|
141
|
+
name: this._name || ''
|
|
131
142
|
})
|
|
132
143
|
this._transport.on('update', () => {
|
|
133
144
|
this.state = this._transport.state
|
|
@@ -156,17 +167,24 @@ export class Bluetooth extends ReadyResource {
|
|
|
156
167
|
await t.close().catch(safetyCatch)
|
|
157
168
|
}
|
|
158
169
|
if (!this._transport) return
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
this._transport = null
|
|
170
|
+
// suspend, don't close: keep the transport (and its GATT service) so a later
|
|
171
|
+
// start() resumes the same instance instead of leaking a new one. suspend()
|
|
172
|
+
// is async (it says goodbye + drains before hanging up); await it.
|
|
173
|
+
await this._transport.suspend()
|
|
165
174
|
this.state = 'off'
|
|
166
175
|
this.emit('update')
|
|
167
176
|
}
|
|
168
177
|
|
|
169
178
|
async _close() {
|
|
170
|
-
|
|
179
|
+
for (const t of [...this._announces]) {
|
|
180
|
+
this._announces.delete(t)
|
|
181
|
+
await t.close().catch(safetyCatch)
|
|
182
|
+
}
|
|
183
|
+
if (this._transport) {
|
|
184
|
+
await this._transport.close().catch(safetyCatch)
|
|
185
|
+
this._transport = null
|
|
186
|
+
}
|
|
187
|
+
this.state = 'off'
|
|
188
|
+
this.emit('update')
|
|
171
189
|
}
|
|
172
190
|
}
|
package/src/index.js
CHANGED
|
@@ -69,7 +69,7 @@ export { t, schema } from './lib/spec.js'
|
|
|
69
69
|
* @property {number} [recoveryTimeout] Max wait for peer data + writer capability during recovery.
|
|
70
70
|
* @property {Uint8Array} [storageKey] 32-byte key encrypting local key material (master seed, device keypairs) at rest. Source it from the OS keychain — cero never stores it.
|
|
71
71
|
* @property {boolean} [extensions] `false` disables the bundled extensions (profileSync, handleSync) for this instance. Build with `{ extensions: false }` too so the spec matches.
|
|
72
|
-
* @property {boolean | any} [bluetooth]
|
|
72
|
+
* @property {boolean | { autoStart?: boolean, backend?: any }} [bluetooth] `true` enables nearby (Bluetooth) sync via `me.bluetooth` (auto-started). `{ autoStart: false }` creates the facade without starting the radio — the app calls `me.bluetooth.start()`/`stop()` (user toggle). `backend` injects a bare-bluetooth-shaped backend (tests); absent backend on an unsupported host → `me.bluetooth.state === 'unsupported'`.
|
|
73
73
|
*/
|
|
74
74
|
|
|
75
75
|
/**
|
|
@@ -177,9 +177,17 @@ export async function cero(dir, spec, opts = {}) {
|
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
if (opts.bluetooth) {
|
|
180
|
+
// `true` → defaults; `{ autoStart, backend }` → options. A bare backend
|
|
181
|
+
// object (pre-1.3 shape, has Central/Server) is still accepted.
|
|
182
|
+
const bt =
|
|
183
|
+
opts.bluetooth === true
|
|
184
|
+
? {}
|
|
185
|
+
: opts.bluetooth.Central
|
|
186
|
+
? { backend: opts.bluetooth }
|
|
187
|
+
: opts.bluetooth
|
|
180
188
|
me.bluetooth = new Bluetooth(me, {
|
|
181
|
-
backend:
|
|
182
|
-
autoStart:
|
|
189
|
+
backend: bt.backend || null,
|
|
190
|
+
autoStart: bt.autoStart !== false
|
|
183
191
|
})
|
|
184
192
|
me.once('close', () => me.bluetooth.close().catch(safetyCatch))
|
|
185
193
|
await me.bluetooth.ready()
|
package/types/bluetooth.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export class Bluetooth extends ReadyResource {
|
|
|
28
28
|
_backend: any;
|
|
29
29
|
_autoStart: boolean;
|
|
30
30
|
_transport: BluetoothTransport;
|
|
31
|
+
_name: any;
|
|
31
32
|
_announces: Set<any>;
|
|
32
33
|
/** @type {'unsupported'|'unauthorized'|'off'|'waiting'|'starting'|'on'} */
|
|
33
34
|
state: "unsupported" | "unauthorized" | "off" | "waiting" | "starting" | "on";
|
|
@@ -52,7 +53,7 @@ export class Bluetooth extends ReadyResource {
|
|
|
52
53
|
*
|
|
53
54
|
* @returns {Promise<void>}
|
|
54
55
|
*/
|
|
55
|
-
start(): Promise<void>;
|
|
56
|
+
start({ name }?: {}): Promise<void>;
|
|
56
57
|
/**
|
|
57
58
|
* Stop advertising/scanning and drop links. Idempotent. Sync stops; local
|
|
58
59
|
* data and the rest of the network (DHT) are untouched.
|
package/types/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* @property {number} [recoveryTimeout] Max wait for peer data + writer capability during recovery.
|
|
20
20
|
* @property {Uint8Array} [storageKey] 32-byte key encrypting local key material (master seed, device keypairs) at rest. Source it from the OS keychain — cero never stores it.
|
|
21
21
|
* @property {boolean} [extensions] `false` disables the bundled extensions (profileSync, handleSync) for this instance. Build with `{ extensions: false }` too so the spec matches.
|
|
22
|
-
* @property {boolean | any} [bluetooth]
|
|
22
|
+
* @property {boolean | { autoStart?: boolean, backend?: any }} [bluetooth] `true` enables nearby (Bluetooth) sync via `me.bluetooth` (auto-started). `{ autoStart: false }` creates the facade without starting the radio — the app calls `me.bluetooth.start()`/`stop()` (user toggle). `backend` injects a bare-bluetooth-shaped backend (tests); absent backend on an unsupported host → `me.bluetooth.state === 'unsupported'`.
|
|
23
23
|
*/
|
|
24
24
|
/**
|
|
25
25
|
* Open (or create) a cero handle at `dir`. Sets up storage, network and
|
|
@@ -133,9 +133,12 @@ export type CeroOpts = {
|
|
|
133
133
|
*/
|
|
134
134
|
extensions?: boolean;
|
|
135
135
|
/**
|
|
136
|
-
* `true` enables nearby (Bluetooth) sync via `me.bluetooth
|
|
136
|
+
* `true` enables nearby (Bluetooth) sync via `me.bluetooth` (auto-started). `{ autoStart: false }` creates the facade without starting the radio — the app calls `me.bluetooth.start()`/`stop()` (user toggle). `backend` injects a bare-bluetooth-shaped backend (tests); absent backend on an unsupported host → `me.bluetooth.state === 'unsupported'`.
|
|
137
137
|
*/
|
|
138
|
-
bluetooth?: boolean |
|
|
138
|
+
bluetooth?: boolean | {
|
|
139
|
+
autoStart?: boolean;
|
|
140
|
+
backend?: any;
|
|
141
|
+
};
|
|
139
142
|
};
|
|
140
143
|
import { t } from './lib/spec.js';
|
|
141
144
|
import { put } from './lib/operators.js';
|