@condorinst/mobile-bridge 0.19.2 → 0.21.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/AGENTS.md +100 -42
- package/CHANGELOG.md +106 -0
- package/README.md +64 -14
- package/contract/bridge-contract.json +70 -25
- package/dist/cli.cjs +436 -5
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +433 -3
- package/dist/cli.js.map +1 -1
- package/dist/dev-harness.global.js +2110 -0
- package/dist/dev.cjs +1662 -0
- package/dist/dev.cjs.map +1 -0
- package/dist/dev.d.cts +683 -0
- package/dist/dev.d.ts +683 -0
- package/dist/dev.js +1611 -0
- package/dist/dev.js.map +1 -0
- package/dist/index.cjs +96 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +265 -19
- package/dist/index.d.ts +265 -19
- package/dist/index.js +94 -3
- package/dist/index.js.map +1 -1
- package/docs/agent-guide.md +83 -25
- package/docs/bridge-contract.md +154 -25
- package/docs/client-guide.md +39 -28
- package/docs/device-testing.md +84 -0
- package/docs/pilot-onboarding.md +26 -12
- package/docs/troubleshooting.md +83 -18
- package/examples/minimal-home/AGENTS.md +9 -6
- package/examples/minimal-home/README.md +10 -5
- package/examples/minimal-home/build.mjs +2 -1
- package/examples/minimal-home/index.html +2 -0
- package/examples/minimal-home/package.json +3 -2
- package/examples/minimal-home/src/main.ts +151 -73
- package/llms-full.txt +2041 -0
- package/llms.txt +15 -13
- package/package.json +9 -3
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"contractVersion": "0.
|
|
3
|
+
"contractVersion": "0.21.0",
|
|
4
4
|
"description": "Machine-readable contract of the Condor Canvas JS<->Native bridge. It states what the TypeScript declarations in dist/index.d.ts cannot express: which keys and commands a sandboxed client can actually reach, which ones need human confirmation, where messages are dropped in silence, the hard limits, and which capability each native version carries. The TypeScript types remain canonical for payload shapes.",
|
|
5
5
|
"audience": "Developers and AI agents building the client bundle that renders inside the Canvas Home.",
|
|
6
6
|
|
|
7
7
|
"versions": {
|
|
8
8
|
"note": "Four independent numbers coexist. Only nativeVersion tells you what the device can do.",
|
|
9
|
-
"package": "0.
|
|
9
|
+
"package": "0.21.0",
|
|
10
10
|
"shellVersion": "0.6.0",
|
|
11
11
|
"clientProtocolVersion": "0.5.0",
|
|
12
|
-
"nativeVersion": "0.
|
|
12
|
+
"nativeVersion": "0.17.0",
|
|
13
13
|
"capabilityDetection": {
|
|
14
14
|
"how": "await BridgeClient.handshake({ clientVersion }) resolves to { shellVersion, nativeVersion, accepted }. Compare ack.nativeVersion against the minNativeVersion in capabilities[].",
|
|
15
15
|
"acceptedIsAlwaysTrue": true,
|
|
16
16
|
"acceptedWarning": "The native side never rejects a handshake, so `accepted` carries no information. Never branch on it.",
|
|
17
|
-
"nativeVersionMayBeNull": "null
|
|
17
|
+
"nativeVersionMayBeNull": "null when the shell could not reach the native side, and in bundles compiled against SDK <= 0.16.x, where the shell did not relay it. Treat null as 'assume nothing beyond the 0.13.0 baseline'. The dev harness reports 0.17.0 unless a scenario sets it to null."
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
"keys": {
|
|
81
81
|
"note": "13 keys exist; 12 are reachable by the sandboxed client. Subscribe with BridgeClient.on(key, cb). Payload shapes are canonical in dist/index.d.ts under the listed type.",
|
|
82
82
|
"entries": {
|
|
83
|
-
"pingPong": { "reachableByClient": true, "payloadType": "PingPongPayload", "emittedWhen": "reply to the `ping` command" },
|
|
84
|
-
"userDevice": { "reachableByClient": true, "payloadType": "UserDevicePayload", "emittedWhen": "reply to the `userDevice` command, and on device roster changes" },
|
|
83
|
+
"pingPong": { "reachableByClient": true, "payloadType": "PingPongPayload", "emittedWhen": "reply to the `ping` command, once the app's background service is up" },
|
|
84
|
+
"userDevice": { "reachableByClient": true, "payloadType": "UserDevicePayload", "emittedWhen": "reply to the `userDevice` command when the device list loads, and on device roster changes. Not guaranteed: see silentDropPaths and prefer BridgeClient.requestUserDevices()." },
|
|
85
85
|
"deviceLightSensors": { "reachableByClient": true, "payloadType": "DeviceLightSensorsPayload", "emittedWhen": "real-time stream, only while realTime is on for that device", "discriminator": "type", "variants": ["actlumus", "actlumus2"] },
|
|
86
86
|
"syncTime": { "reachableByClient": true, "payloadType": "SyncTimeAckPayload", "emittedWhen": "ack of the `syncTime` command" },
|
|
87
87
|
"realTime": { "reachableByClient": true, "payloadType": "RealTimeAckPayload", "emittedWhen": "ack of the `realTime` command" },
|
|
@@ -99,19 +99,19 @@
|
|
|
99
99
|
"commands": {
|
|
100
100
|
"note": "Send with BridgeClient.send(command, args). It is fire-and-forget: there is no return value and no throw. Replies arrive on the key named in repliesOn.",
|
|
101
101
|
"entries": {
|
|
102
|
-
"ping": { "args": {}, "requiresConfirmation": false, "repliesOn": "pingPong" },
|
|
103
|
-
"userDevice": { "args": { "getFromServer": "boolean, default false" }, "requiresConfirmation": false, "repliesOn": "userDevice" },
|
|
104
|
-
"realTime": { "args": { "serialNo": "int", "value": "boolean" }, "requiresConfirmation": false, "repliesOn": "realTime", "note": "Off by default. The deviceLightSensors stream only flows while this is on." },
|
|
105
|
-
"deviceConnection": { "args": { "type": "'add' | 'remove'", "serialNo": "int" }, "requiresConfirmation": false, "repliesOn": "deviceConnection" },
|
|
106
|
-
"sensorLog": { "args": { "requestId": "string", "serialNo": "int", "bodyPart": "'wrist' | 'necklace', optional", "limit": "1..1000, optional", "startingAfter": "opaque cursor, optional", "endingBefore": "opaque cursor, optional", "startTime": "timestamp, optional, minNativeVersion 0.15.0", "endTime": "timestamp, optional, minNativeVersion 0.15.0" }, "requiresConfirmation": false, "repliesOn": "sensorLog", "prefer": "BridgeClient.fetchSensorLog(query), which correlates requestId and applies a timeout for you." },
|
|
102
|
+
"ping": { "args": {}, "requiresConfirmation": false, "repliesOn": "pingPong", "note": "Handled by the app's background service: lost without a reply if sent before the service is up. BridgeClient.waitForService() resends it until a pingPong arrives." },
|
|
103
|
+
"userDevice": { "args": { "getFromServer": "boolean, default false. false: memory or cache while fresh, else the server (use at boot). true: the server first, cache on failure (use for a refresh button)." }, "requiresConfirmation": false, "repliesOn": "userDevice", "prefer": "BridgeClient.requestUserDevices({ getFromServer }), which resends with backoff and resolves { status: 'timeout', hasDevices } instead of waiting forever.", "note": "Handled by the app's background service. A request sent before it is up is lost, and no reply is sent when the list fails to load — including an account with no linked device. An empty list is never sent." },
|
|
104
|
+
"realTime": { "args": { "serialNo": "int", "deviceId": "int, optional, minNativeVersion 0.17.0", "value": "boolean" }, "requiresConfirmation": false, "repliesOn": "realTime", "note": "Off by default. The deviceLightSensors stream only flows while this is on. Always send serialNo; add deviceId to address one device when two share a serialNo." },
|
|
105
|
+
"deviceConnection": { "args": { "type": "'add' | 'remove'", "serialNo": "int", "deviceId": "int, optional, minNativeVersion 0.17.0" }, "requiresConfirmation": false, "repliesOn": "deviceConnection", "note": "Pairs nothing. 'add' subscribes to the BLE connection state of a device from the userDevice list; the state arrives on the deviceConnection key on every change. 'remove' stops it." },
|
|
106
|
+
"sensorLog": { "args": { "requestId": "string", "serialNo": "int", "bodyPart": "'wrist' | 'necklace', optional", "limit": "1..1000, optional", "startingAfter": "opaque cursor, optional", "endingBefore": "opaque cursor, optional", "startTime": "timestamp, optional, minNativeVersion 0.15.0", "endTime": "timestamp, optional, minNativeVersion 0.15.0" }, "requiresConfirmation": false, "repliesOn": "sensorLog", "prefer": "BridgeClient.fetchSensorLog(query), which correlates requestId and applies a timeout for you.", "paging": { "orderWithinPage": "chronological ascending", "noCursorNoRange": "the most recent `limit` logs; older pages with endingBefore while hasPrevious", "withStartTime": "the oldest logs of the range first; newer pages with startingAfter while hasMore", "onlyEndTime": "the most recent logs before endTime", "defaultLimit": 10, "maxLimit": 1000, "logPeriod": "one log per period, programmable per device, default 60 s; derive it from consecutive log_time values" } },
|
|
107
107
|
"openSettings": { "args": {}, "requiresConfirmation": false, "repliesOn": null },
|
|
108
108
|
"requestPermission": { "args": { "permission": "string, must match a native AppPermission name" }, "requiresConfirmation": false, "repliesOn": null, "note": "There is no permission-result key. The OS shows its own prompt and the outcome reaches you as a fresh systemStatus emission." },
|
|
109
109
|
"setStatusBarColor": { "args": { "color": "'#RRGGBB'" }, "requiresConfirmation": false, "repliesOn": null },
|
|
110
110
|
"navigationState": { "args": { "canGoBack": "boolean" }, "requiresConfirmation": false, "repliesOn": null, "prefer": "BridgeClient.reportNavigation(canGoBack)" },
|
|
111
111
|
"language": { "args": {}, "requiresConfirmation": false, "repliesOn": "language", "note": "Pull. The native push happens before window.CondorBridge exists, so a client that mounts later must ask.", "minNativeVersion": "0.14.0" },
|
|
112
112
|
"jsError": { "args": { "message": "string", "stack": "optional", "source": "optional", "lineno": "optional", "colno": "optional" }, "requiresConfirmation": false, "repliesOn": null, "note": "Rate limited: 20 per 10 s, fields truncated at 4 KB." },
|
|
113
|
-
"syncTime": { "args": { "serialNo": "int" }, "requiresConfirmation": true, "repliesOn": "syncTime" },
|
|
114
|
-
"deleteMemory": { "args": { "serialNo": "int" }, "requiresConfirmation": true, "repliesOn": "deleteMemory" },
|
|
113
|
+
"syncTime": { "args": { "serialNo": "int", "deviceId": "int, optional, minNativeVersion 0.17.0" }, "requiresConfirmation": true, "repliesOn": "syncTime" },
|
|
114
|
+
"deleteMemory": { "args": { "serialNo": "int", "deviceId": "int, optional, minNativeVersion 0.17.0" }, "requiresConfirmation": true, "repliesOn": "deleteMemory" },
|
|
115
115
|
"logout": { "args": {}, "requiresConfirmation": true, "repliesOn": null },
|
|
116
116
|
"dfu": { "args": {}, "denied": true, "repliesOn": null }
|
|
117
117
|
},
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
"name": "sensorLog failure",
|
|
131
131
|
"channel": "sensorLog key",
|
|
132
132
|
"shape": { "requestId": "string", "success": false, "error": "string code" },
|
|
133
|
-
"codes": ["CONFLICTING_CURSORS", "INVALID_BODY_PART", "INVALID_LIMIT", "INVALID_START_TIME", "INVALID_END_TIME", "INVALID_TIME_RANGE", "MISSING_DEVICE_SERIAL_NO", "invalid session", "device not found for this user"],
|
|
133
|
+
"codes": ["CONFLICTING_CURSORS", "INVALID_BODY_PART", "INVALID_LIMIT", "INVALID_START_TIME", "INVALID_END_TIME", "INVALID_TIME_RANGE", "MISSING_DEVICE_SERIAL_NO", "DEVICE_SERIAL_AMBIGUOUS", "invalid session", "device not found for this user"],
|
|
134
134
|
"visibility": "fetchSensorLog RESOLVES with success false. It only rejects on timeout.",
|
|
135
135
|
"warning": "error is a diagnostic code, never user-facing text. Map it to your own copy."
|
|
136
136
|
},
|
|
@@ -148,13 +148,16 @@
|
|
|
148
148
|
{ "cause": "unknown command type", "trigger": "typo, or a command added in a newer nativeVersion than the device runs", "observable": "nothing" },
|
|
149
149
|
{ "cause": "permission name outside the native enum", "trigger": "requestPermission with an unrecognized string", "observable": "nothing" },
|
|
150
150
|
{ "cause": "malformed args", "trigger": "realTime, syncTime, deleteMemory or deviceConnection with wrong types", "observable": "nothing" },
|
|
151
|
-
{ "cause": "postMessage failing schema validation", "trigger": "hand-rolled postMessage instead of BridgeClient", "observable": "nothing" }
|
|
151
|
+
{ "cause": "postMessage failing schema validation", "trigger": "hand-rolled postMessage instead of BridgeClient", "observable": "nothing" },
|
|
152
|
+
{ "cause": "background service not running yet", "trigger": "userDevice or ping sent before the app's background service is up, typically right after a cold start; the app does not re-send the list when the service comes up", "observable": "nothing (the handshake, systemStatus and language already work)", "mitigation": "BridgeClient.requestUserDevices() / waitForService()" },
|
|
153
|
+
{ "cause": "device list did not load", "trigger": "userDevice for an account with no linked device, or when the server request fails (no internet, session problem); the app replies only on success", "observable": "nothing; systemStatus.hasDevices stays false", "mitigation": "BridgeClient.requestUserDevices() resolves { status: 'timeout', hasDevices } after 30 s: render an empty state with a retry" }
|
|
152
154
|
],
|
|
153
155
|
|
|
154
156
|
"capabilities": [
|
|
155
157
|
{ "feature": "languageKey", "minNativeVersion": "0.14.0", "description": "The language key and the language pull command exist." },
|
|
156
158
|
{ "feature": "sensorLogTimeRange", "minNativeVersion": "0.15.0", "description": "sensorLog accepts startTime and endTime." },
|
|
157
159
|
{ "feature": "lightSensorRawChannels", "minNativeVersion": "0.16.0", "description": "deviceLightSensors carries the raw light_sensor_* channels and the actlumus2 variant." },
|
|
160
|
+
{ "feature": "deviceIdAddressing", "minNativeVersion": "0.17.0", "description": "realTime, syncTime, deleteMemory and deviceConnection accept an optional deviceId, so one device can be addressed when an ActLumus and a Plus share a serialNo; the acks echo it; deviceConnection, deviceNotification and deviceLightSensors carry it when the serialNo is shared; systemStatus adds deviceSyncErrorById." },
|
|
158
161
|
{ "feature": "nativeVersionRelay", "minShellVersion": "0.6.0", "description": "The shell relays nativeVersion into the sandboxed client. Below this, handshake-ack carried only shellVersion and capability detection was impossible from inside the iframe." }
|
|
159
162
|
],
|
|
160
163
|
|
|
@@ -176,26 +179,68 @@
|
|
|
176
179
|
"statusBarHook": "<meta name=\"theme-color\" content=\"#RRGGBB\"> in the bundle sets the native status bar colour. The setStatusBarColor command overrides it at runtime."
|
|
177
180
|
},
|
|
178
181
|
|
|
182
|
+
"payloadItems": {
|
|
183
|
+
"note": "Item shapes of userDevice and sensorLog. Canonical types in dist/index.d.ts. Fields not listed here are not part of the public contract — do not read them.",
|
|
184
|
+
"joinKey": "deviceId. An item of devicesTelemetry or devicesUserConfig without deviceId is legacy data: fall back to serialNo only when that serialNo appears once in devicesConfig.",
|
|
185
|
+
"hasDevices": "systemStatus.hasDevices is true only after the app loaded a non-empty list from the server; false means no device OR the lookup failed. A hint, never a verdict.",
|
|
186
|
+
"devicesConfig": {
|
|
187
|
+
"type": "DeviceConfigItem",
|
|
188
|
+
"role": "the list of linked devices to render",
|
|
189
|
+
"fields": { "deviceId": "int, unique", "serialNo": "int, may repeat across an ActLumus and a Plus", "deviceBodyPart": "'wrist' | 'necklace' | null", "modelId": "'actlumus' | 'actlumus_plus', absent = ActLumus (gen1)", "bleConnectionPeriod": "int, minutes", "autosync": "bool", "eraseDeviceMemory": "bool", "autoEraseDeviceMemory": "bool", "autoEraseDeviceMemoryThreshold": "int", "readSensorsMemory": "bool", "startDevice": "bool", "readFullMemory": "bool", "allowFirmwareUpdate": "bool" }
|
|
190
|
+
},
|
|
191
|
+
"devicesTelemetry": {
|
|
192
|
+
"type": "DeviceTelemetryItem",
|
|
193
|
+
"role": "last state read from each device over BLE; readings are null until the first sync",
|
|
194
|
+
"fields": { "serialNo": "int", "deviceId": "int, omitted on legacy data", "updataDateTime": "epoch ms | null — last sync; the misspelling is the real field name", "deviceName": "string | null", "deviceVersion": "string | null (firmware)", "hardwareVersion": "string | null", "deviceDateTime": "epoch ms | null", "memoryDataUsage": "number 0-100 (%) | null", "memorySystemUsage": "number 0-100 (%) | null", "batteryLevel": "number 0-100 (%) | null", "batteryVoltage": "number, volts | null", "isCharging": "bool | null", "isOnDock": "bool | null", "syncErrors": "Array<{ serialNo, attemptDate: epoch ms, message: localized string, messageCode: string | null }>" }
|
|
195
|
+
},
|
|
196
|
+
"devicesUserConfig": {
|
|
197
|
+
"type": "DeviceUserConfigItem",
|
|
198
|
+
"role": "per-device toggles",
|
|
199
|
+
"fields": { "serialNo": "int", "deviceId": "int, omitted on legacy data", "syncTime": "bool", "realTime": "bool", "deleteMemory": "bool", "readAllMemory": "bool", "readAllSystemLog": "bool" }
|
|
200
|
+
},
|
|
201
|
+
"sensorLogItem": {
|
|
202
|
+
"type": "SensorLogItem",
|
|
203
|
+
"fields": { "id": "int", "log_time": "'YYYY-MM-DD HH:MM:SS', device-LOCAL time, not UTC", "log_type": "int", "body_part": "'wrist' | 'necklace' | null", "temperature": "°C | null", "lux_photopic": "lux | null", "lux_melanopic": "lux | null", "light_sensor_f1..f8, light_sensor_clear, light_sensor_nir": "raw channels | null (null = the hardware has no such channel)", "act_data_pim, act_data_tat, act_data_zcm": "int | null", "device_log_time, app_log_time": "upload batch markers, not per-log timestamps" }
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
"devTools": {
|
|
208
|
+
"harness": "npx condor-mobile-bridge dev -i <index.html|dist|bundle.zip> [--scenario <name>] [--port 5173]",
|
|
209
|
+
"subpath": "@condorinst/mobile-bridge/dev exports createDevHarness() for a host page; never import it into the bundle (validate fails it with dev-harness-bundled)",
|
|
210
|
+
"scenarios": ["default", "cold-start", "no-devices", "shared-serial", "offline"],
|
|
211
|
+
"outsideShell": "BridgeClient.handshake() rejects at once when the page is not inside the shell (opened directly in a browser)."
|
|
212
|
+
},
|
|
213
|
+
|
|
179
214
|
"verifiedAgainst": {
|
|
180
215
|
"monorepo": "condorinstprogdev/mobile_applications",
|
|
181
216
|
"branch": "dev_canvas",
|
|
182
|
-
"commit": "
|
|
183
|
-
"verifiedOn": "2026-
|
|
217
|
+
"commit": "a1a524fd8491e4c266c7ea7bbcd9b1aa334620db",
|
|
218
|
+
"verifiedOn": "2026-10-20",
|
|
184
219
|
"sources": {
|
|
185
|
-
"nativeVersion": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:
|
|
186
|
-
"jsToNativePayloadBytes": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:
|
|
187
|
-
"jsErrorPerWindow": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:
|
|
188
|
-
"jsErrorFieldBytes": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:
|
|
189
|
-
"acceptedIsAlwaysTrue": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:
|
|
190
|
-
"silentDropPaths": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:
|
|
220
|
+
"nativeVersion": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:38",
|
|
221
|
+
"jsToNativePayloadBytes": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:94",
|
|
222
|
+
"jsErrorPerWindow": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:99-100",
|
|
223
|
+
"jsErrorFieldBytes": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:103",
|
|
224
|
+
"acceptedIsAlwaysTrue": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:486-494",
|
|
225
|
+
"silentDropPaths": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:246-266,319-323,521-536,606-613",
|
|
191
226
|
"bundleZipBytes": "apps/canvas/lib/core/config/whitelabel_bundle_limits.dart:14",
|
|
192
227
|
"bundleGuards": "apps/canvas/lib/data/services/whitelabel_bundle_service.dart:227-398",
|
|
193
228
|
"integrity": "apps/canvas/lib/data/services/whitelabel_bundle_service.dart:244-259",
|
|
194
229
|
"sensorLogValidation": "apps/canvas/lib/domain/entities/sensor_log_entity.dart:70-85",
|
|
195
230
|
"csp": "apps/canvas/web-mock-src/shell.template.html:28",
|
|
196
231
|
"shellPolicy": "apps/canvas/web-mock-src/src/shell.ts:48-98",
|
|
197
|
-
"webViewPermissionDeny": "apps/canvas/lib/ui/pages/home/home_page.dart:
|
|
198
|
-
"opaqueOrigin": "apps/canvas/lib/ui/pages/home/home_page.dart:
|
|
232
|
+
"webViewPermissionDeny": "apps/canvas/lib/ui/pages/home/home_page.dart:263-271",
|
|
233
|
+
"opaqueOrigin": "apps/canvas/lib/ui/pages/home/home_page.dart:299-301",
|
|
234
|
+
"userDeviceToBackgroundService": "apps/canvas/lib/ui/pages/home/bridge/condor_bridge.dart:671-683",
|
|
235
|
+
"userDeviceRepliesOnlyOnSuccess": "packages/condor_core/lib/src/data/services/user_devices_service.dart:28-39",
|
|
236
|
+
"getFromServerSemantics": "packages/condor_core/lib/src/data/repositories/user_devices_repository.dart:49-85",
|
|
237
|
+
"hasDevices": "apps/canvas/lib/data/services/sys_notification_service.dart:224-237",
|
|
238
|
+
"deviceConfigItem": "packages/condor_core/lib/src/domain/entities/device_config_entity.dart:61-77",
|
|
239
|
+
"deviceTelemetryItem": "packages/condor_core/lib/src/domain/entities/device_telemetry_entity.dart:100-117",
|
|
240
|
+
"deviceUserConfigItem": "packages/condor_core/lib/src/domain/entities/device_user_config_entity.dart:78-88",
|
|
241
|
+
"deviceSyncErrorItem": "packages/condor_core/lib/src/domain/entities/device_sync_error_entity.dart:16-23",
|
|
242
|
+
"userDevicesEnvelope": "packages/condor_core/lib/src/domain/entities/user_devices_entity.dart:282-289",
|
|
243
|
+
"bleConnectionPeriodMinutes": "packages/condor_core/lib/src/domain/entities/device_session_record_entity.dart:25"
|
|
199
244
|
},
|
|
200
245
|
"maintenance": "Re-verify every entry in sources before cutting a release. A published contract that drifts from the app is worse than no contract."
|
|
201
246
|
}
|