@oxyhq/core 7.1.1 → 8.1.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/README.md +48 -24
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/HttpService.js +6 -6
- package/dist/cjs/boot/coldBootV2.js +97 -2
- package/dist/cjs/boot/deviceBootReturn.js +15 -0
- package/dist/cjs/i18n/locales/en-US.json +44 -1
- package/dist/cjs/i18n/locales/es-ES.json +44 -1
- package/dist/cjs/i18n/locales/locales/en-US.json +45 -2
- package/dist/cjs/i18n/locales/locales/es-ES.json +45 -2
- package/dist/cjs/index.js +19 -16
- package/dist/cjs/mixins/OxyServices.deviceBoot.js +28 -0
- package/dist/cjs/server/index.js +1 -7
- package/dist/cjs/session/accountDialogController.js +1 -1
- package/dist/cjs/session/accountProjection.js +1 -1
- package/dist/cjs/session/authStateStore.js +6 -0
- package/dist/cjs/session/projectSessionState.js +1 -1
- package/dist/cjs/session/refresh.js +9 -0
- package/dist/cjs/session/sessionClientHost.js +1 -2
- package/dist/cjs/utils/accountUtils.js +1 -1
- package/dist/cjs/utils/oauthPkce.js +142 -0
- package/dist/cjs/utils/platform.js +1 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/HttpService.js +6 -6
- package/dist/esm/boot/coldBootV2.js +97 -2
- package/dist/esm/boot/deviceBootReturn.js +15 -0
- package/dist/esm/i18n/locales/en-US.json +44 -1
- package/dist/esm/i18n/locales/es-ES.json +44 -1
- package/dist/esm/i18n/locales/locales/en-US.json +45 -2
- package/dist/esm/i18n/locales/locales/es-ES.json +45 -2
- package/dist/esm/index.js +11 -13
- package/dist/esm/mixins/OxyServices.deviceBoot.js +29 -1
- package/dist/esm/server/index.js +0 -5
- package/dist/esm/session/accountDialogController.js +1 -1
- package/dist/esm/session/accountProjection.js +1 -1
- package/dist/esm/session/authStateStore.js +6 -0
- package/dist/esm/session/projectSessionState.js +1 -1
- package/dist/esm/session/refresh.js +9 -0
- package/dist/esm/session/sessionClientHost.js +1 -2
- package/dist/esm/utils/accountUtils.js +1 -1
- package/dist/esm/utils/oauthPkce.js +135 -0
- package/dist/esm/utils/platform.js +1 -1
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/HttpService.d.ts +1 -1
- package/dist/types/index.d.ts +3 -2
- package/dist/types/mixins/OxyServices.accounts.d.ts +13 -3
- package/dist/types/mixins/OxyServices.connectedApps.d.ts +4 -0
- package/dist/types/mixins/OxyServices.deviceBoot.d.ts +17 -1
- package/dist/types/mixins/OxyServices.devices.d.ts +3 -2
- package/dist/types/models/interfaces.d.ts +4 -4
- package/dist/types/server/index.d.ts +0 -1
- package/dist/types/session/accountDialogController.d.ts +1 -1
- package/dist/types/session/accountProjection.d.ts +1 -1
- package/dist/types/session/authStateStore.d.ts +20 -0
- package/dist/types/session/projectSessionState.d.ts +1 -1
- package/dist/types/session/refresh.d.ts +4 -8
- package/dist/types/session/sessionClientHost.d.ts +1 -2
- package/dist/types/utils/accountUtils.d.ts +1 -1
- package/dist/types/utils/oauthPkce.d.ts +74 -0
- package/dist/types/utils/platform.d.ts +1 -1
- package/package.json +3 -3
- package/src/HttpService.ts +6 -6
- package/src/boot/__tests__/coldBootV2.test.ts +215 -1
- package/src/boot/__tests__/deviceBootReturn.test.ts +32 -0
- package/src/boot/coldBootV2.ts +117 -2
- package/src/boot/deviceBootReturn.ts +15 -0
- package/src/i18n/locales/en-US.json +45 -2
- package/src/i18n/locales/es-ES.json +45 -2
- package/src/index.ts +23 -16
- package/src/mixins/OxyServices.accounts.ts +12 -0
- package/src/mixins/OxyServices.connectedApps.ts +4 -0
- package/src/mixins/OxyServices.deviceBoot.ts +38 -0
- package/src/mixins/OxyServices.devices.ts +6 -5
- package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +44 -1
- package/src/mixins/__tests__/accounts.test.ts +1 -1
- package/src/models/interfaces.ts +7 -5
- package/src/server/index.ts +0 -6
- package/src/session/__tests__/authStateStore.test.ts +27 -0
- package/src/session/__tests__/refresh.test.ts +14 -0
- package/src/session/accountDialogController.ts +1 -1
- package/src/session/accountProjection.ts +1 -1
- package/src/session/authStateStore.ts +26 -0
- package/src/session/projectSessionState.ts +1 -1
- package/src/session/refresh.ts +13 -8
- package/src/session/sessionClientHost.ts +1 -2
- package/src/utils/__tests__/coldBoot.test.ts +55 -65
- package/src/utils/__tests__/oauthPkce.test.ts +154 -0
- package/src/utils/accountUtils.ts +1 -1
- package/src/utils/oauthPkce.ts +189 -0
- package/src/utils/platform.ts +1 -1
- package/dist/cjs/utils/ssoBounce.js +0 -24
- package/dist/esm/utils/ssoBounce.js +0 -21
- package/dist/types/utils/ssoBounce.d.ts +0 -21
- package/src/utils/ssoBounce.ts +0 -22
package/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
OxyHQ SDK Foundation. Platform-agnostic core library that works in Node.js, browser, and React Native environments. No React dependency.
|
|
4
4
|
|
|
5
|
-
**Current published version: 3.4.16**
|
|
6
|
-
|
|
7
5
|
## Installation
|
|
8
6
|
|
|
9
7
|
```bash
|
|
@@ -13,7 +11,8 @@ bun add @oxyhq/core
|
|
|
13
11
|
## Contents
|
|
14
12
|
|
|
15
13
|
- **OxyServices API client** — all API methods for interacting with OxyHQ services
|
|
16
|
-
- **
|
|
14
|
+
- **Device-first session engine** — `SessionClient` (`src/session/`), `runSessionColdBoot`, and the device-session mixin that back `OxyProvider` in `@oxyhq/services`
|
|
15
|
+
- **OAuth helpers** — `generatePkcePair`, `generateOAuthState`, `buildOAuthAuthorizeUrl` for third-party "Sign in with Oxy" (see [docs/auth/integration-guide.md](../../docs/auth/integration-guide.md))
|
|
17
16
|
- **Crypto** — KeyManager, SignatureService, RecoveryPhraseService
|
|
18
17
|
- **Models and types** — User, ApiError, ClientSession, and more
|
|
19
18
|
- **i18n** — translate function and locale files
|
|
@@ -21,31 +20,61 @@ bun add @oxyhq/core
|
|
|
21
20
|
- **Platform detection utilities**
|
|
22
21
|
- **Device management**
|
|
23
22
|
- **Linked clients** for app backends that need the active Oxy bearer token
|
|
24
|
-
- **User identity contracts and handle normalization** so
|
|
23
|
+
- **User identity contracts and handle normalization** so apps render display names and build local/federated profile handles consistently
|
|
25
24
|
- **Server middleware** for Express request identity and per-user rate limiting
|
|
26
25
|
|
|
27
26
|
## Exports
|
|
28
27
|
|
|
29
28
|
The package exposes two public entry points:
|
|
30
29
|
|
|
31
|
-
- `@oxyhq/core` — main entry (API client,
|
|
32
|
-
- `@oxyhq/core/server` — Express-only helpers (`createOxyRateLimit`, `createOxyAuthMiddleware`, `requireOxyAuth`, `getOxyUserId`, `getRequiredOxyUserId`, and request types)
|
|
30
|
+
- `@oxyhq/core` — main entry (API client, session, crypto, models, shared utilities, i18n, platform, device)
|
|
31
|
+
- `@oxyhq/core/server` — Express-only helpers (`createOxyRateLimit`, `createOxyAuthMiddleware`, `requireOxyAuth`, `getOxyUserId`, `getRequiredOxyUserId`, `createOxyCors`, `safeFetch`, `verifySecret`, and request types)
|
|
33
32
|
|
|
34
|
-
All client/runtime symbols (including `KeyManager`, `SignatureService`, `RecoveryPhraseService`, and the shared color / theme / error / network / debug helpers) are re-exported from the package root. Server-only Express helpers live under `@oxyhq/core/server` so React Native and browser bundles never import Express.
|
|
33
|
+
All client/runtime symbols (including `SessionClient`, `KeyManager`, `SignatureService`, `RecoveryPhraseService`, and the shared color / theme / error / network / debug helpers) are re-exported from the package root. Server-only Express helpers live under `@oxyhq/core/server` so React Native and browser bundles never import Express.
|
|
35
34
|
|
|
36
35
|
## Usage
|
|
37
36
|
|
|
38
37
|
```ts
|
|
39
|
-
import { OxyServices, oxyClient, KeyManager
|
|
38
|
+
import { OxyServices, oxyClient, KeyManager } from '@oxyhq/core';
|
|
40
39
|
import type { User, ApiError } from '@oxyhq/core';
|
|
41
40
|
|
|
42
41
|
// Get user
|
|
43
42
|
const user = await oxyClient.getUserById('123');
|
|
44
43
|
|
|
45
|
-
// Crypto
|
|
46
|
-
const
|
|
44
|
+
// Crypto (KeyManager methods are static)
|
|
45
|
+
const hasIdentity = await KeyManager.hasIdentity();
|
|
47
46
|
```
|
|
48
47
|
|
|
48
|
+
## Device-First Sessions
|
|
49
|
+
|
|
50
|
+
The session authority is the server-side `DeviceSession` (one document per device: signed-in accounts + active account + revision). `@oxyhq/core` owns the whole client side of that contract:
|
|
51
|
+
|
|
52
|
+
- **`SessionClient`** (`src/session/`) — reads `GET /session/device/state`, mutates via `POST /session/device/{add,switch,signout}`, and applies `session_state` socket pushes (room `device:<deviceId>`, token-free payload) so every app on the same device stays in sync.
|
|
53
|
+
- **`runSessionColdBoot`** (`src/boot/coldBootV2.ts`) — the ordered, short-circuit cold-boot runner used by `OxyProvider`. It restores silently from device state or resolves to logged-out; it NEVER auto-redirects to a login page.
|
|
54
|
+
- **Boot handoff** — `GET /auth/device/bootstrap` → `#oxy_boot` fragment → `POST /auth/device/exchange` (single-use, origin-bound code) lets a first visit on a sibling origin adopt the existing device session.
|
|
55
|
+
|
|
56
|
+
The current transport is a durable first-party `oxy_device` cookie (`Domain=.oxy.so`, opaque secret — never the deviceId) plus a persisted rotating refresh-token family. This transport is frozen by decision; a cookie-free `deviceSecret` mint is a pending design goal, not current behavior. Full contract: [docs/auth/device-session.md](../../docs/auth/device-session.md).
|
|
57
|
+
|
|
58
|
+
Consumers never build session restore themselves — mount `OxyProvider` from `@oxyhq/services` with a registered `clientId`.
|
|
59
|
+
|
|
60
|
+
## OAuth Helpers (third party)
|
|
61
|
+
|
|
62
|
+
Third-party apps sign users in with standard OAuth 2.0 Authorization Code + PKCE against `auth.oxy.so`:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { generatePkcePair, generateOAuthState, buildOAuthAuthorizeUrl } from '@oxyhq/core';
|
|
66
|
+
|
|
67
|
+
const [pkce, state] = await Promise.all([generatePkcePair(), generateOAuthState()]);
|
|
68
|
+
const url = buildOAuthAuthorizeUrl({
|
|
69
|
+
clientId: 'oxy_dk_…',
|
|
70
|
+
redirectUri: 'https://merchant.example/auth/callback',
|
|
71
|
+
codeChallenge: pkce.codeChallenge,
|
|
72
|
+
state,
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`OxySignInButton` in `@oxyhq/services` uses these internally when the resolved Application is `third_party`. See [docs/auth/integration-guide.md](../../docs/auth/integration-guide.md).
|
|
77
|
+
|
|
49
78
|
## User Identity And Handles
|
|
50
79
|
|
|
51
80
|
SDK user payloads may arrive with either `id` or Mongo-style `_id`; normalize
|
|
@@ -58,10 +87,10 @@ const id = getNormalizedUserId(user);
|
|
|
58
87
|
const normalizedUser = normalizeUserIdentity(user);
|
|
59
88
|
```
|
|
60
89
|
|
|
61
|
-
`User.displayName` is
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
90
|
+
`User.name.displayName` is **optional** — federated or unresolved actors routinely
|
|
91
|
+
omit it. Render it directly when present; when absent, fall back to the
|
|
92
|
+
normalized handle (`displayName ?? handle`). Never rebuild names from
|
|
93
|
+
`name.first`, `name.last`, `name.full`, or `username`.
|
|
65
94
|
|
|
66
95
|
For profile display/routing, use `getNormalizedUserHandle()`. It strips a
|
|
67
96
|
leading `@`, preserves an existing `user@instance` handle, and appends
|
|
@@ -93,7 +122,7 @@ Linked clients send the current Oxy bearer token for authenticated requests.
|
|
|
93
122
|
State-changing bearer requests do not fetch app-local CSRF tokens; cookie-only
|
|
94
123
|
writes still use CSRF.
|
|
95
124
|
|
|
96
|
-
**GET response caching is OFF by default for linked clients
|
|
125
|
+
**GET response caching is OFF by default for linked clients.** The
|
|
97
126
|
SDK's per-instance GET cache is only safe on the canonical `OxyServices` client,
|
|
98
127
|
where every mutation (`updateProfile`, `followUser`, `blockUser`, …) busts the
|
|
99
128
|
matching cached GET. A linked client targets the consuming app's own backend,
|
|
@@ -145,7 +174,9 @@ using backend-specific fields.
|
|
|
145
174
|
bun run build
|
|
146
175
|
```
|
|
147
176
|
|
|
148
|
-
Compiles with TypeScript, producing CJS, ESM, and type declaration outputs.
|
|
177
|
+
Compiles with TypeScript, producing CJS, ESM, and type declaration outputs. The
|
|
178
|
+
ESM build must never contain `require()` calls — use `await import()` for
|
|
179
|
+
optional/platform-specific modules.
|
|
149
180
|
|
|
150
181
|
## KeyManager Safety
|
|
151
182
|
|
|
@@ -153,13 +184,6 @@ Compiles with TypeScript, producing CJS, ESM, and type declaration outputs.
|
|
|
153
184
|
- `restoreIdentityFromBackup()` treats keychain-read exceptions as transient — never clobbers a healthy-but-locked primary. Rejects mismatched backups (dual mismatch guards).
|
|
154
185
|
- `deleteIdentity(skipBackup=false, force=false, userConfirmed=false)` — `force=true` also deletes the backup slot.
|
|
155
186
|
|
|
156
|
-
## FedCM (`OxyServices.fedcm.ts`)
|
|
157
|
-
|
|
158
|
-
- Use W3C-spec `mode` enum: `'active'` / `'passive'`. Do NOT use legacy `'button'` / `'widget'` (Chrome throws TypeError).
|
|
159
|
-
- Client sends `'active'` first, transparently retries with legacy value for Chrome 125–131 backwards compat.
|
|
160
|
-
- Token exchange requires a server-minted nonce from `POST /fedcm/nonce` — local UUID nonces are rejected.
|
|
161
|
-
- **Silent SSO guard is NOT here**: a module-level singleton in core was tried and reverted — it re-evaluates in the Metro web bundle so the guard did not hold. The guard lives in the consumer hooks (`useWebSSO` in `@oxyhq/services` and `@oxyhq/auth`) and in `WebOxyProvider`. Do NOT move it back into a core module-level singleton.
|
|
162
|
-
|
|
163
187
|
## `verifyChallenge` Token Planting
|
|
164
188
|
|
|
165
|
-
`OxyServices.verifyChallenge()`
|
|
189
|
+
`OxyServices.verifyChallenge()` plants the freshly-minted access token internally before returning. Callers do not need to plant tokens manually after `verifyChallenge` — the SDK handles it.
|