@neurosity/sdk 6.5.9 → 6.5.11

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.
Files changed (130) hide show
  1. package/dist/browser/neurosity.iife.js +2419 -1009
  2. package/dist/browser/neurosity.js +180 -148
  3. package/dist/browser/neurosity.js.map +1 -1
  4. package/dist/cjs/__tests__/Neurosity.test.d.ts +1 -0
  5. package/dist/cjs/__tests__/Neurosity.test.js +201 -0
  6. package/dist/cjs/__tests__/WebBluetoothTransport.test.d.ts +1 -0
  7. package/dist/cjs/__tests__/WebBluetoothTransport.test.js +201 -0
  8. package/dist/cjs/__tests__/accelerometer.test.d.ts +1 -0
  9. package/dist/cjs/__tests__/accelerometer.test.js +158 -0
  10. package/dist/cjs/__tests__/auth.test.d.ts +1 -0
  11. package/dist/cjs/__tests__/auth.test.js +239 -0
  12. package/dist/cjs/__tests__/brainwaves.test.d.ts +1 -0
  13. package/dist/cjs/__tests__/brainwaves.test.js +291 -0
  14. package/dist/cjs/__tests__/device.test.d.ts +1 -0
  15. package/dist/cjs/__tests__/device.test.js +281 -0
  16. package/dist/cjs/__tests__/haptics.test.d.ts +1 -0
  17. package/dist/cjs/__tests__/haptics.test.js +162 -0
  18. package/dist/cjs/__tests__/metrics.test.d.ts +1 -0
  19. package/dist/cjs/__tests__/metrics.test.js +178 -0
  20. package/dist/cjs/__tests__/oauth.test.d.ts +1 -0
  21. package/dist/cjs/__tests__/oauth.test.js +138 -0
  22. package/dist/cjs/__tests__/settings.test.d.ts +1 -0
  23. package/dist/cjs/__tests__/settings.test.js +130 -0
  24. package/dist/cjs/__tests__/setup/webBluetooth.setup.d.ts +11 -0
  25. package/dist/cjs/__tests__/setup/webBluetooth.setup.js +35 -0
  26. package/dist/cjs/__tests__/setup.d.ts +0 -0
  27. package/dist/cjs/__tests__/setup.js +7 -0
  28. package/dist/cjs/__tests__/streaming.test.d.ts +1 -0
  29. package/dist/cjs/__tests__/streaming.test.js +259 -0
  30. package/dist/cjs/__tests__/timesync.test.d.ts +1 -0
  31. package/dist/cjs/__tests__/timesync.test.js +54 -0
  32. package/dist/cjs/__tests__/utils.test.d.ts +1 -0
  33. package/dist/cjs/__tests__/utils.test.js +281 -0
  34. package/dist/cjs/api/bluetooth/BluetoothClient.d.ts +6 -6
  35. package/dist/cjs/api/bluetooth/BluetoothTransport.d.ts +1 -1
  36. package/dist/cjs/api/bluetooth/react-native/ReactNativeTransport.d.ts +4 -4
  37. package/dist/cjs/api/bluetooth/react-native/types/ReactNativeTypes.d.ts +2 -2
  38. package/dist/cjs/api/bluetooth/types/index.d.ts +2 -2
  39. package/dist/cjs/api/bluetooth/utils/decodeJSONChunks.d.ts +1 -1
  40. package/dist/cjs/api/bluetooth/utils/stitch.d.ts +1 -1
  41. package/dist/cjs/api/bluetooth/utils/textCodec.d.ts +1 -1
  42. package/dist/cjs/api/bluetooth/web/WebBluetoothTransport.d.ts +1 -1
  43. package/dist/cjs/api/firebase/FirebaseDevice.d.ts +1 -1
  44. package/dist/cjs/api/firebase/FirebaseUser.d.ts +1 -1
  45. package/dist/cjs/api/index.js +1 -1
  46. package/dist/cjs/timesync/Timesync.d.ts +1 -1
  47. package/dist/cjs/types/awareness.d.ts +1 -1
  48. package/dist/cjs/types/brainwaves.d.ts +25 -12
  49. package/dist/cjs/types/credentials.d.ts +4 -4
  50. package/dist/cjs/types/deviceInfo.d.ts +4 -4
  51. package/dist/cjs/types/epoch.d.ts +1 -1
  52. package/dist/cjs/types/experiment.d.ts +1 -1
  53. package/dist/cjs/types/hapticEffects.d.ts +1 -1
  54. package/dist/cjs/types/marker.d.ts +1 -1
  55. package/dist/cjs/types/metrics.d.ts +2 -2
  56. package/dist/cjs/types/oauth.d.ts +4 -4
  57. package/dist/cjs/types/sample.d.ts +2 -2
  58. package/dist/cjs/types/signalQuality.d.ts +1 -1
  59. package/dist/cjs/types/skill.d.ts +2 -2
  60. package/dist/cjs/types/user.d.ts +3 -3
  61. package/dist/cjs/utils/oauth.d.ts +1 -1
  62. package/dist/cjs/utils/transferDevice.d.ts +3 -3
  63. package/dist/cjs/utils/whileOnline.d.ts +1 -1
  64. package/dist/electron/index.js +1 -1
  65. package/dist/electron/index.js.map +1 -1
  66. package/dist/esm/__tests__/Neurosity.test.d.ts +1 -0
  67. package/dist/esm/__tests__/Neurosity.test.js +199 -0
  68. package/dist/esm/__tests__/WebBluetoothTransport.test.d.ts +1 -0
  69. package/dist/esm/__tests__/WebBluetoothTransport.test.js +199 -0
  70. package/dist/esm/__tests__/accelerometer.test.d.ts +1 -0
  71. package/dist/esm/__tests__/accelerometer.test.js +156 -0
  72. package/dist/esm/__tests__/auth.test.d.ts +1 -0
  73. package/dist/esm/__tests__/auth.test.js +237 -0
  74. package/dist/esm/__tests__/brainwaves.test.d.ts +1 -0
  75. package/dist/esm/__tests__/brainwaves.test.js +289 -0
  76. package/dist/esm/__tests__/device.test.d.ts +1 -0
  77. package/dist/esm/__tests__/device.test.js +279 -0
  78. package/dist/esm/__tests__/haptics.test.d.ts +1 -0
  79. package/dist/esm/__tests__/haptics.test.js +160 -0
  80. package/dist/esm/__tests__/metrics.test.d.ts +1 -0
  81. package/dist/esm/__tests__/metrics.test.js +176 -0
  82. package/dist/esm/__tests__/oauth.test.d.ts +1 -0
  83. package/dist/esm/__tests__/oauth.test.js +133 -0
  84. package/dist/esm/__tests__/settings.test.d.ts +1 -0
  85. package/dist/esm/__tests__/settings.test.js +128 -0
  86. package/dist/esm/__tests__/setup/webBluetooth.setup.d.ts +11 -0
  87. package/dist/esm/__tests__/setup/webBluetooth.setup.js +35 -0
  88. package/dist/esm/__tests__/setup.d.ts +0 -0
  89. package/dist/esm/__tests__/setup.js +7 -0
  90. package/dist/esm/__tests__/streaming.test.d.ts +1 -0
  91. package/dist/esm/__tests__/streaming.test.js +257 -0
  92. package/dist/esm/__tests__/timesync.test.d.ts +1 -0
  93. package/dist/esm/__tests__/timesync.test.js +52 -0
  94. package/dist/esm/__tests__/utils.test.d.ts +1 -0
  95. package/dist/esm/__tests__/utils.test.js +279 -0
  96. package/dist/esm/api/bluetooth/BluetoothClient.d.ts +6 -6
  97. package/dist/esm/api/bluetooth/BluetoothTransport.d.ts +1 -1
  98. package/dist/esm/api/bluetooth/react-native/ReactNativeTransport.d.ts +4 -4
  99. package/dist/esm/api/bluetooth/react-native/types/ReactNativeTypes.d.ts +2 -2
  100. package/dist/esm/api/bluetooth/types/index.d.ts +2 -2
  101. package/dist/esm/api/bluetooth/utils/decodeJSONChunks.d.ts +1 -1
  102. package/dist/esm/api/bluetooth/utils/stitch.d.ts +1 -1
  103. package/dist/esm/api/bluetooth/utils/textCodec.d.ts +1 -1
  104. package/dist/esm/api/bluetooth/web/WebBluetoothTransport.d.ts +1 -1
  105. package/dist/esm/api/firebase/FirebaseDevice.d.ts +1 -1
  106. package/dist/esm/api/firebase/FirebaseUser.d.ts +1 -1
  107. package/dist/esm/api/index.js +2 -2
  108. package/dist/esm/neurosity.mjs +2480 -1007
  109. package/dist/esm/timesync/Timesync.d.ts +1 -1
  110. package/dist/esm/types/awareness.d.ts +1 -1
  111. package/dist/esm/types/brainwaves.d.ts +25 -12
  112. package/dist/esm/types/credentials.d.ts +4 -4
  113. package/dist/esm/types/deviceInfo.d.ts +4 -4
  114. package/dist/esm/types/epoch.d.ts +1 -1
  115. package/dist/esm/types/experiment.d.ts +1 -1
  116. package/dist/esm/types/hapticEffects.d.ts +1 -1
  117. package/dist/esm/types/marker.d.ts +1 -1
  118. package/dist/esm/types/metrics.d.ts +2 -2
  119. package/dist/esm/types/oauth.d.ts +4 -4
  120. package/dist/esm/types/sample.d.ts +2 -2
  121. package/dist/esm/types/signalQuality.d.ts +1 -1
  122. package/dist/esm/types/skill.d.ts +2 -2
  123. package/dist/esm/types/user.d.ts +3 -3
  124. package/dist/esm/utils/oauth.d.ts +1 -1
  125. package/dist/esm/utils/transferDevice.d.ts +3 -3
  126. package/dist/esm/utils/whileOnline.d.ts +1 -1
  127. package/dist/examples/neurosity.iife.js +2419 -1009
  128. package/dist/examples/neurosity.js +180 -148
  129. package/dist/examples/neurosity.mjs +2480 -1007
  130. package/package.json +17 -5
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ var __importDefault = (this && this.__importDefault) || function (mod) {
23
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const createOAuthURL_1 = require("../api/https/createOAuthURL");
27
+ const getOAuthToken_1 = require("../api/https/getOAuthToken");
28
+ const axios_1 = __importDefault(require("axios"));
29
+ // Mock axios
30
+ jest.mock("axios", () => ({
31
+ get: jest.fn().mockImplementation((url, config) => {
32
+ var _a;
33
+ if (!((_a = config === null || config === void 0 ? void 0 : config.params) === null || _a === void 0 ? void 0 : _a.client_id)) {
34
+ return Promise.reject(new Error("Missing required parameter: clientId"));
35
+ }
36
+ return Promise.resolve({
37
+ data: {
38
+ url: `/oauth/createOAuthURL?client_id=${config.params.client_id}&redirect_uri=${encodeURIComponent(config.params.redirect_uri)}&response_type=${config.params.response_type}&state=${config.params.state}&scope=${encodeURIComponent(config.params.scope)}`
39
+ }
40
+ });
41
+ }),
42
+ post: jest.fn().mockImplementation((url, data) => {
43
+ if (!data.clientId || !data.clientSecret || !data.userId) {
44
+ return Promise.reject(new Error("Missing OAuth credentials"));
45
+ }
46
+ if (data.clientId === "expired") {
47
+ return Promise.reject(new Error("Token expired"));
48
+ }
49
+ return Promise.resolve({
50
+ data: {
51
+ userId: "test-user-id",
52
+ accessToken: "test-access-token",
53
+ refreshToken: "test-refresh-token",
54
+ expiresIn: 3600
55
+ }
56
+ });
57
+ })
58
+ }));
59
+ // Mock getOAuthToken
60
+ jest.mock("../api/https/getOAuthToken", () => {
61
+ return {
62
+ __esModule: true,
63
+ getOAuthToken: jest
64
+ .fn()
65
+ .mockImplementation((query, options) => __awaiter(void 0, void 0, void 0, function* () {
66
+ try {
67
+ const baseURL = options.emulator
68
+ ? `http://${options.emulatorHost}:${options.emulatorFunctionsPort}/neurosity-device/us-central1`
69
+ : "https://us-central1-neurosity-device.cloudfunctions.net";
70
+ const response = yield axios_1.default.post(baseURL, query);
71
+ return response.data;
72
+ }
73
+ catch (error) {
74
+ throw error;
75
+ }
76
+ }))
77
+ };
78
+ });
79
+ describe("OAuth and Token Management", () => {
80
+ const options = {
81
+ emulator: true,
82
+ emulatorHost: "localhost",
83
+ emulatorFunctionsPort: 5001
84
+ };
85
+ describe("OAuth URL Creation", () => {
86
+ const config = {
87
+ clientId: "test-client-id",
88
+ redirectUri: "http://localhost:3000/callback",
89
+ responseType: "token",
90
+ state: "random-state",
91
+ scope: ["read:devices-info", "read:brainwaves"]
92
+ };
93
+ it("should create OAuth URL with valid credentials", () => __awaiter(void 0, void 0, void 0, function* () {
94
+ const url = yield (0, createOAuthURL_1.createOAuthURL)(config, options);
95
+ expect(url).toContain(`client_id=${config.clientId}`);
96
+ expect(url).toContain(`redirect_uri=${encodeURIComponent(config.redirectUri)}`);
97
+ expect(url).toContain(`response_type=${config.responseType}`);
98
+ expect(url).toContain(`state=${config.state}`);
99
+ expect(url).toContain(`scope=${encodeURIComponent(config.scope.join(","))}`);
100
+ }));
101
+ it("should reject OAuth URL creation with missing credentials", () => __awaiter(void 0, void 0, void 0, function* () {
102
+ const { clientId } = config, invalidConfig = __rest(config, ["clientId"]);
103
+ yield expect((0, createOAuthURL_1.createOAuthURL)(invalidConfig, options)).rejects.toThrow("Missing required parameter: clientId");
104
+ }));
105
+ });
106
+ describe("OAuth Token Management", () => {
107
+ it("should get OAuth token with valid credentials", () => __awaiter(void 0, void 0, void 0, function* () {
108
+ const query = {
109
+ clientId: "test-client-id",
110
+ clientSecret: "test-client-secret",
111
+ userId: "test-user-id"
112
+ };
113
+ const token = yield (0, getOAuthToken_1.getOAuthToken)(query, options);
114
+ expect(token).toEqual({
115
+ userId: "test-user-id",
116
+ accessToken: "test-access-token",
117
+ refreshToken: "test-refresh-token",
118
+ expiresIn: 3600
119
+ });
120
+ }));
121
+ it("should handle expired token", () => __awaiter(void 0, void 0, void 0, function* () {
122
+ const query = {
123
+ clientId: "expired",
124
+ clientSecret: "test-client-secret",
125
+ userId: "test-user-id"
126
+ };
127
+ yield expect((0, getOAuthToken_1.getOAuthToken)(query, options)).rejects.toThrow("Token expired");
128
+ }));
129
+ it("should handle missing credentials", () => __awaiter(void 0, void 0, void 0, function* () {
130
+ const query = {
131
+ clientId: "test-client-id",
132
+ clientSecret: "",
133
+ userId: ""
134
+ };
135
+ yield expect((0, getOAuthToken_1.getOAuthToken)(query, options)).rejects.toThrow("Missing OAuth credentials");
136
+ }));
137
+ });
138
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const rxjs_1 = require("rxjs");
13
+ const operators_1 = require("rxjs/operators");
14
+ const Neurosity_1 = require("../Neurosity");
15
+ // Mock CloudClient
16
+ jest.mock("../api/index", () => {
17
+ const mockSettings = new rxjs_1.BehaviorSubject({
18
+ lsl: false,
19
+ supportAccess: false,
20
+ activityLogging: false
21
+ });
22
+ const mockCloudClient = {
23
+ login: jest.fn(),
24
+ logout: jest.fn(),
25
+ onAuthStateChanged: jest.fn(),
26
+ onDeviceChange: jest.fn(),
27
+ status: jest.fn(),
28
+ didSelectDevice: jest.fn().mockResolvedValue(true),
29
+ observeNamespace: jest.fn((namespace) => {
30
+ if (namespace === "settings") {
31
+ return mockSettings;
32
+ }
33
+ return (0, rxjs_1.of)(null);
34
+ }),
35
+ changeSettings: jest.fn((settings) => __awaiter(void 0, void 0, void 0, function* () {
36
+ // Validate settings
37
+ const validKeys = ["lsl", "bluetooth", "timesync", "deviceNickname"];
38
+ const hasInvalidKey = Object.keys(settings).some((key) => !validKeys.includes(key));
39
+ if (hasInvalidKey) {
40
+ throw new Error("Invalid settings");
41
+ }
42
+ mockSettings.next(Object.assign(Object.assign({}, mockSettings.value), settings));
43
+ return Promise.resolve();
44
+ })),
45
+ userClaims: {
46
+ scopes: ["settings"]
47
+ }
48
+ };
49
+ return {
50
+ CloudClient: jest.fn().mockImplementation(() => mockCloudClient)
51
+ };
52
+ });
53
+ const testDeviceId = "mock-device-id";
54
+ describe("Settings", () => {
55
+ let neurosity;
56
+ let cloudClient;
57
+ beforeEach(() => {
58
+ neurosity = new Neurosity_1.Neurosity({
59
+ deviceId: testDeviceId
60
+ });
61
+ cloudClient = neurosity.cloudClient;
62
+ });
63
+ describe("Settings Management", () => {
64
+ it("should get current settings", (done) => {
65
+ neurosity
66
+ .settings()
67
+ .pipe((0, operators_1.take)(1))
68
+ .subscribe({
69
+ next: (settings) => {
70
+ expect(settings).toBeDefined();
71
+ expect(settings.lsl).toBe(false);
72
+ expect(settings.supportAccess).toBe(false);
73
+ expect(settings.activityLogging).toBe(false);
74
+ done();
75
+ },
76
+ error: done
77
+ });
78
+ });
79
+ it("should update settings", (done) => {
80
+ const newSettings = {
81
+ lsl: true,
82
+ bluetooth: true,
83
+ timesync: true
84
+ };
85
+ neurosity
86
+ .changeSettings(newSettings)
87
+ .then(() => {
88
+ neurosity
89
+ .settings()
90
+ .pipe((0, operators_1.take)(1))
91
+ .subscribe({
92
+ next: (settings) => {
93
+ expect(settings.lsl).toBe(true);
94
+ expect(settings.supportAccess).toBe(true);
95
+ expect(settings.activityLogging).toBe(true);
96
+ done();
97
+ },
98
+ error: done
99
+ });
100
+ })
101
+ .catch(done);
102
+ });
103
+ it("should update device nickname", (done) => {
104
+ neurosity
105
+ .changeSettings({ supportAccess: true })
106
+ .then(() => {
107
+ neurosity
108
+ .settings()
109
+ .pipe((0, operators_1.take)(1))
110
+ .subscribe({
111
+ next: (settings) => {
112
+ expect(settings.supportAccess).toBe(true);
113
+ done();
114
+ },
115
+ error: done
116
+ });
117
+ })
118
+ .catch(done);
119
+ });
120
+ });
121
+ describe("Error Handling", () => {
122
+ it("should handle invalid settings changes", () => __awaiter(void 0, void 0, void 0, function* () {
123
+ const invalidChanges = {
124
+ invalidSetting: true
125
+ };
126
+ // @ts-ignore - Testing invalid settings
127
+ yield expect(neurosity.changeSettings(invalidChanges)).rejects.toThrow("Invalid settings");
128
+ }));
129
+ });
130
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Setup file for Web Bluetooth tests
3
+ * This configures a minimal browser-like environment for testing Web Bluetooth functionality
4
+ */
5
+ /// <reference types="jest" />
6
+ declare const mockBluetooth: {
7
+ getDevices: jest.Mock<any, any, any>;
8
+ requestDevice: jest.Mock<any, any, any>;
9
+ };
10
+ declare const mockNavigator: Navigator;
11
+ declare const mockWindow: Window & typeof globalThis;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Setup file for Web Bluetooth tests
3
+ * This configures a minimal browser-like environment for testing Web Bluetooth functionality
4
+ */
5
+ // Mock window and navigator.bluetooth
6
+ const mockBluetooth = {
7
+ getDevices: jest.fn(),
8
+ requestDevice: jest.fn()
9
+ };
10
+ const mockNavigator = {
11
+ bluetooth: mockBluetooth
12
+ };
13
+ const mockWindow = {
14
+ navigator: mockNavigator
15
+ };
16
+ // Set up global object for Node environment
17
+ global.window = mockWindow;
18
+ global.navigator = mockWindow.navigator;
19
+ // Mock isWebBluetoothSupported
20
+ jest.mock("../../api/bluetooth/web/isWebBluetoothSupported", () => ({
21
+ isWebBluetoothSupported: jest.fn().mockReturnValue(true)
22
+ }));
23
+ // Mock IPK constants
24
+ jest.mock("@neurosity/ipk", () => ({
25
+ BLUETOOTH_PRIMARY_SERVICE_UUID_HEX: "test-service-uuid",
26
+ BLUETOOTH_COMPANY_IDENTIFIER_HEX: 0x1234,
27
+ BLUETOOTH_DEVICE_NAME_PREFIXES: ["Crown"],
28
+ BLUETOOTH_CHUNK_DELIMITER: "\n",
29
+ BLUETOOTH_CHARACTERISTICS: {
30
+ ACTION: "test-action-uuid",
31
+ ACTION_STATUS: "test-action-status-uuid",
32
+ COMMAND: "test-command-uuid",
33
+ STATE: "test-state-uuid"
34
+ }
35
+ }));
File without changes
@@ -0,0 +1,7 @@
1
+ /// <reference types="jest" />
2
+ // Increase the default timeout for async operations
3
+ jest.setTimeout(10000);
4
+ // Add custom matchers if needed
5
+ expect.extend({
6
+ // Add custom matchers here if needed in the future
7
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,259 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const Neurosity_1 = require("../Neurosity");
13
+ const rxjs_1 = require("rxjs");
14
+ const status_1 = require("../types/status");
15
+ // Mock Firebase modules
16
+ jest.mock("../api/firebase", () => ({
17
+ FirebaseApp: jest.fn().mockImplementation(() => ({
18
+ disconnect: jest.fn(),
19
+ useEmulator: jest.fn()
20
+ })),
21
+ FirebaseUser: jest.fn().mockImplementation(() => ({
22
+ login: jest.fn(),
23
+ logout: jest.fn(),
24
+ onAuthStateChanged: jest.fn().mockReturnValue((0, rxjs_1.of)(null)),
25
+ onUserClaimsChange: jest.fn().mockReturnValue((0, rxjs_1.of)({}))
26
+ })),
27
+ FirebaseDevice: jest.fn().mockImplementation(() => ({
28
+ disconnect: jest.fn(),
29
+ getInfo: jest.fn(),
30
+ dispatchAction: jest.fn()
31
+ }))
32
+ }));
33
+ describe("Data Streaming", () => {
34
+ let neurosity;
35
+ const testDeviceId = "test-device-id";
36
+ const options = {
37
+ deviceId: testDeviceId,
38
+ emulator: true,
39
+ skill: {
40
+ id: "test-skill-id",
41
+ bundleId: "test-bundle-id",
42
+ spec: "1.0.0",
43
+ name: "Test Skill",
44
+ description: "A test skill",
45
+ metrics: ["brainwaves"],
46
+ userId: "test-user-id",
47
+ timestamp: Date.now(),
48
+ status: "active",
49
+ thumbnail: "test-thumbnail"
50
+ }
51
+ };
52
+ beforeEach(() => {
53
+ neurosity = new Neurosity_1.Neurosity(options);
54
+ // Mock cloudClient with userClaims for OAuth scope validation
55
+ // and required methods
56
+ neurosity["cloudClient"] = {
57
+ userClaims: {
58
+ scopes: ["brainwaves"]
59
+ },
60
+ onDeviceChange: jest.fn().mockReturnValue((0, rxjs_1.of)({
61
+ deviceId: testDeviceId,
62
+ status: status_1.STATUS.ONLINE
63
+ })),
64
+ osVersion: jest.fn().mockReturnValue((0, rxjs_1.of)("1.0.0")),
65
+ status: jest.fn().mockReturnValue((0, rxjs_1.of)({ state: status_1.STATUS.ONLINE })),
66
+ metrics: {
67
+ subscribe: jest.fn().mockReturnValue((0, rxjs_1.of)({})),
68
+ on: jest.fn().mockImplementation((subscription, callback) => {
69
+ // Simulate metric data
70
+ callback({});
71
+ return jest.fn();
72
+ }),
73
+ unsubscribe: jest.fn()
74
+ },
75
+ subscriptionManager: {
76
+ add: jest.fn(),
77
+ remove: jest.fn(),
78
+ removeAll: jest.fn()
79
+ }
80
+ };
81
+ // Mock _osHasBluetoothSupport to return false to avoid Bluetooth-related code paths
82
+ neurosity["_osHasBluetoothSupport"] = jest.fn().mockReturnValue((0, rxjs_1.of)(false));
83
+ });
84
+ afterEach(() => __awaiter(void 0, void 0, void 0, function* () {
85
+ try {
86
+ yield neurosity.logout();
87
+ }
88
+ catch (error) {
89
+ // Ignore logout errors in cleanup
90
+ }
91
+ }));
92
+ describe("Brainwaves", () => {
93
+ it("should stream raw brainwaves data", () => __awaiter(void 0, void 0, void 0, function* () {
94
+ const mockRawData = {
95
+ data: [
96
+ [1, 2, 3, 4, 5, 6, 7, 8],
97
+ [9, 10, 11, 12, 13, 14, 15, 16]
98
+ ],
99
+ info: {
100
+ samplingRate: 256,
101
+ startTime: Date.now(),
102
+ channelNames: ["test-channel-1", "test-channel-2"]
103
+ }
104
+ };
105
+ // Mock the getCloudMetric function to return our mock data
106
+ neurosity["_getCloudMetricDependencies"] = jest.fn().mockReturnValue({
107
+ options,
108
+ cloudClient: neurosity["cloudClient"],
109
+ onDeviceChange: neurosity["cloudClient"].onDeviceChange,
110
+ status: neurosity["cloudClient"].status,
111
+ getCloudMetric: jest.fn().mockReturnValue((0, rxjs_1.of)(mockRawData))
112
+ });
113
+ const brainwaves = yield (0, rxjs_1.firstValueFrom)(neurosity.brainwaves("raw").pipe((0, rxjs_1.take)(1)));
114
+ expect(brainwaves).toBeDefined();
115
+ if ("data" in brainwaves) {
116
+ expect(Array.isArray(brainwaves.data)).toBe(true);
117
+ expect(brainwaves.data.length).toBe(2);
118
+ expect(brainwaves.data[0].length).toBe(8);
119
+ expect(brainwaves.info.samplingRate).toBe(256);
120
+ }
121
+ }));
122
+ it("should stream power by band data", () => __awaiter(void 0, void 0, void 0, function* () {
123
+ const mockPowerByBand = {
124
+ gamma: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],
125
+ beta: [0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9],
126
+ alpha: [0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],
127
+ theta: [0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1],
128
+ delta: [0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2],
129
+ info: {
130
+ samplingRate: 256,
131
+ startTime: Date.now(),
132
+ channelNames: ["test-channel-1", "test-channel-2"]
133
+ }
134
+ };
135
+ // Mock the getCloudMetric function to return our mock data
136
+ neurosity["_getCloudMetricDependencies"] = jest.fn().mockReturnValue({
137
+ options,
138
+ cloudClient: neurosity["cloudClient"],
139
+ onDeviceChange: neurosity["cloudClient"].onDeviceChange,
140
+ status: neurosity["cloudClient"].status,
141
+ getCloudMetric: jest.fn().mockReturnValue((0, rxjs_1.of)(mockPowerByBand))
142
+ });
143
+ const powerByBand = yield (0, rxjs_1.firstValueFrom)(neurosity.brainwaves("powerByBand").pipe((0, rxjs_1.take)(1)));
144
+ expect(powerByBand).toBeDefined();
145
+ if ("gamma" in powerByBand) {
146
+ expect(powerByBand.gamma).toBeDefined();
147
+ expect(powerByBand.beta).toBeDefined();
148
+ expect(powerByBand.alpha).toBeDefined();
149
+ expect(powerByBand.theta).toBeDefined();
150
+ expect(powerByBand.delta).toBeDefined();
151
+ expect(powerByBand.gamma.length).toBe(8);
152
+ }
153
+ }));
154
+ it("should stream PSD data", () => __awaiter(void 0, void 0, void 0, function* () {
155
+ const mockPSD = {
156
+ label: "psd",
157
+ psd: [
158
+ [1, 2, 3, 4],
159
+ [5, 6, 7, 8]
160
+ ],
161
+ freqs: [0, 2, 4, 6],
162
+ info: {
163
+ samplingRate: 256,
164
+ startTime: Date.now(),
165
+ notchFrequency: "50",
166
+ channelNames: ["test-channel-1", "test-channel-2"]
167
+ }
168
+ };
169
+ // Mock the getCloudMetric function to return our mock data
170
+ neurosity["_getCloudMetricDependencies"] = jest.fn().mockReturnValue({
171
+ options,
172
+ cloudClient: neurosity["cloudClient"],
173
+ onDeviceChange: neurosity["cloudClient"].onDeviceChange,
174
+ status: neurosity["cloudClient"].status,
175
+ getCloudMetric: jest.fn().mockReturnValue((0, rxjs_1.of)(mockPSD))
176
+ });
177
+ const psd = yield (0, rxjs_1.firstValueFrom)(neurosity.brainwaves("psd").pipe((0, rxjs_1.take)(1)));
178
+ expect(psd).toBeDefined();
179
+ if ("psd" in psd) {
180
+ expect(Array.isArray(psd.psd)).toBe(true);
181
+ expect(Array.isArray(psd.freqs)).toBe(true);
182
+ expect(psd.info.samplingRate).toBe(256);
183
+ }
184
+ }));
185
+ it("should throw error when OAuth scope is missing", () => __awaiter(void 0, void 0, void 0, function* () {
186
+ // Remove brainwaves scope
187
+ neurosity["cloudClient"].userClaims.scopes = [];
188
+ // Mock the getCloudMetric function to throw an error
189
+ neurosity["_getCloudMetricDependencies"] = jest.fn().mockReturnValue({
190
+ options,
191
+ cloudClient: neurosity["cloudClient"],
192
+ onDeviceChange: neurosity["cloudClient"].onDeviceChange,
193
+ status: neurosity["cloudClient"].status,
194
+ getCloudMetric: jest.fn().mockImplementation(() => {
195
+ throw new Error("Neurosity SDK: No permission to access the brainwaves metric. To access this metric, edit the skill's permissions");
196
+ })
197
+ });
198
+ // Mock the metrics subscription to throw an error
199
+ neurosity["cloudClient"].metrics.subscribe = jest
200
+ .fn()
201
+ .mockImplementation(() => {
202
+ throw new Error("Neurosity SDK: No permission to access the brainwaves metric. To access this metric, edit the skill's permissions");
203
+ });
204
+ yield expect((0, rxjs_1.firstValueFrom)(neurosity.brainwaves("raw").pipe((0, rxjs_1.take)(1)))).rejects.toThrow("Neurosity SDK: No permission to access the brainwaves metric. To access this metric, edit the skill's permissions");
205
+ }));
206
+ });
207
+ describe("Metrics", () => {
208
+ // TODO: Issue #XYZ - Metric streaming tests need to be implemented
209
+ // These tests require proper mocking of the metric data streams
210
+ it.skip("should stream focus data", () => __awaiter(void 0, void 0, void 0, function* () {
211
+ const focus = yield (0, rxjs_1.firstValueFrom)(neurosity.focus().pipe((0, rxjs_1.take)(1)));
212
+ expect(focus).toBeDefined();
213
+ expect(typeof focus.probability).toBe("number");
214
+ expect(focus.probability).toBeGreaterThanOrEqual(0);
215
+ expect(focus.probability).toBeLessThanOrEqual(1);
216
+ }));
217
+ it.skip("should stream calm data", () => __awaiter(void 0, void 0, void 0, function* () {
218
+ const calm = yield (0, rxjs_1.firstValueFrom)(neurosity.calm().pipe((0, rxjs_1.take)(1)));
219
+ expect(calm).toBeDefined();
220
+ expect(typeof calm.probability).toBe("number");
221
+ expect(calm.probability).toBeGreaterThanOrEqual(0);
222
+ expect(calm.probability).toBeLessThanOrEqual(1);
223
+ }));
224
+ it.skip("should stream kinesis data", () => __awaiter(void 0, void 0, void 0, function* () {
225
+ const kinesis = yield (0, rxjs_1.firstValueFrom)(neurosity.kinesis("someAction").pipe((0, rxjs_1.take)(1)));
226
+ expect(kinesis).toBeDefined();
227
+ expect(typeof kinesis.probability).toBe("number");
228
+ expect(kinesis.probability).toBeGreaterThanOrEqual(0);
229
+ expect(kinesis.probability).toBeLessThanOrEqual(1);
230
+ }));
231
+ });
232
+ describe("Accelerometer", () => {
233
+ // TODO: Issue #XYZ - Accelerometer streaming tests need to be implemented
234
+ // These tests require proper mocking of the accelerometer data
235
+ it.skip("should stream accelerometer data", () => __awaiter(void 0, void 0, void 0, function* () {
236
+ const accelerometer = yield (0, rxjs_1.firstValueFrom)(neurosity.accelerometer().pipe((0, rxjs_1.take)(1)));
237
+ expect(accelerometer).toBeDefined();
238
+ expect(accelerometer.x).toBeDefined();
239
+ expect(accelerometer.y).toBeDefined();
240
+ expect(accelerometer.z).toBeDefined();
241
+ }));
242
+ });
243
+ describe("Error Handling", () => {
244
+ // TODO: Issue #XYZ - Error handling tests need to be implemented
245
+ // These tests require proper error simulation and handling
246
+ it.skip("should handle subscription errors gracefully", () => __awaiter(void 0, void 0, void 0, function* () {
247
+ // Mock a subscription error
248
+ const errorSubscription = neurosity.brainwaves("raw").pipe((0, rxjs_1.take)(1));
249
+ yield expect((0, rxjs_1.firstValueFrom)(errorSubscription)).rejects.toThrow();
250
+ }));
251
+ it.skip("should handle rate limiting", () => __awaiter(void 0, void 0, void 0, function* () {
252
+ // Test rapid subscription creation and cleanup
253
+ const subscriptions = Array(10)
254
+ .fill(null)
255
+ .map(() => neurosity.brainwaves("raw").pipe((0, rxjs_1.take)(1)));
256
+ yield expect(Promise.all(subscriptions.map((sub) => (0, rxjs_1.firstValueFrom)(sub)))).rejects.toThrow();
257
+ }));
258
+ });
259
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const Neurosity_1 = require("../Neurosity");
4
+ // Mock CloudClient
5
+ jest.mock("../api", () => {
6
+ const originalModule = jest.requireActual("../api");
7
+ class MockCloudClient {
8
+ constructor(options) {
9
+ this.user = null;
10
+ this.userClaims = { scopes: ["brainwaves"] };
11
+ this.getTimesyncOffset = jest.fn().mockImplementation(() => {
12
+ return 150; // Mock 150ms offset
13
+ });
14
+ this.options = options;
15
+ }
16
+ }
17
+ return Object.assign(Object.assign({}, originalModule), { CloudClient: jest
18
+ .fn()
19
+ .mockImplementation((options) => new MockCloudClient(options)) });
20
+ });
21
+ describe("Timesync", () => {
22
+ let neurosity;
23
+ const testDeviceId = "test-device-id";
24
+ describe("with timesync enabled", () => {
25
+ beforeEach(() => {
26
+ neurosity = new Neurosity_1.Neurosity({
27
+ deviceId: testDeviceId,
28
+ emulator: true,
29
+ timesync: true
30
+ });
31
+ });
32
+ it("should get timesync offset", () => {
33
+ const offset = neurosity.getTimesyncOffset();
34
+ expect(offset).toBeDefined();
35
+ expect(typeof offset).toBe("number");
36
+ expect(offset).toBe(150);
37
+ });
38
+ });
39
+ describe("with timesync disabled", () => {
40
+ beforeEach(() => {
41
+ neurosity = new Neurosity_1.Neurosity({
42
+ deviceId: testDeviceId,
43
+ emulator: true,
44
+ timesync: false
45
+ });
46
+ });
47
+ it("should return 0 when timesync is disabled", () => {
48
+ const offset = neurosity.getTimesyncOffset();
49
+ expect(offset).toBeDefined();
50
+ expect(typeof offset).toBe("number");
51
+ expect(offset).toBe(0);
52
+ });
53
+ });
54
+ });
@@ -0,0 +1 @@
1
+ export {};