@livx.cc/native-kit 0.34.0 → 0.35.1
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 +1 -1
- package/package.json +1 -1
- package/src/core/NativeKit.ts +2 -0
- package/src/index.ts +7 -0
- package/src/modules/appleSignIn.ts +96 -0
- package/src/modules/motion.ts +4 -3
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Isomorphic native-capabilities kit for PWAs — the **same API in the browser and inside an [appwrap](https://github.com/Livshitz/appwrap) native shell**. Zero dependencies.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
bun add @livx.cc/native-kit
|
|
6
|
+
bun add @livx.cc/native-kit
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
```ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livx.cc/native-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.1",
|
|
4
4
|
"description": "Isomorphic native-capabilities kit for PWAs \u2014 same API in browser and in an appwrap native shell. Zero dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Elya Livshitz",
|
package/src/core/NativeKit.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { AppwrapAdapter } from './appwrap-adapter';
|
|
|
2
2
|
import { WebAdapter } from './web-adapter';
|
|
3
3
|
import { Capability, Handshake, InvokeOptions, KIT_PROTOCOL, KitError, NativeKitAdapter, Platform, Unsubscribe } from './types';
|
|
4
4
|
import { AppModule } from '../modules/app';
|
|
5
|
+
import { AppleSignInModule } from '../modules/appleSignIn';
|
|
5
6
|
import { BackgroundTaskModule } from '../modules/backgroundTask';
|
|
6
7
|
import { BillingModule } from '../modules/billing/billing';
|
|
7
8
|
import { BiometricsModule } from '../modules/biometrics';
|
|
@@ -105,6 +106,7 @@ export class NativeKit {
|
|
|
105
106
|
public readonly updates = new UpdatesModule(this);
|
|
106
107
|
public readonly backgroundTask = new BackgroundTaskModule(this);
|
|
107
108
|
public readonly tracking = new TrackingModule(this);
|
|
109
|
+
public readonly appleSignIn = new AppleSignInModule(this);
|
|
108
110
|
|
|
109
111
|
public handshakeInfo: Handshake | null = null;
|
|
110
112
|
public options: NativeKitOptions;
|
package/src/index.ts
CHANGED
|
@@ -42,6 +42,13 @@ export type { CalendarEventOptions } from './modules/calendar';
|
|
|
42
42
|
export type { BrowserOptions } from './modules/browser';
|
|
43
43
|
export type { OAuthAuthorizeParams, OAuthResult } from './modules/oauth';
|
|
44
44
|
export type { TrackingStatus } from './modules/tracking';
|
|
45
|
+
export type {
|
|
46
|
+
AppleSignInName,
|
|
47
|
+
AppleSignInParams,
|
|
48
|
+
AppleSignInResult,
|
|
49
|
+
AppleSignInCancelled,
|
|
50
|
+
} from './modules/appleSignIn';
|
|
51
|
+
export { isAppleSignInResult } from './modules/appleSignIn';
|
|
45
52
|
export { ClientTrustedValidator, HttpValidator, HttpValidatorOptions } from './modules/billing/validators';
|
|
46
53
|
export { HttpBillingProvider, HttpBillingProviderOptions } from './modules/billing/providers';
|
|
47
54
|
export type { HeaderProvider } from './modules/billing/http';
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { NativeKit } from '../core/NativeKit';
|
|
2
|
+
import { KitError } from '../core/types';
|
|
3
|
+
|
|
4
|
+
/** The name Apple returns on the FIRST authorization per Apple ID (subsequent sign-ins omit it). */
|
|
5
|
+
export interface AppleSignInName {
|
|
6
|
+
/** Given (first) name, when provided. */
|
|
7
|
+
givenName?: string;
|
|
8
|
+
/** Family (last) name, when provided. */
|
|
9
|
+
familyName?: string;
|
|
10
|
+
/** A display name composed by the OS from the components, when provided. */
|
|
11
|
+
displayName?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** A successful native Sign in with Apple. Feed `identityToken` + `nonce` (raw) to Firebase:
|
|
15
|
+
* `signInWithCredential(OAuthProvider.credential('apple.com', { idToken: identityToken, rawNonce: nonce }))`. */
|
|
16
|
+
export interface AppleSignInResult {
|
|
17
|
+
/** The Apple identity JWT (`id_token`) — what Firebase / your backend verifies. */
|
|
18
|
+
identityToken: string;
|
|
19
|
+
/** Short-lived authorization code (for an optional server-side token exchange). */
|
|
20
|
+
authorizationCode?: string;
|
|
21
|
+
/** The RAW nonce you passed in — Apple hashed SHA256(nonce); Firebase needs the raw value back. */
|
|
22
|
+
nonce: string;
|
|
23
|
+
/** First-authorization-only profile. Apple returns name/email ONLY the first time per Apple ID —
|
|
24
|
+
* persist it on first sign-in; it is absent on every subsequent call. */
|
|
25
|
+
user?: { name?: AppleSignInName; email?: string };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Sign in resolved without a credential because the user dismissed the system sheet. */
|
|
29
|
+
export interface AppleSignInCancelled {
|
|
30
|
+
cancelled: true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface AppleSignInParams {
|
|
34
|
+
/** A RAW, cryptographically-random nonce (the caller generates it). The handler sends SHA256(nonce)
|
|
35
|
+
* to Apple and returns this raw value so you can pass it to Firebase as `rawNonce`. Required. */
|
|
36
|
+
nonce: string;
|
|
37
|
+
/** Profile scopes to request on first authorization. Default `['name', 'email']`. */
|
|
38
|
+
scopes?: Array<'name' | 'email'>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** True when an {@link AppleSignInResult} (a credential) is present (not the cancelled shape). */
|
|
42
|
+
export function isAppleSignInResult(r: AppleSignInResult | AppleSignInCancelled): r is AppleSignInResult {
|
|
43
|
+
return (r as AppleSignInCancelled).cancelled !== true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Native Sign in with Apple — iOS `ASAuthorizationController` (the system account sheet). Returns the
|
|
48
|
+
* `identityToken` (JWT) + the raw nonce DIRECTLY to JS, so a wrapped app does true-native Apple auth and
|
|
49
|
+
* hands the result to Firebase `signInWithCredential(OAuthProvider.credential('apple.com', { idToken,
|
|
50
|
+
* rawNonce }))` — no Services ID, no https Return URL, no browser redirect, no cross-origin storage.
|
|
51
|
+
*
|
|
52
|
+
* WHY (not `kit.oauth`): the web-OAuth path (`ASWebAuthenticationSession`) needs an Apple **Services ID**
|
|
53
|
+
* with a custom-scheme `redirect_uri`, which Apple rejects (Services IDs require registered https Return
|
|
54
|
+
* URLs). The native ASAuthorization flow uses the **App ID** (bundle) and returns the token directly.
|
|
55
|
+
*
|
|
56
|
+
* Provider-agnostic, like `kit.push`/`kit.oauth`: the shell owns only the device-side primitive (present
|
|
57
|
+
* the sheet, hash the nonce, hand back the token). The PWA generates the nonce and does the Firebase
|
|
58
|
+
* `signInWithCredential` exchange.
|
|
59
|
+
*
|
|
60
|
+
* Capability gating (honest):
|
|
61
|
+
* - iOS 13+: `'native'`.
|
|
62
|
+
* - Android / web / iOS < 13: `'none'` — Sign in with Apple has NO native SDK off iOS. {@link signIn}
|
|
63
|
+
* throws `UNSUPPORTED`; the PWA should fall back to its web Apple auth (Firebase popup/redirect)
|
|
64
|
+
* when `capability !== 'native'`. Branch on {@link capability}.
|
|
65
|
+
*
|
|
66
|
+
* Cancel contract: a user-dismissed sheet RESOLVES `{ cancelled: true }` (never throws) — mirrors
|
|
67
|
+
* {@link import('./scanner').ScannerModule}. Real failures reject with a {@link import('../core/types').KitError}.
|
|
68
|
+
*/
|
|
69
|
+
export class AppleSignInModule {
|
|
70
|
+
constructor(private kit: NativeKit) {}
|
|
71
|
+
|
|
72
|
+
/** `'native'` on an iOS shell · `'none'` on Android/web/iOS<13. */
|
|
73
|
+
get capability() {
|
|
74
|
+
return this.kit.capability('appleSignIn');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Present the native Sign in with Apple sheet. Resolves an {@link AppleSignInResult} on success or
|
|
79
|
+
* `{ cancelled: true }` if the user dismisses it (branch with {@link isAppleSignInResult}).
|
|
80
|
+
*
|
|
81
|
+
* The handler hashes the supplied raw `nonce` (SHA256) before sending it to Apple and returns the
|
|
82
|
+
* RAW nonce in the result so you can pass it to Firebase as `rawNonce`.
|
|
83
|
+
*
|
|
84
|
+
* Dismiss-bound — the sheet resolves only when the user completes or cancels, so there's no watchdog
|
|
85
|
+
* timeout (a deadline would abandon the request mid-handshake). Throws `UNSUPPORTED` off iOS.
|
|
86
|
+
*/
|
|
87
|
+
signIn(params: AppleSignInParams): Promise<AppleSignInResult | AppleSignInCancelled> {
|
|
88
|
+
const nonce = String(params?.nonce ?? '');
|
|
89
|
+
if (!nonce) return Promise.reject(new KitError('NATIVE_ERROR', 'appleSignIn: a raw nonce is required'));
|
|
90
|
+
if (this.capability !== 'native') {
|
|
91
|
+
return Promise.reject(new KitError('UNSUPPORTED', 'appleSignIn is iOS-only (no native Sign in with Apple off iOS)'));
|
|
92
|
+
}
|
|
93
|
+
const scopes = params.scopes ?? ['name', 'email'];
|
|
94
|
+
return this.kit.invoke('appleSignIn.signIn', { nonce, scopes }, { timeoutMs: 'none' });
|
|
95
|
+
}
|
|
96
|
+
}
|
package/src/modules/motion.ts
CHANGED
|
@@ -19,11 +19,12 @@ export class MotionModule {
|
|
|
19
19
|
return this.kit.capability('motion');
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/** Stream motion samples
|
|
23
|
-
|
|
22
|
+
/** Stream motion samples; resolves an unsubscribe once streaming starts. `opts.hz` sets the emit
|
|
23
|
+
* rate (default 10, clamped 5–60 native-side) — bump it for crisp tilt (e.g. a game asks 60). */
|
|
24
|
+
async watch(cb: (sample: MotionSample) => void, opts?: { hz?: number }): Promise<Unsubscribe> {
|
|
24
25
|
const off = this.kit.on('motion.data', (p) => cb(p as MotionSample));
|
|
25
26
|
try {
|
|
26
|
-
await this.kit.invoke('motion.start');
|
|
27
|
+
await this.kit.invoke('motion.start', opts?.hz ? { hz: opts.hz } : undefined);
|
|
27
28
|
} catch (e) {
|
|
28
29
|
off();
|
|
29
30
|
throw e;
|