syzygy-services-rn 1.0.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/.github/workflows/ci.yml +42 -0
- package/.github/workflows/release.yml +30 -0
- package/CHANGELOG.md +23 -0
- package/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/__tests__/analytics/AnalyticsProvider.test.d.ts +2 -0
- package/dist/__tests__/analytics/AnalyticsProvider.test.d.ts.map +1 -0
- package/dist/__tests__/analytics/AnalyticsProvider.test.js +85 -0
- package/dist/__tests__/analytics/AnalyticsProvider.test.js.map +1 -0
- package/dist/__tests__/auth/AuthProvider.test.d.ts +2 -0
- package/dist/__tests__/auth/AuthProvider.test.d.ts.map +1 -0
- package/dist/__tests__/auth/AuthProvider.test.js +147 -0
- package/dist/__tests__/auth/AuthProvider.test.js.map +1 -0
- package/dist/__tests__/crashreporting/CrashReporter.test.d.ts +2 -0
- package/dist/__tests__/crashreporting/CrashReporter.test.d.ts.map +1 -0
- package/dist/__tests__/crashreporting/CrashReporter.test.js +89 -0
- package/dist/__tests__/crashreporting/CrashReporter.test.js.map +1 -0
- package/dist/__tests__/deviceservices/DeviceProvider.test.d.ts +2 -0
- package/dist/__tests__/deviceservices/DeviceProvider.test.d.ts.map +1 -0
- package/dist/__tests__/deviceservices/DeviceProvider.test.js +66 -0
- package/dist/__tests__/deviceservices/DeviceProvider.test.js.map +1 -0
- package/dist/__tests__/filemanagement/FileProvider.test.d.ts +2 -0
- package/dist/__tests__/filemanagement/FileProvider.test.d.ts.map +1 -0
- package/dist/__tests__/filemanagement/FileProvider.test.js +95 -0
- package/dist/__tests__/filemanagement/FileProvider.test.js.map +1 -0
- package/dist/__tests__/networking/NetworkClient.test.d.ts +2 -0
- package/dist/__tests__/networking/NetworkClient.test.d.ts.map +1 -0
- package/dist/__tests__/networking/NetworkClient.test.js +162 -0
- package/dist/__tests__/networking/NetworkClient.test.js.map +1 -0
- package/dist/__tests__/persistence/StorageProvider.test.d.ts +2 -0
- package/dist/__tests__/persistence/StorageProvider.test.d.ts.map +1 -0
- package/dist/__tests__/persistence/StorageProvider.test.js +70 -0
- package/dist/__tests__/persistence/StorageProvider.test.js.map +1 -0
- package/dist/__tests__/pushnotifications/PushProvider.test.d.ts +2 -0
- package/dist/__tests__/pushnotifications/PushProvider.test.d.ts.map +1 -0
- package/dist/__tests__/pushnotifications/PushProvider.test.js +56 -0
- package/dist/__tests__/pushnotifications/PushProvider.test.js.map +1 -0
- package/dist/__tests__/remoteconfig/RemoteConfigProvider.test.d.ts +2 -0
- package/dist/__tests__/remoteconfig/RemoteConfigProvider.test.d.ts.map +1 -0
- package/dist/__tests__/remoteconfig/RemoteConfigProvider.test.js +127 -0
- package/dist/__tests__/remoteconfig/RemoteConfigProvider.test.js.map +1 -0
- package/dist/__tests__/websocket/WebSocketProvider.test.d.ts +2 -0
- package/dist/__tests__/websocket/WebSocketProvider.test.d.ts.map +1 -0
- package/dist/__tests__/websocket/WebSocketProvider.test.js +85 -0
- package/dist/__tests__/websocket/WebSocketProvider.test.js.map +1 -0
- package/dist/analytics/AnalyticsProvider.d.ts +83 -0
- package/dist/analytics/AnalyticsProvider.d.ts.map +1 -0
- package/dist/analytics/AnalyticsProvider.js +122 -0
- package/dist/analytics/AnalyticsProvider.js.map +1 -0
- package/dist/auth/AuthProvider.d.ts +85 -0
- package/dist/auth/AuthProvider.d.ts.map +1 -0
- package/dist/auth/AuthProvider.js +240 -0
- package/dist/auth/AuthProvider.js.map +1 -0
- package/dist/crashreporting/CrashReporter.d.ts +103 -0
- package/dist/crashreporting/CrashReporter.d.ts.map +1 -0
- package/dist/crashreporting/CrashReporter.js +87 -0
- package/dist/crashreporting/CrashReporter.js.map +1 -0
- package/dist/deviceservices/DeviceProvider.d.ts +63 -0
- package/dist/deviceservices/DeviceProvider.d.ts.map +1 -0
- package/dist/deviceservices/DeviceProvider.js +102 -0
- package/dist/deviceservices/DeviceProvider.js.map +1 -0
- package/dist/filemanagement/FileProvider.d.ts +92 -0
- package/dist/filemanagement/FileProvider.d.ts.map +1 -0
- package/dist/filemanagement/FileProvider.js +108 -0
- package/dist/filemanagement/FileProvider.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/networking/NetworkClient.d.ts +62 -0
- package/dist/networking/NetworkClient.d.ts.map +1 -0
- package/dist/networking/NetworkClient.js +140 -0
- package/dist/networking/NetworkClient.js.map +1 -0
- package/dist/persistence/StorageProvider.d.ts +40 -0
- package/dist/persistence/StorageProvider.d.ts.map +1 -0
- package/dist/persistence/StorageProvider.js +56 -0
- package/dist/persistence/StorageProvider.js.map +1 -0
- package/dist/pushnotifications/PushProvider.d.ts +92 -0
- package/dist/pushnotifications/PushProvider.d.ts.map +1 -0
- package/dist/pushnotifications/PushProvider.js +57 -0
- package/dist/pushnotifications/PushProvider.js.map +1 -0
- package/dist/remoteconfig/RemoteConfigProvider.d.ts +101 -0
- package/dist/remoteconfig/RemoteConfigProvider.d.ts.map +1 -0
- package/dist/remoteconfig/RemoteConfigProvider.js +112 -0
- package/dist/remoteconfig/RemoteConfigProvider.js.map +1 -0
- package/dist/websocket/WebSocketProvider.d.ts +153 -0
- package/dist/websocket/WebSocketProvider.d.ts.map +1 -0
- package/dist/websocket/WebSocketProvider.js +240 -0
- package/dist/websocket/WebSocketProvider.js.map +1 -0
- package/jest.config.js +7 -0
- package/package.json +48 -0
- package/src/__tests__/analytics/AnalyticsProvider.test.ts +111 -0
- package/src/__tests__/auth/AuthProvider.test.ts +170 -0
- package/src/__tests__/crashreporting/CrashReporter.test.ts +112 -0
- package/src/__tests__/deviceservices/DeviceProvider.test.ts +75 -0
- package/src/__tests__/filemanagement/FileProvider.test.ts +104 -0
- package/src/__tests__/networking/NetworkClient.test.ts +185 -0
- package/src/__tests__/persistence/StorageProvider.test.ts +78 -0
- package/src/__tests__/pushnotifications/PushProvider.test.ts +62 -0
- package/src/__tests__/remoteconfig/RemoteConfigProvider.test.ts +147 -0
- package/src/__tests__/websocket/WebSocketProvider.test.ts +95 -0
- package/src/analytics/AnalyticsProvider.ts +169 -0
- package/src/auth/AuthProvider.ts +277 -0
- package/src/crashreporting/CrashReporter.ts +167 -0
- package/src/deviceservices/DeviceProvider.ts +151 -0
- package/src/filemanagement/FileProvider.ts +132 -0
- package/src/index.ts +10 -0
- package/src/networking/NetworkClient.ts +216 -0
- package/src/persistence/StorageProvider.ts +54 -0
- package/src/pushnotifications/PushProvider.ts +120 -0
- package/src/remoteconfig/RemoteConfigProvider.ts +187 -0
- package/src/websocket/WebSocketProvider.ts +327 -0
- package/syzygy.yml +9 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ['**']
|
|
6
|
+
tags-ignore: ['*']
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- uses: actions/setup-node@v4
|
|
17
|
+
with:
|
|
18
|
+
node-version: '20'
|
|
19
|
+
|
|
20
|
+
- run: npm ci
|
|
21
|
+
|
|
22
|
+
- name: Fetch ESLint + Prettier configs
|
|
23
|
+
run: |
|
|
24
|
+
curl -fsSL https://raw.githubusercontent.com/Syzygy-Hub/.github/main/engineering/tooling/rn/.eslintrc.ts.json -o .eslintrc.json
|
|
25
|
+
curl -fsSL https://raw.githubusercontent.com/Syzygy-Hub/.github/main/engineering/tooling/rn/.prettierrc -o .prettierrc
|
|
26
|
+
|
|
27
|
+
- name: Typecheck
|
|
28
|
+
run: npm run typecheck
|
|
29
|
+
|
|
30
|
+
- name: Lint
|
|
31
|
+
run: npm run lint
|
|
32
|
+
|
|
33
|
+
- name: Test
|
|
34
|
+
run: npm test
|
|
35
|
+
|
|
36
|
+
- name: Upload coverage
|
|
37
|
+
if: always()
|
|
38
|
+
uses: actions/upload-artifact@v4
|
|
39
|
+
with:
|
|
40
|
+
name: coverage
|
|
41
|
+
path: coverage/
|
|
42
|
+
if-no-files-found: warn
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ['[0-9]+.[0-9]+.[0-9]+']
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
id-token: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
release:
|
|
13
|
+
uses: Syzygy-Hub/.github/.github/workflows/rn-release.yml@main
|
|
14
|
+
secrets: inherit
|
|
15
|
+
|
|
16
|
+
publish-npm:
|
|
17
|
+
needs: release
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
permissions:
|
|
20
|
+
id-token: write
|
|
21
|
+
contents: read
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
- uses: actions/setup-node@v4
|
|
25
|
+
with:
|
|
26
|
+
node-version: '24'
|
|
27
|
+
registry-url: 'https://registry.npmjs.org'
|
|
28
|
+
package-manager-cache: false
|
|
29
|
+
- run: npm ci
|
|
30
|
+
- run: npm publish --access=public --provenance
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2026-09-12
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- NetworkClient interface and fetch-backed HTTP client
|
|
13
|
+
- StorageProvider interface and AsyncStorage-backed key-value persistence stub
|
|
14
|
+
- AuthProvider interface and JWT token storage and refresh stub
|
|
15
|
+
- FileProvider interface and RNFS-backed file I/O stub
|
|
16
|
+
- PushProvider interface and push token registration stub
|
|
17
|
+
- DeviceProvider interface and react-native device info stub
|
|
18
|
+
- RemoteConfigProvider interface and in-memory remote config store
|
|
19
|
+
- AnalyticsProvider interface and console analytics event logging stub
|
|
20
|
+
- CrashReporter interface and console crash logging stub
|
|
21
|
+
- WebSocketProvider interface and native WebSocket implementation stub
|
|
22
|
+
|
|
23
|
+
[1.0.0]: https://github.com/Syzygy-Hub/syzygy-services-rn/releases/tag/1.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Syzygy Hub
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+

|
|
2
|
+

|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
<picture>
|
|
7
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Syzygy-Hub/.github/main/assets/syzygy-banner-dark.png">
|
|
8
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/Syzygy-Hub/.github/main/assets/syzygy-banner-light.png">
|
|
9
|
+
<img alt="Syzygy Banner" src="https://raw.githubusercontent.com/Syzygy-Hub/.github/main/assets/syzygy-banner-light.png">
|
|
10
|
+
</picture>
|
|
11
|
+
|
|
12
|
+
# syzygy-services-rn
|
|
13
|
+
|
|
14
|
+
Concrete I/O service implementations for the Syzygy React Native ecosystem — networking, persistence, auth, file management, push notifications, device services, remote config, analytics, crash reporting, and WebSocket.
|
|
15
|
+
|
|
16
|
+
## Modules
|
|
17
|
+
|
|
18
|
+
| Module | Interface | Implementation | Description |
|
|
19
|
+
|--------|-----------|----------------|-------------|
|
|
20
|
+
| `networking` | `NetworkClient` | `FetchNetworkClient` | HTTP GET/POST via global `fetch` |
|
|
21
|
+
| `persistence` | `StorageProvider` | `InMemoryStorageProvider` | Key-value storage (swap with AsyncStorage) |
|
|
22
|
+
| `auth` | `AuthProvider` | `JWTAuthProvider` | JWT token storage and refresh stub |
|
|
23
|
+
| `filemanagement` | `FileProvider` | `NodeFileProvider` | File read/write/delete (swap with RNFS) |
|
|
24
|
+
| `pushnotifications` | `PushProvider` | `InMemoryPushProvider` | Push token registration stub |
|
|
25
|
+
| `deviceservices` | `DeviceProvider` | `NodeDeviceProvider` | Hostname, platform, OS version |
|
|
26
|
+
| `remoteconfig` | `RemoteConfigProvider` | `InMemoryRemoteConfigProvider` | In-memory remote config store |
|
|
27
|
+
| `analytics` | `AnalyticsProvider` | `ConsoleAnalyticsProvider` | Console-based event logging stub |
|
|
28
|
+
| `crashreporting` | `CrashReporter` | `ConsoleCrashReporter` | Console-based crash/error logging stub |
|
|
29
|
+
| `websocket` | `WebSocketProvider` | `NativeWebSocketProvider` | Native WebSocket implementation stub |
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
npm install syzygy-services-rn
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Requirements
|
|
38
|
+
|
|
39
|
+
- React Native 0.73+
|
|
40
|
+
- TypeScript 5.0+
|
|
41
|
+
- Node 20+
|
|
42
|
+
|
|
43
|
+
## Dependencies
|
|
44
|
+
|
|
45
|
+
- `syzygy-foundation-rn` ^1.1.0
|
|
46
|
+
|
|
47
|
+
## Ecosystem
|
|
48
|
+
|
|
49
|
+
`syzygy-services-rn` is part of the Syzygy React Native ecosystem. It sits in the **services layer** — the I/O boundary of the architecture — and depends only on `syzygy-foundation-rn`. Each module ships its own interface alongside a concrete implementation, making it straightforward to swap in production adapters (AsyncStorage, RNFS, Firebase, etc.) while keeping the rest of the codebase decoupled.
|
|
50
|
+
|
|
51
|
+
| Package | Layer | Description |
|
|
52
|
+
|---------|-------|-------------|
|
|
53
|
+
| `syzygy-foundation-rn` | foundation | Primitives, utilities, base types |
|
|
54
|
+
| `syzygy-services-rn` | services | I/O service interfaces and implementations |
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalyticsProvider.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/analytics/AnalyticsProvider.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const syzygy_foundation_rn_1 = require("syzygy-foundation-rn");
|
|
4
|
+
const AnalyticsProvider_1 = require("../../analytics/AnalyticsProvider");
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// InMemoryAnalyticsProvider
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
describe('InMemoryAnalyticsProvider', () => {
|
|
9
|
+
it('track stores the event', () => {
|
|
10
|
+
const provider = new AnalyticsProvider_1.InMemoryAnalyticsProvider();
|
|
11
|
+
const event = (0, syzygy_foundation_rn_1.createAnalyticsEvent)('button_click', { label: 'submit' });
|
|
12
|
+
provider.track(event);
|
|
13
|
+
expect(provider.events).toHaveLength(1);
|
|
14
|
+
expect(provider.events[0].name).toBe('button_click');
|
|
15
|
+
expect(provider.events[0].properties.label).toBe('submit');
|
|
16
|
+
});
|
|
17
|
+
it('identify stores user properties', () => {
|
|
18
|
+
const provider = new AnalyticsProvider_1.InMemoryAnalyticsProvider();
|
|
19
|
+
provider.identify('user-1', { plan: 'pro' });
|
|
20
|
+
expect(provider.userProperties.userId).toBe('user-1');
|
|
21
|
+
expect(provider.userProperties.plan).toBe('pro');
|
|
22
|
+
});
|
|
23
|
+
it('setUserProperties merges into existing properties', () => {
|
|
24
|
+
const provider = new AnalyticsProvider_1.InMemoryAnalyticsProvider();
|
|
25
|
+
provider.setUserProperties({ a: 1 });
|
|
26
|
+
provider.setUserProperties({ b: 2 });
|
|
27
|
+
expect(provider.userProperties.a).toBe(1);
|
|
28
|
+
expect(provider.userProperties.b).toBe(2);
|
|
29
|
+
});
|
|
30
|
+
it('trackScreen records the screen name and adds a screen_view event', () => {
|
|
31
|
+
const provider = new AnalyticsProvider_1.InMemoryAnalyticsProvider();
|
|
32
|
+
provider.trackScreen('HomeScreen', { tab: 'feed' });
|
|
33
|
+
expect(provider.screenViews).toEqual(['HomeScreen']);
|
|
34
|
+
expect(provider.events[0].name).toBe('screen_view');
|
|
35
|
+
expect(provider.events[0].properties.screenName).toBe('HomeScreen');
|
|
36
|
+
});
|
|
37
|
+
it('sessionId is a non-empty string', () => {
|
|
38
|
+
const provider = new AnalyticsProvider_1.InMemoryAnalyticsProvider();
|
|
39
|
+
expect(provider.sessionId.length).toBeGreaterThan(0);
|
|
40
|
+
});
|
|
41
|
+
it('reset clears user properties and generates a new sessionId', () => {
|
|
42
|
+
const provider = new AnalyticsProvider_1.InMemoryAnalyticsProvider();
|
|
43
|
+
provider.identify('user-1', { plan: 'free' });
|
|
44
|
+
const oldSession = provider.sessionId;
|
|
45
|
+
provider.reset();
|
|
46
|
+
expect(provider.userProperties).toEqual({});
|
|
47
|
+
expect(provider.sessionId).not.toBe(oldSession);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// ConsoleAnalyticsProvider
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
describe('ConsoleAnalyticsProvider', () => {
|
|
54
|
+
let consoleSpy;
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
57
|
+
});
|
|
58
|
+
afterEach(() => {
|
|
59
|
+
consoleSpy.mockRestore();
|
|
60
|
+
});
|
|
61
|
+
it('track emits to console.log', () => {
|
|
62
|
+
const provider = new AnalyticsProvider_1.ConsoleAnalyticsProvider();
|
|
63
|
+
const event = (0, syzygy_foundation_rn_1.createAnalyticsEvent)('page_view');
|
|
64
|
+
provider.track(event);
|
|
65
|
+
expect(consoleSpy).toHaveBeenCalledWith('[Analytics] track', 'page_view', {}, expect.anything());
|
|
66
|
+
});
|
|
67
|
+
it('trackScreen emits a screen_view event', () => {
|
|
68
|
+
const provider = new AnalyticsProvider_1.ConsoleAnalyticsProvider();
|
|
69
|
+
provider.trackScreen('SettingsScreen');
|
|
70
|
+
expect(consoleSpy).toHaveBeenCalledWith('[Analytics] track', 'screen_view', expect.objectContaining({ screenName: 'SettingsScreen' }), expect.anything());
|
|
71
|
+
});
|
|
72
|
+
it('identify logs user and updates userProperties', () => {
|
|
73
|
+
const provider = new AnalyticsProvider_1.ConsoleAnalyticsProvider();
|
|
74
|
+
provider.identify('u2', { email: 'a@b.com' });
|
|
75
|
+
expect(provider.userProperties.userId).toBe('u2');
|
|
76
|
+
expect(consoleSpy).toHaveBeenCalledWith('[Analytics] identify', 'u2', { email: 'a@b.com' });
|
|
77
|
+
});
|
|
78
|
+
it('reset generates a new sessionId', () => {
|
|
79
|
+
const provider = new AnalyticsProvider_1.ConsoleAnalyticsProvider();
|
|
80
|
+
const s1 = provider.sessionId;
|
|
81
|
+
provider.reset();
|
|
82
|
+
expect(provider.sessionId).not.toBe(s1);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=AnalyticsProvider.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalyticsProvider.test.js","sourceRoot":"","sources":["../../../src/__tests__/analytics/AnalyticsProvider.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthProvider.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/auth/AuthProvider.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const syzygy_foundation_rn_1 = require("syzygy-foundation-rn");
|
|
4
|
+
const AuthProvider_1 = require("../../auth/AuthProvider");
|
|
5
|
+
const StorageProvider_1 = require("../../persistence/StorageProvider");
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Helpers
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
function makeToken(overrides = {}) {
|
|
10
|
+
return {
|
|
11
|
+
accessToken: 'access-abc',
|
|
12
|
+
refreshToken: 'refresh-xyz',
|
|
13
|
+
...overrides,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function makeExpiredToken() {
|
|
17
|
+
return makeToken({
|
|
18
|
+
expiresAt: (0, syzygy_foundation_rn_1.createSyzygyTimestamp)(Date.now() - 10000),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function makeValidToken() {
|
|
22
|
+
return makeToken({
|
|
23
|
+
expiresAt: (0, syzygy_foundation_rn_1.createSyzygyTimestamp)(Date.now() + 60000),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Tests
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
describe('JWTAuthProvider', () => {
|
|
30
|
+
it('starts in unauthenticated state', () => {
|
|
31
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
32
|
+
const provider = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
33
|
+
expect(provider.state.kind).toBe('unauthenticated');
|
|
34
|
+
});
|
|
35
|
+
it('authenticate transitions to authenticated', () => {
|
|
36
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
37
|
+
const provider = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
38
|
+
provider.authenticate(makeToken());
|
|
39
|
+
expect(provider.state.kind).toBe('authenticated');
|
|
40
|
+
});
|
|
41
|
+
it('authenticate persists the access token in storage', async () => {
|
|
42
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
43
|
+
const provider = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
44
|
+
const token = makeToken({ accessToken: 'persisted-token' });
|
|
45
|
+
provider.authenticate(token);
|
|
46
|
+
// Allow async persistence to complete
|
|
47
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
48
|
+
const stored = await storage.get({ identifier: 'syzygy.auth.accessToken' });
|
|
49
|
+
expect(stored).toBe('persisted-token');
|
|
50
|
+
});
|
|
51
|
+
it('signOut transitions to unauthenticated and clears token', async () => {
|
|
52
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
53
|
+
const provider = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
54
|
+
provider.authenticate(makeToken());
|
|
55
|
+
provider.signOut();
|
|
56
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
57
|
+
expect(provider.state.kind).toBe('unauthenticated');
|
|
58
|
+
const stored = await storage.get({ identifier: 'syzygy.auth.accessToken' });
|
|
59
|
+
expect(stored).toBeUndefined();
|
|
60
|
+
});
|
|
61
|
+
it('subscribe notifies listener on state change', () => {
|
|
62
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
63
|
+
const provider = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
64
|
+
const states = [];
|
|
65
|
+
provider.subscribe((s) => states.push(s.kind));
|
|
66
|
+
provider.authenticate(makeToken());
|
|
67
|
+
provider.signOut();
|
|
68
|
+
expect(states).toEqual(['authenticated', 'unauthenticated']);
|
|
69
|
+
});
|
|
70
|
+
it('unsubscribe stops notifications', () => {
|
|
71
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
72
|
+
const provider = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
73
|
+
const states = [];
|
|
74
|
+
const unsub = provider.subscribe((s) => states.push(s.kind));
|
|
75
|
+
provider.authenticate(makeToken());
|
|
76
|
+
unsub();
|
|
77
|
+
provider.signOut();
|
|
78
|
+
expect(states).toEqual(['authenticated']); // signOut not received
|
|
79
|
+
});
|
|
80
|
+
it('restore loads a valid token from storage', async () => {
|
|
81
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
82
|
+
const provider = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
83
|
+
provider.authenticate(makeValidToken());
|
|
84
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
85
|
+
const provider2 = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
86
|
+
await provider2.restore();
|
|
87
|
+
expect(provider2.state.kind).toBe('authenticated');
|
|
88
|
+
});
|
|
89
|
+
it('restore transitions to expired when token is past expiresAt', async () => {
|
|
90
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
91
|
+
const provider = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
92
|
+
provider.authenticate(makeExpiredToken());
|
|
93
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
94
|
+
const provider2 = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
95
|
+
await provider2.restore();
|
|
96
|
+
expect(provider2.state.kind).toBe('expired');
|
|
97
|
+
});
|
|
98
|
+
it('restore transitions to unauthenticated when no token in storage', async () => {
|
|
99
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
100
|
+
const provider = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
101
|
+
await provider.restore();
|
|
102
|
+
expect(provider.state.kind).toBe('unauthenticated');
|
|
103
|
+
});
|
|
104
|
+
it('refresh without network config throws AuthError', async () => {
|
|
105
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
106
|
+
const provider = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
107
|
+
provider.authenticate(makeToken());
|
|
108
|
+
await expect(provider.refresh()).rejects.toBeInstanceOf(AuthProvider_1.AuthError);
|
|
109
|
+
});
|
|
110
|
+
it('refresh without an authenticated token throws AuthError', async () => {
|
|
111
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
112
|
+
const provider = new AuthProvider_1.JWTAuthProvider({ storage });
|
|
113
|
+
await expect(provider.refresh()).rejects.toBeInstanceOf(AuthProvider_1.AuthError);
|
|
114
|
+
});
|
|
115
|
+
it('AuthState helpers work correctly', () => {
|
|
116
|
+
const token = makeToken();
|
|
117
|
+
expect(syzygy_foundation_rn_1.AuthState.isAuthenticated(syzygy_foundation_rn_1.AuthState.authenticated(token))).toBe(true);
|
|
118
|
+
expect(syzygy_foundation_rn_1.AuthState.isAuthenticated(syzygy_foundation_rn_1.AuthState.unauthenticated())).toBe(false);
|
|
119
|
+
expect(syzygy_foundation_rn_1.AuthState.token(syzygy_foundation_rn_1.AuthState.authenticated(token))).toEqual(token);
|
|
120
|
+
expect(syzygy_foundation_rn_1.AuthState.token(syzygy_foundation_rn_1.AuthState.unauthenticated())).toBeUndefined();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// extractExpFromJwt
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
describe('extractExpFromJwt', () => {
|
|
127
|
+
function buildJwt(payload) {
|
|
128
|
+
const header = Buffer.from(JSON.stringify({ alg: 'HS256' })).toString('base64url');
|
|
129
|
+
const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
|
|
130
|
+
return `${header}.${body}.sig`;
|
|
131
|
+
}
|
|
132
|
+
it('extracts the exp claim as milliseconds', () => {
|
|
133
|
+
const expSec = Math.floor(Date.now() / 1000) + 3600;
|
|
134
|
+
const jwt = buildJwt({ exp: expSec });
|
|
135
|
+
const result = (0, AuthProvider_1.extractExpFromJwt)(jwt);
|
|
136
|
+
expect(result?.millisecondsSinceEpoch).toBe(expSec * 1000);
|
|
137
|
+
});
|
|
138
|
+
it('returns undefined when exp is missing', () => {
|
|
139
|
+
const jwt = buildJwt({ sub: 'user-1' });
|
|
140
|
+
expect((0, AuthProvider_1.extractExpFromJwt)(jwt)).toBeUndefined();
|
|
141
|
+
});
|
|
142
|
+
it('returns undefined for a malformed token', () => {
|
|
143
|
+
expect((0, AuthProvider_1.extractExpFromJwt)('not.a')).toBeUndefined();
|
|
144
|
+
expect((0, AuthProvider_1.extractExpFromJwt)('')).toBeUndefined();
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
//# sourceMappingURL=AuthProvider.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthProvider.test.js","sourceRoot":"","sources":["../../../src/__tests__/auth/AuthProvider.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CrashReporter.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/crashreporting/CrashReporter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const CrashReporter_1 = require("../../crashreporting/CrashReporter");
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// InMemoryCrashReporter
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
describe('InMemoryCrashReporter', () => {
|
|
8
|
+
it('recordError stores the error record', () => {
|
|
9
|
+
const reporter = new CrashReporter_1.InMemoryCrashReporter();
|
|
10
|
+
const error = new Error('test error');
|
|
11
|
+
reporter.recordError(error, { module: 'auth' });
|
|
12
|
+
expect(reporter.errors).toHaveLength(1);
|
|
13
|
+
expect(reporter.errors[0].error).toBe(error);
|
|
14
|
+
expect(reporter.errors[0].metadata.module).toBe('auth');
|
|
15
|
+
});
|
|
16
|
+
it('reportCrash stores the crash record', () => {
|
|
17
|
+
const reporter = new CrashReporter_1.InMemoryCrashReporter();
|
|
18
|
+
reporter.reportCrash('fatal crash', { screen: 'Home' });
|
|
19
|
+
expect(reporter.crashes).toHaveLength(1);
|
|
20
|
+
expect(reporter.crashes[0].message).toBe('fatal crash');
|
|
21
|
+
expect(reporter.crashes[0].metadata.screen).toBe('Home');
|
|
22
|
+
});
|
|
23
|
+
it('setUserContext is retrievable', () => {
|
|
24
|
+
const reporter = new CrashReporter_1.InMemoryCrashReporter();
|
|
25
|
+
reporter.setUserContext({ userId: 'u1', email: 'u@example.com' });
|
|
26
|
+
expect(reporter.userContext?.userId).toBe('u1');
|
|
27
|
+
expect(reporter.userContext?.email).toBe('u@example.com');
|
|
28
|
+
});
|
|
29
|
+
it('setUserContext can be cleared with undefined', () => {
|
|
30
|
+
const reporter = new CrashReporter_1.InMemoryCrashReporter();
|
|
31
|
+
reporter.setUserContext({ userId: 'u1' });
|
|
32
|
+
reporter.setUserContext(undefined);
|
|
33
|
+
expect(reporter.userContext).toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
it('setMetadata stores key-value pairs', () => {
|
|
36
|
+
const reporter = new CrashReporter_1.InMemoryCrashReporter();
|
|
37
|
+
reporter.setMetadata('version', '1.2.3');
|
|
38
|
+
reporter.setMetadata('env', 'prod');
|
|
39
|
+
expect(reporter.metadata.version).toBe('1.2.3');
|
|
40
|
+
expect(reporter.metadata.env).toBe('prod');
|
|
41
|
+
});
|
|
42
|
+
it('metadata is included in crash records', () => {
|
|
43
|
+
const reporter = new CrashReporter_1.InMemoryCrashReporter();
|
|
44
|
+
reporter.setMetadata('buildNumber', '42');
|
|
45
|
+
reporter.reportCrash('boom');
|
|
46
|
+
expect(reporter.crashes[0].metadata.buildNumber).toBe('42');
|
|
47
|
+
});
|
|
48
|
+
it('metadata is included in error records', () => {
|
|
49
|
+
const reporter = new CrashReporter_1.InMemoryCrashReporter();
|
|
50
|
+
reporter.setMetadata('env', 'staging');
|
|
51
|
+
reporter.recordError(new Error('oops'));
|
|
52
|
+
expect(reporter.errors[0].metadata.env).toBe('staging');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// ConsoleCrashReporter
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
describe('ConsoleCrashReporter', () => {
|
|
59
|
+
let consoleSpy;
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
62
|
+
});
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
consoleSpy.mockRestore();
|
|
65
|
+
});
|
|
66
|
+
it('recordError does not throw', () => {
|
|
67
|
+
const reporter = new CrashReporter_1.ConsoleCrashReporter();
|
|
68
|
+
expect(() => reporter.recordError(new Error('non-fatal'), { ctx: 'test' })).not.toThrow();
|
|
69
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
70
|
+
});
|
|
71
|
+
it('reportCrash does not throw', () => {
|
|
72
|
+
const reporter = new CrashReporter_1.ConsoleCrashReporter();
|
|
73
|
+
expect(() => reporter.reportCrash('crash msg')).not.toThrow();
|
|
74
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
it('setUserContext is stored and reflected in crash reports', () => {
|
|
77
|
+
const reporter = new CrashReporter_1.ConsoleCrashReporter();
|
|
78
|
+
reporter.setUserContext({ userId: 'u42' });
|
|
79
|
+
reporter.reportCrash('uh oh');
|
|
80
|
+
expect(consoleSpy).toHaveBeenCalledWith('[CrashReporter] CRASH:', 'uh oh', expect.any(Object), expect.objectContaining({ userId: 'u42' }));
|
|
81
|
+
});
|
|
82
|
+
it('setMetadata is reflected in error reports', () => {
|
|
83
|
+
const reporter = new CrashReporter_1.ConsoleCrashReporter();
|
|
84
|
+
reporter.setMetadata('platform', 'ios');
|
|
85
|
+
reporter.recordError(new Error('err'));
|
|
86
|
+
expect(consoleSpy).toHaveBeenCalledWith('[CrashReporter] ERROR:', 'err', expect.objectContaining({ platform: 'ios' }), undefined);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=CrashReporter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CrashReporter.test.js","sourceRoot":"","sources":["../../../src/__tests__/crashreporting/CrashReporter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeviceProvider.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/deviceservices/DeviceProvider.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const DeviceProvider_1 = require("../../deviceservices/DeviceProvider");
|
|
4
|
+
const StorageProvider_1 = require("../../persistence/StorageProvider");
|
|
5
|
+
describe('NodeDeviceProvider', () => {
|
|
6
|
+
it('platform is always "rn"', () => {
|
|
7
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
8
|
+
const provider = new DeviceProvider_1.NodeDeviceProvider({ storage });
|
|
9
|
+
expect(provider.platform).toBe('rn');
|
|
10
|
+
});
|
|
11
|
+
it('osVersion is a non-empty string', () => {
|
|
12
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
13
|
+
const provider = new DeviceProvider_1.NodeDeviceProvider({ storage });
|
|
14
|
+
expect(typeof provider.osVersion).toBe('string');
|
|
15
|
+
expect(provider.osVersion.length).toBeGreaterThan(0);
|
|
16
|
+
});
|
|
17
|
+
it('appVersion matches the override when provided', () => {
|
|
18
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
19
|
+
const provider = new DeviceProvider_1.NodeDeviceProvider({ storage, appVersion: '2.3.4' });
|
|
20
|
+
expect(provider.appVersion).toBe('2.3.4');
|
|
21
|
+
});
|
|
22
|
+
it('appVersion defaults to a non-empty string when no override', () => {
|
|
23
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
24
|
+
const provider = new DeviceProvider_1.NodeDeviceProvider({ storage });
|
|
25
|
+
expect(provider.appVersion.length).toBeGreaterThan(0);
|
|
26
|
+
});
|
|
27
|
+
it('isSimulator is false by default', () => {
|
|
28
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
29
|
+
const provider = new DeviceProvider_1.NodeDeviceProvider({ storage });
|
|
30
|
+
expect(provider.isSimulator).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
it('isSimulator can be overridden', () => {
|
|
33
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
34
|
+
const provider = new DeviceProvider_1.NodeDeviceProvider({ storage, isSimulator: true });
|
|
35
|
+
expect(provider.isSimulator).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
it('deviceId generates and persists a UUID', async () => {
|
|
38
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
39
|
+
const provider = new DeviceProvider_1.NodeDeviceProvider({ storage });
|
|
40
|
+
const id = await provider.deviceId;
|
|
41
|
+
expect(typeof id).toBe('string');
|
|
42
|
+
expect(id.length).toBeGreaterThan(0);
|
|
43
|
+
});
|
|
44
|
+
it('deviceId is the same across multiple calls', async () => {
|
|
45
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
46
|
+
const provider = new DeviceProvider_1.NodeDeviceProvider({ storage });
|
|
47
|
+
const id1 = await provider.deviceId;
|
|
48
|
+
const id2 = await provider.deviceId;
|
|
49
|
+
expect(id1).toBe(id2);
|
|
50
|
+
});
|
|
51
|
+
it('deviceId persists across provider instances sharing the same storage', async () => {
|
|
52
|
+
const storage = new StorageProvider_1.InMemoryStorageProvider();
|
|
53
|
+
const provider1 = new DeviceProvider_1.NodeDeviceProvider({ storage });
|
|
54
|
+
const id1 = await provider1.deviceId;
|
|
55
|
+
const provider2 = new DeviceProvider_1.NodeDeviceProvider({ storage });
|
|
56
|
+
const id2 = await provider2.deviceId;
|
|
57
|
+
expect(id1).toBe(id2);
|
|
58
|
+
});
|
|
59
|
+
it('deviceId is unique across different storage instances', async () => {
|
|
60
|
+
const p1 = new DeviceProvider_1.NodeDeviceProvider({ storage: new StorageProvider_1.InMemoryStorageProvider() });
|
|
61
|
+
const p2 = new DeviceProvider_1.NodeDeviceProvider({ storage: new StorageProvider_1.InMemoryStorageProvider() });
|
|
62
|
+
const [id1, id2] = await Promise.all([p1.deviceId, p2.deviceId]);
|
|
63
|
+
expect(id1).not.toBe(id2);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
//# sourceMappingURL=DeviceProvider.test.js.map
|