@octane-xplat/auth 0.9.0 → 0.11.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.
Files changed (76) hide show
  1. package/README.md +115 -16
  2. package/dist/native/auth/src/base64.js +17 -0
  3. package/dist/native/auth/src/hosted.js +252 -0
  4. package/dist/native/auth/src/sha256.js +141 -0
  5. package/dist/native/index.js +6 -5
  6. package/dist/native/octane-client-build.json +1 -1
  7. package/dist/native/platform/src/a11y.js +1 -0
  8. package/dist/native/platform/src/app-info.js +1 -0
  9. package/dist/native/platform/src/auth-session.js +138 -0
  10. package/dist/native/platform/src/breakpoints.tsrx.js +5 -0
  11. package/dist/native/platform/src/clipboard.js +1 -0
  12. package/dist/native/platform/src/connectivity.js +1 -0
  13. package/dist/native/platform/src/deep-links.js +1 -0
  14. package/dist/native/platform/src/device.js +3 -0
  15. package/dist/native/platform/src/index.js +17 -0
  16. package/dist/native/platform/src/lifecycle.tsrx.js +7 -0
  17. package/dist/native/platform/src/locale.js +3 -0
  18. package/dist/native/platform/src/open-url.js +1 -0
  19. package/dist/native/platform/src/random.js +38 -0
  20. package/dist/native/platform/src/safe-area.tsrx.js +4 -0
  21. package/dist/native/platform/src/screen.tsrx.js +4 -0
  22. package/dist/native/platform/src/storage.js +1 -0
  23. package/dist/native/platform/src/system-bars.js +1 -0
  24. package/dist/native/secure-storage/src/index.js +2 -0
  25. package/dist/native/secure-storage/src/secure-storage.js +17 -0
  26. package/dist/web/auth/src/base64.js +17 -0
  27. package/dist/web/auth/src/hosted.js +251 -0
  28. package/dist/web/auth/src/sha256.js +141 -0
  29. package/dist/web/index.js +6 -5
  30. package/dist/web/octane-client-build.json +1 -1
  31. package/dist/web/platform/src/app-info.web.js +3 -0
  32. package/dist/web/platform/src/auth-session.web.js +10 -0
  33. package/dist/web/platform/src/breakpoints.web.tsrx.js +7 -0
  34. package/dist/web/platform/src/clipboard.web.js +3 -0
  35. package/dist/web/platform/src/deep-links.web.js +3 -0
  36. package/dist/web/platform/src/device.web.js +2 -0
  37. package/dist/web/platform/src/host-bridge.web.js +18 -0
  38. package/dist/web/platform/src/host-protocol.js +73 -0
  39. package/dist/web/platform/src/host-runtime.web.js +76 -0
  40. package/dist/web/platform/src/index.web.js +13 -0
  41. package/dist/web/platform/src/lifecycle.web.tsrx.js +3 -0
  42. package/dist/web/platform/src/locale.web.js +10 -0
  43. package/dist/web/platform/src/random.web.js +21 -0
  44. package/dist/web/platform/src/safe-area.web.tsrx.js +3 -0
  45. package/dist/web/platform/src/screen.web.tsrx.js +3 -0
  46. package/dist/web/platform/src/webauthn.web.js +2 -0
  47. package/dist/web/secure-storage/src/secure-storage.web.js +21 -0
  48. package/package.json +11 -5
  49. package/src/AppleSignInButton.macos.tsrx +28 -30
  50. package/src/GoogleSignInButton.macos.tsrx +18 -4
  51. package/src/apple-button.macos.ts +75 -0
  52. package/src/apple.macos.ts +87 -130
  53. package/src/base64.ts +25 -0
  54. package/src/google.macos.ts +81 -14
  55. package/src/hosted.ts +392 -0
  56. package/src/index.macos.ts +17 -0
  57. package/src/index.ts +17 -0
  58. package/src/index.web.ts +17 -0
  59. package/src/sha256.ts +118 -0
  60. package/src/types.ts +216 -4
  61. package/types/generated/.tsrx-typegen-manifest.json +3 -0
  62. package/types/generated/base64.d.ts +1 -0
  63. package/types/generated/hosted.d.ts +6 -0
  64. package/types/generated/index.d.ts +2 -1
  65. package/types/generated/index.web.d.ts +2 -1
  66. package/types/generated/sha256.d.ts +4 -0
  67. package/types/generated/types.d.ts +200 -4
  68. package/types/index.macos.d.ts +40 -0
  69. /package/dist/native/{AppleSignInButton.tsrx.js → auth/src/AppleSignInButton.tsrx.js} +0 -0
  70. /package/dist/native/{GoogleSignInButton.tsrx.js → auth/src/GoogleSignInButton.tsrx.js} +0 -0
  71. /package/dist/native/{apple.js → auth/src/apple.js} +0 -0
  72. /package/dist/native/{google.js → auth/src/google.js} +0 -0
  73. /package/dist/web/{AppleSignInButton.web.tsrx.js → auth/src/AppleSignInButton.web.tsrx.js} +0 -0
  74. /package/dist/web/{GoogleSignInButton.web.tsrx.js → auth/src/GoogleSignInButton.web.tsrx.js} +0 -0
  75. /package/dist/web/{apple.web.js → auth/src/apple.web.js} +0 -0
  76. /package/dist/web/{google.web.js → auth/src/google.web.js} +0 -0
package/README.md CHANGED
@@ -1,24 +1,28 @@
1
1
  # `@octane-xplat/auth`
2
2
 
3
- Sign in with Apple and Google Sign-In for Octane xplat apps — the native
4
- SDKs (`@nativescript/apple-sign-in`, `@nativescript/google-signin`) on
5
- iOS/Android, the providers' web SDKs (Apple JS / Google Identity Services)
6
- in the browser, and AuthenticationServices through the ObjC bridge plus a
7
- Google flow on the macOS AppKit host. One `AuthUser`/`AuthCredential`
8
- contract everywhere.
9
-
10
3
  ```sh
11
4
  pnpm add @octane-xplat/auth
12
5
  ```
13
6
 
14
- ```tsx
15
- import { appleAuth, googleAuth, AppleSignInButton } from '@octane-xplat/auth'
7
+ Sign in with Apple and Google Sign-In for Octane xplat apps — the native
8
+ SDKs (`@nativescript/apple-sign-in`, `@nativescript/google-signin`) on
9
+ iOS/Android, the providers' web SDKs (Apple JS / Google Identity Services)
10
+ in the browser, and AuthenticationServices through the ObjC bridge plus a
11
+ app-configured hosted Google flow on the macOS AppKit host. One `AuthUser`/`AuthCredential`
12
+ contract everywhere. `createHostedAuth` adds a generic hosted sign-in
13
+ ceremony + Bearer session transport for apps whose backend issues and redeems
14
+ sign-in attempts.
16
15
 
17
- appleAuth.configure({ clientId: 'com.example.app.web' }) // web-only fields
16
+ ```ts
17
+ import { appleAuth } from '@octane-xplat/auth'
18
18
 
19
- const result = await appleAuth.signIn({ scopes: ['email', 'name'] })
20
- if (result.status === 'success') {
21
- const { idToken, user } = result.credential // hand idToken to your backend
19
+ appleAuth.configure({ clientId: 'com.example.app.web' })
20
+ if (appleAuth.supported) {
21
+ const result = await appleAuth.signIn({ scopes: ['email', 'name'] })
22
+ if (result.status === 'success') {
23
+ // Send this credential to your backend for verification.
24
+ const { idToken, user } = result.credential
25
+ }
22
26
  }
23
27
  ```
24
28
 
@@ -26,13 +30,108 @@ Each provider object reports `supported` — Apple is `false` on Android —
26
30
  and exposes `configure`, `signIn`, and provider extras
27
31
  (`appleAuth.getCredentialState`, `googleAuth.signOut`). `SignInResult`
28
32
  distinguishes `success` / `cancelled` / `error`; a dismissed sheet is
29
- `cancelled`, not a throw. The sign-in buttons are platform-authentic
30
- components, so render them from platform-suffixed files or accept each
33
+ `cancelled`, not a throw. Apple uses the official ASAuthorizationAppleIDButton on AppKit; Google
34
+ uses a text trigger for the hosted flow there. The other sign-in buttons are
35
+ platform-authentic components, so render them from platform-suffixed files or accept each
31
36
  target's native styling.
32
37
 
38
+ The following component belongs in an `.ios.tsx` file.
39
+
40
+ ```tsx
41
+ import { AppleSignInButton, appleAuth, googleAuth } from '@octane-xplat/auth'
42
+
43
+ export function SignIn() {
44
+ return (
45
+ <AppleSignInButton
46
+ onResult={(result) => {
47
+ if (result.status === 'success') {
48
+ void appleAuth.getCredentialState(result.credential.user.id)
49
+ }
50
+ }}
51
+ />
52
+ )
53
+ }
54
+ // When ending a Google session:
55
+ await googleAuth.signOut()
56
+ ```
57
+
33
58
  Web needs registered client IDs; iOS needs the `applesignin` entitlement
34
59
  and Google's `GoogleService-Info.plist`/reversed-client-id URL scheme;
35
60
  Android needs `google-services.json` and a `serverClientId` for
36
61
  `serverAuthCode`. Guide: [Using device
37
- features](../../docs/platform-services.md). Exercised by
62
+ features](../../docs/platform/platform-services.md). Exercised by
38
63
  [`AuthDemo`](../demos/src/AuthDemo.tsrx).
64
+
65
+ On macOS, `supported` reports AuthenticationServices availability, not completed
66
+ provider registration. Apple needs a signed app ID with Sign in with Apple
67
+ enabled and a matching provisioning profile and entitlement. Google needs
68
+ `googleAuth.configure({ hostedFlow })`, where `createRequest` starts a fresh
69
+ backend attempt and `complete` validates/redeems the captured callback on that
70
+ backend, returning `AuthCredential`. A client ID alone is insufficient on
71
+ AppKit. The adapter receives the configured client IDs, scopes, hosted domain,
72
+ and per-attempt nonce; the backend must apply and verify them.
73
+
74
+ See [macOS provider setup](../../docs/platform/platform-services.md#macos-provider-sign-in)
75
+ and the [maintained hosted adapter](../../examples/auth/google-hosted.macos.ts).
76
+
77
+ ## Hosted sign-in ceremonies
78
+
79
+ `createHostedAuth` authenticates a native app through a hosted sign-in page:
80
+ your `HostedAuthFlow` issues a PKCE-bound attempt and returns the hosted URL,
81
+ the app opens it in a system browser (`authSession` — ASWebAuthenticationSession
82
+ on iOS/macOS, Custom Tab on Android), and `complete` redeems the browser
83
+ callback. The client persists the credential record — a short-lived access
84
+ token plus a durable session credential — through
85
+ `@octane-xplat/secure-storage` (Keychain/Keystore), refreshes the access token
86
+ through the flow's `refresh`, and revokes through `revoke` on sign-out.
87
+
88
+ ```ts
89
+ import { createHostedAuth, postJson, queryParam } from '@octane-xplat/auth'
90
+
91
+ export const auth = createHostedAuth({
92
+ apiOrigin: 'https://api.example.com',
93
+ flow: {
94
+ async begin({ fetch, pkce }) {
95
+ const res = await postJson(fetch, 'https://api.example.com/oauth/attempt', {
96
+ code_challenge: pkce.challenge,
97
+ scheme: 'myapp',
98
+ })
99
+ if (!res.ok) throw new Error(`attempt rejected (${res.status})`)
100
+ const { attempt_id, state } = await res.json()
101
+ return {
102
+ url: `https://api.example.com/sign-in?attempt=${attempt_id}&state=${state}`,
103
+ callbackScheme: 'myapp',
104
+ state,
105
+ }
106
+ },
107
+ async complete(callbackUrl, attempt, { fetch, pkce }) {
108
+ const res = await postJson(fetch, 'https://api.example.com/oauth/exchange', {
109
+ code: queryParam(callbackUrl, 'code'),
110
+ code_verifier: pkce.verifier,
111
+ state: attempt.state,
112
+ })
113
+ if (!res.ok) return null
114
+ const { token, expires_at, session_token } = await res.json()
115
+ return { expiresAt: expires_at * 1000, sessionToken: session_token, token }
116
+ },
117
+ },
118
+ })
119
+
120
+ const result = await auth.signIn() // opens the hosted sign-in page
121
+ if (result.status === 'success') {
122
+ const response = await auth.fetch('/api/me') // Bearer attach + refresh-on-401
123
+ }
124
+ ```
125
+
126
+ `auth.fetch` attaches `Authorization: Bearer <access token>` to same-origin
127
+ `/api/*` paths (the `/api/auth` mount is excluded by default — override
128
+ `authorizePath` for other layouts) and replays once after a refresh when the
129
+ server answers an `invalid_token` challenge. The `callbackScheme` your flow
130
+ returns must be registered as an incoming-link scheme in the app (Android: a
131
+ manifest intent-filter) and allowlisted by your backend. On web `supported` is
132
+ `false` — browser apps keep the cookie session flow.
133
+
134
+ ```ts
135
+ const status = await auth.restore() // 'authenticated' if a session was stored
136
+ await auth.signOut() // revokes the session and clears stored credentials
137
+ ```
@@ -0,0 +1,17 @@
1
+ //#region src/base64.ts
2
+ var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
3
+ function bytesToBase64Url(bytes) {
4
+ let out = "";
5
+ for (let i = 0; i < bytes.length; i += 3) {
6
+ const a = bytes[i];
7
+ const b = i + 1 < bytes.length ? bytes[i + 1] : 0;
8
+ const c = i + 2 < bytes.length ? bytes[i + 2] : 0;
9
+ out += ALPHABET[a >> 2];
10
+ out += ALPHABET[(a & 3) << 4 | b >> 4];
11
+ if (i + 1 < bytes.length) out += ALPHABET[(b & 15) << 2 | c >> 6];
12
+ if (i + 2 < bytes.length) out += ALPHABET[c & 63];
13
+ }
14
+ return out;
15
+ }
16
+ //#endregion
17
+ export { bytesToBase64Url };
@@ -0,0 +1,252 @@
1
+ import { random } from "../../platform/src/random.js";
2
+ import { authSession } from "../../platform/src/auth-session.js";
3
+ import "../../platform/src/index.js";
4
+ import { secureStorage } from "../../secure-storage/src/secure-storage.js";
5
+ import "../../secure-storage/src/index.js";
6
+ import { bytesToBase64Url } from "./base64.js";
7
+ import { sha256, utf8Bytes } from "./sha256.js";
8
+ //#region src/hosted.ts
9
+ var DEFAULT_STORAGE_KEY = "hosted-auth";
10
+ var REFRESH_SKEW_MS = 3e4;
11
+ function createHostedAuth(config) {
12
+ const apiOrigin = normalizeOrigin(config.apiOrigin);
13
+ const authorizePath = config.authorizePath ?? defaultAuthorizePath;
14
+ const storageKey = config.storageKey ?? DEFAULT_STORAGE_KEY;
15
+ const now = config.now ?? Date.now;
16
+ const transport = config.fetch ?? ((url, init) => {
17
+ const impl = globalThis.fetch;
18
+ if (!impl) return Promise.reject(/* @__PURE__ */ new Error("hostedAuth: fetch is unavailable on this target"));
19
+ return impl(url, init);
20
+ });
21
+ let credentials;
22
+ let refreshPromise = null;
23
+ function store() {
24
+ return config.storage ?? secureStorage.impl;
25
+ }
26
+ async function persist(creds) {
27
+ credentials = creds;
28
+ const storage = store();
29
+ if (!storage) return;
30
+ try {
31
+ if (creds) await storage.set(storageKey, JSON.stringify(creds));
32
+ else await storage.remove(storageKey);
33
+ } catch {}
34
+ }
35
+ async function load() {
36
+ if (credentials !== void 0) return credentials;
37
+ const storage = store();
38
+ if (!storage) {
39
+ credentials = null;
40
+ return null;
41
+ }
42
+ try {
43
+ const raw = await storage.get(storageKey);
44
+ const parsed = raw ? parseCredentials(raw) : null;
45
+ if (credentials === void 0) credentials = parsed;
46
+ if (!parsed && raw) await storage.remove(storageKey);
47
+ } catch {
48
+ credentials ??= null;
49
+ }
50
+ return credentials ?? null;
51
+ }
52
+ async function refresh() {
53
+ const creds = await load();
54
+ if (!creds || !config.flow.refresh) return null;
55
+ const next = await config.flow.refresh(creds, { fetch: transport });
56
+ if (!isCredentials(next)) {
57
+ await persist(null);
58
+ return null;
59
+ }
60
+ await persist(next);
61
+ return next.token;
62
+ }
63
+ function refreshedAccessToken() {
64
+ refreshPromise ??= refresh().finally(() => {
65
+ refreshPromise = null;
66
+ });
67
+ return refreshPromise;
68
+ }
69
+ async function getAccessToken() {
70
+ const creds = await load();
71
+ if (!creds) return null;
72
+ if (creds.expiresAt - now() > REFRESH_SKEW_MS) return creds.token;
73
+ return refreshedAccessToken();
74
+ }
75
+ async function signIn() {
76
+ const session = config.authSession ?? {
77
+ supported: authSession.supported,
78
+ open: (url, options) => {
79
+ const impl = authSession.impl;
80
+ if (!impl) return Promise.resolve({
81
+ type: "error",
82
+ message: "hostedAuth: hosted sign-in is not supported on this target"
83
+ });
84
+ return impl.open(url, options);
85
+ }
86
+ };
87
+ if (!session.supported || !random.supported) return {
88
+ status: "error",
89
+ message: "hostedAuth: hosted sign-in is not supported on this target"
90
+ };
91
+ const verifier = bytesToBase64Url(random.bytes(32));
92
+ const pkce = {
93
+ challenge: bytesToBase64Url(sha256(utf8Bytes(verifier))),
94
+ verifier
95
+ };
96
+ let attempt;
97
+ try {
98
+ attempt = await config.flow.begin({
99
+ fetch: transport,
100
+ pkce
101
+ });
102
+ } catch (error) {
103
+ return {
104
+ status: "error",
105
+ message: errorMessage(error)
106
+ };
107
+ }
108
+ const result = await session.open(attempt.url, { callbackScheme: attempt.callbackScheme });
109
+ if (result.type === "cancel") return { status: "cancelled" };
110
+ if (result.type === "error") return {
111
+ status: "error",
112
+ message: result.message
113
+ };
114
+ if (attempt.state !== void 0 && queryParam(result.url, "state") !== attempt.state) return {
115
+ status: "error",
116
+ message: "hostedAuth: callback did not carry the expected state"
117
+ };
118
+ try {
119
+ const creds = await config.flow.complete(result.url, attempt, {
120
+ fetch: transport,
121
+ pkce
122
+ });
123
+ if (!isCredentials(creds)) return {
124
+ status: "error",
125
+ message: "hostedAuth: sign-in did not produce credentials"
126
+ };
127
+ await persist(creds);
128
+ return { status: "success" };
129
+ } catch (error) {
130
+ return {
131
+ status: "error",
132
+ message: errorMessage(error)
133
+ };
134
+ }
135
+ }
136
+ async function fetchWithAuth(url, init) {
137
+ const pathname = apiPath(url, apiOrigin);
138
+ if (pathname === null || !authorizePath(pathname)) return transport(url, init);
139
+ const target = url.startsWith("/") ? `${apiOrigin}${url}` : url;
140
+ const token = await getAccessToken();
141
+ const response = await transport(target, token === null ? init : withBearer(init, token));
142
+ if (!isInvalidAccessTokenChallenge(response.status, response.headers)) return response;
143
+ const refreshed = await refreshedAccessToken();
144
+ if (refreshed === null) return response;
145
+ return transport(target, withBearer(init, refreshed));
146
+ }
147
+ async function signOut() {
148
+ const creds = await load();
149
+ await persist(null);
150
+ if (!creds || !config.flow.revoke) return;
151
+ try {
152
+ await config.flow.revoke(creds, { fetch: transport });
153
+ } catch {}
154
+ }
155
+ return {
156
+ get supported() {
157
+ return (config.authSession?.supported ?? authSession.supported) && random.supported;
158
+ },
159
+ restore: async () => await load() ? "authenticated" : "unauthenticated",
160
+ signIn,
161
+ getAccessToken,
162
+ fetch: fetchWithAuth,
163
+ signOut
164
+ };
165
+ }
166
+ function normalizeOrigin(value) {
167
+ const trimmed = value.trim().replace(/\/+$/u, "");
168
+ if (!/^https?:\/\/[^\s/?#]+$/u.test(trimmed)) throw new TypeError(`hostedAuth: apiOrigin must be an HTTP(S) origin without path or parameters, got ${JSON.stringify(value)}`);
169
+ return trimmed;
170
+ }
171
+ /** `POST` a JSON body through the flow's transport. */
172
+ function postJson(transport, url, body) {
173
+ return transport(url, {
174
+ body: JSON.stringify(body),
175
+ headers: { "content-type": "application/json" },
176
+ method: "POST"
177
+ });
178
+ }
179
+ /** `?name=value` extraction without URLSearchParams (not in the native program). */
180
+ function queryParam(url, name) {
181
+ const start = url.indexOf("?");
182
+ if (start === -1) return null;
183
+ const query = url.slice(start + 1).split("#", 1)[0];
184
+ for (const pair of query.split("&")) {
185
+ const eq = pair.indexOf("=");
186
+ if ((eq === -1 ? pair : pair.slice(0, eq)) === name) return eq === -1 ? "" : decodeURIComponent(pair.slice(eq + 1).replaceAll("+", " "));
187
+ }
188
+ return null;
189
+ }
190
+ function isCredentials(value) {
191
+ const creds = value;
192
+ return !!creds && typeof creds.token === "string" && typeof creds.expiresAt === "number" && typeof creds.sessionToken === "string";
193
+ }
194
+ function parseCredentials(raw) {
195
+ try {
196
+ const parsed = JSON.parse(raw);
197
+ if (isCredentials(parsed)) return {
198
+ expiresAt: parsed.expiresAt,
199
+ sessionToken: parsed.sessionToken,
200
+ token: parsed.token
201
+ };
202
+ } catch {}
203
+ return null;
204
+ }
205
+ /**
206
+ * Pathname of `url` when it belongs to `apiOrigin` — `null` for other
207
+ * origins. Relative (`/path`) and origin-prefixed inputs both resolve.
208
+ */
209
+ function apiPath(url, apiOrigin) {
210
+ if (url.startsWith("//")) return null;
211
+ let path;
212
+ if (url.startsWith("/")) path = url;
213
+ else if (url.startsWith(apiOrigin + "/") || url === apiOrigin) path = url.slice(apiOrigin.length) || "/";
214
+ else return null;
215
+ const end = path.search(/[?#]/u);
216
+ return end === -1 ? path : path.slice(0, end);
217
+ }
218
+ /**
219
+ * Default `authorizePath` — every same-origin path under `/api/` except the
220
+ * `/api/auth` mount hosted backends reserve for auth endpoints.
221
+ */
222
+ function defaultAuthorizePath(pathname) {
223
+ return pathname.startsWith("/api/") && !(pathname === "/api/auth" || pathname.startsWith("/api/auth/"));
224
+ }
225
+ function withBearer(init, token) {
226
+ const headers = {};
227
+ const incoming = init?.headers;
228
+ if (incoming) {
229
+ if (Symbol.iterator in incoming) for (const [name, value] of incoming) headers[name.toLowerCase()] = value;
230
+ else for (const name of Object.keys(incoming)) headers[name.toLowerCase()] = incoming[name];
231
+ }
232
+ headers.authorization = `Bearer ${token}`;
233
+ return {
234
+ ...init,
235
+ headers
236
+ };
237
+ }
238
+ /**
239
+ * RFC 6750 `401 + WWW-Authenticate: Bearer error="invalid_token"` — the
240
+ * challenge that distinguishes a dead access token from an ordinary
241
+ * authorization failure.
242
+ */
243
+ function isInvalidAccessTokenChallenge(status, headers) {
244
+ if (status !== 401) return false;
245
+ const challenge = headers.get("www-authenticate");
246
+ return !!challenge && /error\s*=\s*"invalid_token"/iu.test(challenge);
247
+ }
248
+ function errorMessage(error) {
249
+ return error instanceof Error ? error.message : "hostedAuth: the hosted ceremony failed";
250
+ }
251
+ //#endregion
252
+ export { createHostedAuth, postJson, queryParam };
@@ -0,0 +1,141 @@
1
+ //#region src/sha256.ts
2
+ function utf8Bytes(input) {
3
+ const bytes = [];
4
+ for (let i = 0; i < input.length; i++) {
5
+ let cp = input.charCodeAt(i);
6
+ if (cp >= 55296 && cp <= 56319 && i + 1 < input.length) {
7
+ const low = input.charCodeAt(i + 1);
8
+ if (low >= 56320 && low <= 57343) {
9
+ cp = 65536 + (cp - 55296 << 10) + (low - 56320);
10
+ i++;
11
+ }
12
+ }
13
+ if (cp < 128) bytes.push(cp);
14
+ else if (cp < 2048) bytes.push(192 | cp >> 6, 128 | cp & 63);
15
+ else if (cp < 65536) bytes.push(224 | cp >> 12, 128 | cp >> 6 & 63, 128 | cp & 63);
16
+ else bytes.push(240 | cp >> 18, 128 | cp >> 12 & 63, 128 | cp >> 6 & 63, 128 | cp & 63);
17
+ }
18
+ return new Uint8Array(bytes);
19
+ }
20
+ function sha256(bytes) {
21
+ const K = new Uint32Array([
22
+ 1116352408,
23
+ 1899447441,
24
+ 3049323471,
25
+ 3921009573,
26
+ 961987163,
27
+ 1508970993,
28
+ 2453635748,
29
+ 2870763221,
30
+ 3624381080,
31
+ 310598401,
32
+ 607225278,
33
+ 1426881987,
34
+ 1925078388,
35
+ 2162078206,
36
+ 2614888103,
37
+ 3248222580,
38
+ 3835390401,
39
+ 4022224774,
40
+ 264347078,
41
+ 604807628,
42
+ 770255983,
43
+ 1249150122,
44
+ 1555081692,
45
+ 1996064986,
46
+ 2554220882,
47
+ 2821834349,
48
+ 2952996808,
49
+ 3210313671,
50
+ 3336571891,
51
+ 3584528711,
52
+ 113926993,
53
+ 338241895,
54
+ 666307205,
55
+ 773529912,
56
+ 1294757372,
57
+ 1396182291,
58
+ 1695183700,
59
+ 1986661051,
60
+ 2177026350,
61
+ 2456956037,
62
+ 2730485921,
63
+ 2820302411,
64
+ 3259730800,
65
+ 3345764771,
66
+ 3516065817,
67
+ 3600352804,
68
+ 4094571909,
69
+ 275423344,
70
+ 430227734,
71
+ 506948616,
72
+ 659060556,
73
+ 883997877,
74
+ 958139571,
75
+ 1322822218,
76
+ 1537002063,
77
+ 1747873779,
78
+ 1955562222,
79
+ 2024104815,
80
+ 2227730452,
81
+ 2361852424,
82
+ 2428436474,
83
+ 2756734187,
84
+ 3204031479,
85
+ 3329325298
86
+ ]);
87
+ const H = new Uint32Array([
88
+ 1779033703,
89
+ 3144134277,
90
+ 1013904242,
91
+ 2773480762,
92
+ 1359893119,
93
+ 2600822924,
94
+ 528734635,
95
+ 1541459225
96
+ ]);
97
+ const bitLen = bytes.length * 8;
98
+ const padded = new Uint8Array(bytes.length + 9 + 63 & -64);
99
+ padded.set(bytes);
100
+ padded[bytes.length] = 128;
101
+ const dv = new DataView(padded.buffer);
102
+ dv.setUint32(padded.length - 8, Math.floor(bitLen / 4294967296));
103
+ dv.setUint32(padded.length - 4, bitLen >>> 0);
104
+ const w = /* @__PURE__ */ new Uint32Array(64);
105
+ for (let block = 0; block < padded.length; block += 64) {
106
+ for (let t = 0; t < 16; t++) w[t] = dv.getUint32(block + t * 4);
107
+ for (let t = 16; t < 64; t++) {
108
+ const s0 = (w[t - 15] >>> 7 | w[t - 15] << 25) ^ (w[t - 15] >>> 18 | w[t - 15] << 14) ^ w[t - 15] >>> 3;
109
+ const s1 = (w[t - 2] >>> 17 | w[t - 2] << 15) ^ (w[t - 2] >>> 19 | w[t - 2] << 13) ^ w[t - 2] >>> 10;
110
+ w[t] = w[t - 16] + s0 + w[t - 7] + s1 >>> 0;
111
+ }
112
+ let [a, b, c, d, e, f, g, h] = H;
113
+ for (let t = 0; t < 64; t++) {
114
+ const S1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);
115
+ const t1 = h + S1 + (e & f ^ ~e & g) + K[t] + w[t] >>> 0;
116
+ const t2 = ((a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10)) + (a & b ^ a & c ^ b & c) >>> 0;
117
+ h = g;
118
+ g = f;
119
+ f = e;
120
+ e = d + t1 >>> 0;
121
+ d = c;
122
+ c = b;
123
+ b = a;
124
+ a = t1 + t2 >>> 0;
125
+ }
126
+ H[0] = H[0] + a >>> 0;
127
+ H[1] = H[1] + b >>> 0;
128
+ H[2] = H[2] + c >>> 0;
129
+ H[3] = H[3] + d >>> 0;
130
+ H[4] = H[4] + e >>> 0;
131
+ H[5] = H[5] + f >>> 0;
132
+ H[6] = H[6] + g >>> 0;
133
+ H[7] = H[7] + h >>> 0;
134
+ }
135
+ const digest = /* @__PURE__ */ new Uint8Array(32);
136
+ const out = new DataView(digest.buffer);
137
+ for (let i = 0; i < 8; i++) out.setUint32(i * 4, H[i]);
138
+ return digest;
139
+ }
140
+ //#endregion
141
+ export { sha256, utf8Bytes };
@@ -1,5 +1,6 @@
1
- import { appleAuth } from "./apple.js";
2
- import { googleAuth } from "./google.js";
3
- import { AppleSignInButton } from "./AppleSignInButton.tsrx.js";
4
- import { GoogleSignInButton } from "./GoogleSignInButton.tsrx.js";
5
- export { AppleSignInButton, GoogleSignInButton, appleAuth, googleAuth };
1
+ import { appleAuth } from "./auth/src/apple.js";
2
+ import { googleAuth } from "./auth/src/google.js";
3
+ import { AppleSignInButton } from "./auth/src/AppleSignInButton.tsrx.js";
4
+ import { GoogleSignInButton } from "./auth/src/GoogleSignInButton.tsrx.js";
5
+ import { createHostedAuth, postJson, queryParam } from "./auth/src/hosted.js";
6
+ export { AppleSignInButton, GoogleSignInButton, appleAuth, createHostedAuth, googleAuth, postJson, queryParam };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
- "buildId": "2924c745-ebe0-4012-9aea-c8c26eeb7458",
3
+ "buildId": "bb35374e-9484-4dd6-88c4-77050251d038",
4
4
  "mode": "production",
5
5
  "capabilities": {
6
6
  "independentHydration": false
@@ -0,0 +1 @@
1
+ import "@nativescript/core";
@@ -0,0 +1 @@
1
+ import "@nativescript/core";