@symbiote-native/apple-authentication 0.0.0-stage → 0.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.
Files changed (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +264 -2
  3. package/build/angular/apple-authentication-button/index.d.ts +12 -0
  4. package/build/angular/apple-authentication-button/index.js +98 -0
  5. package/build/angular/index.d.ts +2 -0
  6. package/build/angular/index.js +3 -0
  7. package/build/core/apple-authentication-button.d.ts +20 -0
  8. package/build/core/apple-authentication-button.js +28 -0
  9. package/build/core/apple-authentication.d.ts +34 -0
  10. package/build/core/apple-authentication.js +85 -0
  11. package/build/core/constants.d.ts +2 -0
  12. package/build/core/constants.js +3 -0
  13. package/build/core/index.d.ts +5 -0
  14. package/build/core/index.js +4 -0
  15. package/build/core/native-module.d.ts +10 -0
  16. package/build/core/native-module.js +8 -0
  17. package/build/core/types.d.ts +104 -0
  18. package/build/core/types.js +56 -0
  19. package/build/react/apple-authentication-button.d.ts +6 -0
  20. package/build/react/apple-authentication-button.js +7 -0
  21. package/build/react/index.d.ts +3 -0
  22. package/build/react/index.js +3 -0
  23. package/build/solid/apple-authentication-button.d.ts +3 -0
  24. package/build/solid/apple-authentication-button.js +4 -0
  25. package/build/solid/index.d.ts +3 -0
  26. package/build/solid/index.js +3 -0
  27. package/build/svelte/apple-authentication-button.svelte +17 -0
  28. package/build/svelte/apple-authentication-button.svelte.d.ts +4 -0
  29. package/build/svelte/index.d.ts +2 -0
  30. package/build/svelte/index.js +3 -0
  31. package/build/vue/apple-authentication-button.d.ts +3 -0
  32. package/build/vue/apple-authentication-button.js +15 -0
  33. package/build/vue/index.d.ts +3 -0
  34. package/build/vue/index.js +3 -0
  35. package/build-ngc/angular/apple-authentication-button/index.d.ts +15 -0
  36. package/build-ngc/angular/apple-authentication-button/index.js +48 -0
  37. package/build-ngc/angular/apple-authentication-button/index.js.map +1 -0
  38. package/build-ngc/angular/index.d.ts +2 -0
  39. package/build-ngc/angular/index.js +4 -0
  40. package/build-ngc/angular/index.js.map +1 -0
  41. package/build-ngc/core/apple-authentication-button.d.ts +20 -0
  42. package/build-ngc/core/apple-authentication-button.js +29 -0
  43. package/build-ngc/core/apple-authentication-button.js.map +1 -0
  44. package/build-ngc/core/apple-authentication.d.ts +34 -0
  45. package/build-ngc/core/apple-authentication.js +86 -0
  46. package/build-ngc/core/apple-authentication.js.map +1 -0
  47. package/build-ngc/core/constants.d.ts +2 -0
  48. package/build-ngc/core/constants.js +4 -0
  49. package/build-ngc/core/constants.js.map +1 -0
  50. package/build-ngc/core/index.d.ts +5 -0
  51. package/build-ngc/core/index.js +5 -0
  52. package/build-ngc/core/index.js.map +1 -0
  53. package/build-ngc/core/native-module.d.ts +10 -0
  54. package/build-ngc/core/native-module.js +9 -0
  55. package/build-ngc/core/native-module.js.map +1 -0
  56. package/build-ngc/core/types.d.ts +104 -0
  57. package/build-ngc/core/types.js +57 -0
  58. package/build-ngc/core/types.js.map +1 -0
  59. package/native-link.json +11 -0
  60. package/package.json +145 -3
  61. package/src/angular/apple-authentication-button/index.ts +36 -0
  62. package/src/angular/index.ts +28 -0
  63. package/src/core/apple-authentication-button.ts +69 -0
  64. package/src/core/apple-authentication.ts +130 -0
  65. package/src/core/constants.ts +5 -0
  66. package/src/core/index.ts +31 -0
  67. package/src/core/native-module.ts +38 -0
  68. package/src/core/types.ts +121 -0
  69. package/src/react/apple-authentication-button.ts +12 -0
  70. package/src/react/index.ts +28 -0
  71. package/src/solid/apple-authentication-button.ts +9 -0
  72. package/src/solid/index.ts +28 -0
  73. package/src/svelte/apple-authentication-button.svelte +17 -0
  74. package/src/svelte/index.ts +4 -0
  75. package/src/svelte/svelte-ambient.d.ts +3 -0
  76. package/src/svelte/svelte-compile.test-helper.ts +6 -0
  77. package/src/vue/apple-authentication-button.ts +18 -0
  78. package/src/vue/index.ts +28 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 A. Prokopenko
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 CHANGED
@@ -1,3 +1,265 @@
1
- # Temporary Holding Version
1
+ # @symbiote-native/apple-authentication
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [`expo-apple-authentication`](https://docs.expo.dev/versions/latest/sdk/apple-authentication/) for
4
+ **every** [SymbioteNative](../../README.md) adapter: React, Vue, Svelte, Solid and Angular. Sign in
5
+ with Apple, iOS only: the credential flow and the system button.
6
+
7
+ Built the same way as [`@symbiote-native/clipboard`](../clipboard)'s `ClipboardPasteButton`, an
8
+ `expo-modules-core` native view reached through `requireNativeViewManager` (see the
9
+ `symbiote-expo-native-module` project skill: why `expo-modules-core` is depended on directly and never
10
+ the `expo` meta-package, why the upstream JS is hand-ported into `core/`, and how autolinking finds the
11
+ native module). The credential flow is plain async functions in `core/`, the button is the one render function every
12
+ adapter turns into its own element.
13
+
14
+ ## Install
15
+
16
+ **New app:**
17
+
18
+ ```bash
19
+ npx @symbiote-native/cli new my-app --apple-authentication
20
+ ```
21
+
22
+ **Existing SymbioteNative app:**
23
+
24
+ ```bash
25
+ npx @symbiote-native/cli add --apple-authentication
26
+ ```
27
+
28
+ Either way: installs `@symbiote-native/apple-authentication` and wires the native autolinking automatically,
29
+ see [`@symbiote-native/cli`](../cli).
30
+
31
+ <details>
32
+ <summary>Manual install (no CLI - installing and wiring native autolinking by hand)</summary>
33
+
34
+ ```bash
35
+ npm install @symbiote-native/apple-authentication
36
+ ```
37
+
38
+ Depends on `expo-apple-authentication` and `expo-modules-core` directly (regular dependencies, pinned to exact
39
+ versions, since this package's `core/` is hand-ported against one specific native API shape).
40
+ Never install `expo-apple-authentication` yourself, and never add the `expo` package to this project: it bundles
41
+ its own Metro/Babel pipeline that conflicts with this project's own.
42
+
43
+ ### Required one-time step: native autolinking wiring
44
+
45
+ `expo-apple-authentication`'s native code is discovered by `expo-modules-autolinking`, not by RN's own
46
+ `react-native.config.cjs` mechanism. Wire it into the native host app **once**, it covers this package
47
+ and every other `expo-modules-core` package with zero further changes. The steps and the
48
+ mechanics behind them are in the `symbiote-expo-native-module` skill and in
49
+ [`@symbiote-native/network`](../network)'s README; the reference app is `examples/expo-react`.
50
+
51
+ ### Entitlement and Info.plist
52
+
53
+ The package declares what `expo-apple-authentication`'s config plugin adds, and the `expo-modules-link`
54
+ postinstall writes it into the app:
55
+
56
+ | File | Entry |
57
+ | ------------------ | -------------------------------------------------------------- |
58
+ | `Info.plist` | `CFBundleAllowMixedLocalizations = true`, for the localized button |
59
+ | `*.entitlements` | `com.apple.developer.applesignin = ['Default']` |
60
+
61
+ When the app has no `*.entitlements` file the postinstall creates `<App>/<App>.entitlements` next to
62
+ `Info.plist` and wires it into the Xcode project. Pick a signing Team in Xcode once; Sign in with
63
+ Apple does not work without one.
64
+
65
+ </details>
66
+
67
+ ## Shape
68
+
69
+ ```
70
+ src/core/ apple-authentication.ts - isAvailableAsync, signInAsync, refreshAsync,
71
+ signOutAsync, getCredentialStateAsync, formatFullName, addRevokeListener over
72
+ requireOptionalNativeModule with a stub. apple-authentication-button.ts - the
73
+ button descriptor. types.ts - enums and credential types.
74
+ src/react/ @symbiote-native/apple-authentication/react - AppleAuthenticationButton
75
+ src/vue/ @symbiote-native/apple-authentication/vue - AppleAuthenticationButton
76
+ src/svelte/ @symbiote-native/apple-authentication/svelte - AppleAuthenticationButton
77
+ src/solid/ @symbiote-native/apple-authentication/solid - AppleAuthenticationButton
78
+ src/angular/ @symbiote-native/apple-authentication/angular - AppleAuthenticationButton
79
+ ```
80
+
81
+ The functions and the enums are the same on every adapter, they live in the shared core. Off iOS the
82
+ native module is missing, so the functions throw `UnavailabilityError` instead of crashing at import.
83
+
84
+ ## Use it
85
+
86
+ ### React
87
+
88
+ ```tsx
89
+ import {
90
+ AppleAuthenticationButton,
91
+ AppleAuthenticationButtonStyle,
92
+ AppleAuthenticationButtonType,
93
+ signInAsync,
94
+ } from '@symbiote-native/apple-authentication/react';
95
+
96
+ <AppleAuthenticationButton
97
+ buttonType={AppleAuthenticationButtonType.SIGN_IN}
98
+ buttonStyle={AppleAuthenticationButtonStyle.BLACK}
99
+ cornerRadius={8}
100
+ style={{ width: 200, height: 44 }}
101
+ onPress={() => signInAsync()}
102
+ />;
103
+ ```
104
+
105
+ ### Vue
106
+
107
+ ```vue
108
+ <script setup lang="ts">
109
+ import {
110
+ AppleAuthenticationButton,
111
+ AppleAuthenticationButtonStyle,
112
+ AppleAuthenticationButtonType,
113
+ signInAsync,
114
+ } from '@symbiote-native/apple-authentication/vue';
115
+ </script>
116
+
117
+ <template>
118
+ <AppleAuthenticationButton
119
+ :button-type="AppleAuthenticationButtonType.SIGN_IN"
120
+ :button-style="AppleAuthenticationButtonStyle.BLACK"
121
+ :corner-radius="8"
122
+ :style="{ width: 200, height: 44 }"
123
+ :on-press="() => signInAsync()"
124
+ />
125
+ </template>
126
+ ```
127
+
128
+ ### Angular
129
+
130
+ ```ts
131
+ import {
132
+ AppleAuthenticationButton,
133
+ AppleAuthenticationButtonStyle,
134
+ AppleAuthenticationButtonType,
135
+ signInAsync,
136
+ } from '@symbiote-native/apple-authentication/angular';
137
+
138
+ @Component({
139
+ imports: [AppleAuthenticationButton],
140
+ template: `
141
+ <AppleAuthenticationButton
142
+ [buttonType]="type"
143
+ [buttonStyle]="style"
144
+ [cornerRadius]="8"
145
+ [onPress]="signIn"
146
+ />
147
+ `,
148
+ })
149
+ export class SignIn {
150
+ readonly type = AppleAuthenticationButtonType.SIGN_IN;
151
+ readonly style = AppleAuthenticationButtonStyle.BLACK;
152
+ readonly signIn = () => signInAsync();
153
+ }
154
+ ```
155
+
156
+ ### Svelte
157
+
158
+ ```svelte
159
+ <script lang="ts">
160
+ import {
161
+ AppleAuthenticationButton,
162
+ AppleAuthenticationButtonStyle,
163
+ AppleAuthenticationButtonType,
164
+ signInAsync,
165
+ } from '@symbiote-native/apple-authentication/svelte';
166
+ </script>
167
+
168
+ <AppleAuthenticationButton
169
+ buttonType={AppleAuthenticationButtonType.SIGN_IN}
170
+ buttonStyle={AppleAuthenticationButtonStyle.BLACK}
171
+ cornerRadius={8}
172
+ style={{ width: 200, height: 44 }}
173
+ onPress={() => signInAsync()}
174
+ />
175
+ ```
176
+
177
+ ### Solid
178
+
179
+ ```tsx
180
+ import {
181
+ AppleAuthenticationButton,
182
+ AppleAuthenticationButtonStyle,
183
+ AppleAuthenticationButtonType,
184
+ signInAsync,
185
+ } from '@symbiote-native/apple-authentication/solid';
186
+
187
+ <AppleAuthenticationButton
188
+ buttonType={AppleAuthenticationButtonType.SIGN_IN}
189
+ buttonStyle={AppleAuthenticationButtonStyle.BLACK}
190
+ cornerRadius={8}
191
+ style={{ width: 200, height: 44 }}
192
+ onPress={() => signInAsync()}
193
+ />;
194
+ ```
195
+
196
+ ## API
197
+
198
+ ```ts
199
+ isAvailableAsync(): Promise<boolean> // false off iOS
200
+ signInAsync(options?): Promise<AppleAuthenticationCredential> // rejects ERR_REQUEST_CANCELED on cancel
201
+ refreshAsync(options): Promise<AppleAuthenticationCredential>
202
+ signOutAsync(options): Promise<AppleAuthenticationCredential>
203
+ getCredentialStateAsync(user): Promise<AppleAuthenticationCredentialState> // not on the Simulator
204
+ formatFullName(fullName, formatStyle?): string
205
+ addRevokeListener(listener): EventSubscription
206
+
207
+ <AppleAuthenticationButton onPress buttonType buttonStyle cornerRadius? style? /> // needs width and height
208
+ ```
209
+
210
+ Plus the `AppleAuthenticationScope`, `AppleAuthenticationButtonType`, `AppleAuthenticationButtonStyle`,
211
+ `AppleAuthenticationOperation` and `AppleAuthenticationCredentialState` enums and the `I`-prefixed
212
+ credential types, hand-ported from upstream's `AppleAuthentication.types.ts`.
213
+
214
+ ## Notes
215
+
216
+ - **iOS only.** Off iOS `isAvailableAsync()` resolves `false`, every other function throws
217
+ `UnavailabilityError`, and the button renders nothing with a warning in development. Gate the
218
+ button on `isAvailableAsync()`.
219
+ - **Cancelling is an error with a code.** `signInAsync` and `refreshAsync` reject with
220
+ `ERR_REQUEST_CANCELED` when the user dismisses the sheet. Any other code is a real failure.
221
+ - **A credential without tokens is a failure.** If the result lacks `authorizationCode`,
222
+ `identityToken` or `user`, the call rejects with `ERR_REQUEST_FAILED`, so a resolved credential is
223
+ always usable.
224
+ - **Name and email arrive once.** Apple returns `fullName` and `email` only the first time a user
225
+ signs in to your app, and only for the scopes you requested. Store them when you get them, for
226
+ example with [`@symbiote-native/secure-store`](/docs/packages/secure-store/) or on your server.
227
+ - **The button label is drawn by iOS.** You pick `buttonType` and `buttonStyle`, the text follows the
228
+ app's localization, and the package sets `CFBundleAllowMixedLocalizations` for it.
229
+ - **Not ported.** Nothing: the web build and the config plugin itself are replaced by the manifest above. Upstream ships no tests, so the suites here are written against its behavior.
230
+
231
+ ## Common questions
232
+
233
+ - **The button does not show up.** Give it a width and a height and render it only when
234
+ `isAvailableAsync()` resolves `true`. Check the entitlement and the signing Team.
235
+ - **Spins forever on the Simulator.** An Apple simulator bug, test on a real device.
236
+ `getCredentialStateAsync` always throws on the simulator.
237
+ - **`ERR_REQUEST_FAILED` with error 1000 on a device.** Enable the capability for the App ID,
238
+ regenerate the provisioning profile, select a Team, keep `com.apple.developer.applesignin` in the
239
+ entitlements.
240
+ - **Cancel or failure.** A cancel rejects with `ERR_REQUEST_CANCELED`, anything else is a failure.
241
+ - **`fullName` and `email` are `null` the second time.** Apple returns them only on the first sign
242
+ in, store them.
243
+ - **Button text.** Drawn by iOS from the app's localizations, not settable from JavaScript.
244
+ - **Firebase `aud` mismatch.** `host.exp.Exponent` only appears in Expo Go. Builds use your own
245
+ bundle identifier.
246
+ - **Android and web.** Not supported, the functions throw `UnavailabilityError`.
247
+
248
+ Sources: [Expo docs: AppleAuthentication](https://docs.expo.dev/versions/latest/sdk/apple-authentication/),
249
+ [expo/expo#11476](https://github.com/expo/expo/issues/11476),
250
+ [expo/expo#5781](https://github.com/expo/expo/issues/5781),
251
+ [expo/expo#8341](https://github.com/expo/expo/issues/8341),
252
+ [expo/expo#5690](https://github.com/expo/expo/issues/5690),
253
+ [expo/expo#7129](https://github.com/expo/expo/issues/7129),
254
+ [expo/expo#16162](https://github.com/expo/expo/issues/16162).
255
+
256
+ ## Test it
257
+
258
+ No device is needed for the logic. The core tests (`src/core/*.test.ts`) replace `expo-modules-core`
259
+ (the native module and `requireNativeViewManager`) and assert the descriptor a render function returns. The
260
+ adapter tests (`src/{react,vue,solid,angular}/**/*.test.*`, `vitest`) render the real component over the
261
+ recording Fabric with an injected view config and assert the committed payload, and Svelte's
262
+ `*.smoke.test.ts` compile the `.svelte` files and mount them. Painting itself is verified on a device in
263
+ the six `examples/expo-*` canary apps (`examples/expo-react`, `examples/expo-vue-sfc`,
264
+ `examples/expo-vue-tsx`, `examples/expo-svelte`, `examples/expo-solid`, `examples/expo-angular`), see the
265
+ parent [README](../../README.md).
@@ -0,0 +1,12 @@
1
+ import { NativeViewBase } from '@symbiote-native/angular';
2
+ import type { IDescriptor } from '@symbiote-native/components';
3
+ import type { IAppleAuthenticationButtonProps } from '../../core/apple-authentication-button';
4
+ /** Angular twin of `expo-apple-authentication`'s `AppleAuthenticationButton`, iOS only */
5
+ export declare class AppleAuthenticationButton extends NativeViewBase {
6
+ onPress: IAppleAuthenticationButtonProps['onPress'];
7
+ buttonType: IAppleAuthenticationButtonProps['buttonType'];
8
+ buttonStyle: IAppleAuthenticationButtonProps['buttonStyle'];
9
+ cornerRadius?: IAppleAuthenticationButtonProps['cornerRadius'];
10
+ protected readonly propNames: readonly ["onPress", "buttonType", "buttonStyle", "cornerRadius"];
11
+ protected renderView(props: object): IDescriptor | null;
12
+ }
@@ -0,0 +1,98 @@
1
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
3
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
4
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
5
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
6
+ var _, done = false;
7
+ for (var i = decorators.length - 1; i >= 0; i--) {
8
+ var context = {};
9
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
10
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
11
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
12
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
13
+ if (kind === "accessor") {
14
+ if (result === void 0) continue;
15
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
16
+ if (_ = accept(result.get)) descriptor.get = _;
17
+ if (_ = accept(result.set)) descriptor.set = _;
18
+ if (_ = accept(result.init)) initializers.unshift(_);
19
+ }
20
+ else if (_ = accept(result)) {
21
+ if (kind === "field") initializers.unshift(_);
22
+ else descriptor[key] = _;
23
+ }
24
+ }
25
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
26
+ done = true;
27
+ };
28
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
29
+ var useValue = arguments.length > 2;
30
+ for (var i = 0; i < initializers.length; i++) {
31
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
32
+ }
33
+ return useValue ? value : void 0;
34
+ };
35
+ import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
36
+ import { DescriptorOutlet, NativeViewBase } from '@symbiote-native/angular';
37
+ import { renderAppleAuthenticationButton } from '../../core/apple-authentication-button.js';
38
+ /** Angular twin of `expo-apple-authentication`'s `AppleAuthenticationButton`, iOS only */
39
+ let AppleAuthenticationButton = (() => {
40
+ let _classDecorators = [Component({
41
+ selector: 'AppleAuthenticationButton',
42
+ standalone: true,
43
+ imports: [DescriptorOutlet],
44
+ changeDetection: ChangeDetectionStrategy.OnPush,
45
+ template: `@if (descriptor; as node) {
46
+ <symbiote-descriptor-outlet [node]="node" />
47
+ }`,
48
+ })];
49
+ let _classDescriptor;
50
+ let _classExtraInitializers = [];
51
+ let _classThis;
52
+ let _classSuper = NativeViewBase;
53
+ let _onPress_decorators;
54
+ let _onPress_initializers = [];
55
+ let _onPress_extraInitializers = [];
56
+ let _buttonType_decorators;
57
+ let _buttonType_initializers = [];
58
+ let _buttonType_extraInitializers = [];
59
+ let _buttonStyle_decorators;
60
+ let _buttonStyle_initializers = [];
61
+ let _buttonStyle_extraInitializers = [];
62
+ let _cornerRadius_decorators;
63
+ let _cornerRadius_initializers = [];
64
+ let _cornerRadius_extraInitializers = [];
65
+ var AppleAuthenticationButton = class extends _classSuper {
66
+ static { _classThis = this; }
67
+ static {
68
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
69
+ _onPress_decorators = [Input({ required: true })];
70
+ _buttonType_decorators = [Input({ required: true })];
71
+ _buttonStyle_decorators = [Input({ required: true })];
72
+ _cornerRadius_decorators = [Input()];
73
+ __esDecorate(null, null, _onPress_decorators, { kind: "field", name: "onPress", static: false, private: false, access: { has: obj => "onPress" in obj, get: obj => obj.onPress, set: (obj, value) => { obj.onPress = value; } }, metadata: _metadata }, _onPress_initializers, _onPress_extraInitializers);
74
+ __esDecorate(null, null, _buttonType_decorators, { kind: "field", name: "buttonType", static: false, private: false, access: { has: obj => "buttonType" in obj, get: obj => obj.buttonType, set: (obj, value) => { obj.buttonType = value; } }, metadata: _metadata }, _buttonType_initializers, _buttonType_extraInitializers);
75
+ __esDecorate(null, null, _buttonStyle_decorators, { kind: "field", name: "buttonStyle", static: false, private: false, access: { has: obj => "buttonStyle" in obj, get: obj => obj.buttonStyle, set: (obj, value) => { obj.buttonStyle = value; } }, metadata: _metadata }, _buttonStyle_initializers, _buttonStyle_extraInitializers);
76
+ __esDecorate(null, null, _cornerRadius_decorators, { kind: "field", name: "cornerRadius", static: false, private: false, access: { has: obj => "cornerRadius" in obj, get: obj => obj.cornerRadius, set: (obj, value) => { obj.cornerRadius = value; } }, metadata: _metadata }, _cornerRadius_initializers, _cornerRadius_extraInitializers);
77
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
78
+ AppleAuthenticationButton = _classThis = _classDescriptor.value;
79
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
80
+ __runInitializers(_classThis, _classExtraInitializers);
81
+ }
82
+ onPress = __runInitializers(this, _onPress_initializers, void 0);
83
+ buttonType = (__runInitializers(this, _onPress_extraInitializers), __runInitializers(this, _buttonType_initializers, void 0));
84
+ buttonStyle = (__runInitializers(this, _buttonType_extraInitializers), __runInitializers(this, _buttonStyle_initializers, void 0));
85
+ cornerRadius = (__runInitializers(this, _buttonStyle_extraInitializers), __runInitializers(this, _cornerRadius_initializers, void 0));
86
+ propNames = (__runInitializers(this, _cornerRadius_extraInitializers), [
87
+ 'onPress',
88
+ 'buttonType',
89
+ 'buttonStyle',
90
+ 'cornerRadius',
91
+ ]);
92
+ renderView(props) {
93
+ return renderAppleAuthenticationButton(props);
94
+ }
95
+ };
96
+ return AppleAuthenticationButton = _classThis;
97
+ })();
98
+ export { AppleAuthenticationButton };
@@ -0,0 +1,2 @@
1
+ export { AppleAuthenticationButton } from './apple-authentication-button';
2
+ export { APPLE_AUTHENTICATION_MODULE_NAME, AppleAuthenticationButtonStyle, AppleAuthenticationButtonType, AppleAuthenticationCredentialState, AppleAuthenticationOperation, AppleAuthenticationScope, AppleAuthenticationUserDetectionStatus, addRevokeListener, appleAuthenticationButtonViewName, formatFullName, getCredentialStateAsync, isAvailableAsync, refreshAsync, signInAsync, signOutAsync, type EventSubscription, type IAppleAuthenticationButtonProps, type IAppleAuthenticationCredential, type IAppleAuthenticationFullName, type IAppleAuthenticationFullNameFormatStyle, type IAppleAuthenticationRefreshOptions, type IAppleAuthenticationSignInOptions, type IAppleAuthenticationSignOutOptions, } from '../core';
@@ -0,0 +1,3 @@
1
+ // @symbiote-native/apple-authentication/angular: кнопка и поток входа на общем ядре
2
+ export { AppleAuthenticationButton } from './apple-authentication-button/index.js';
3
+ export { APPLE_AUTHENTICATION_MODULE_NAME, AppleAuthenticationButtonStyle, AppleAuthenticationButtonType, AppleAuthenticationCredentialState, AppleAuthenticationOperation, AppleAuthenticationScope, AppleAuthenticationUserDetectionStatus, addRevokeListener, appleAuthenticationButtonViewName, formatFullName, getCredentialStateAsync, isAvailableAsync, refreshAsync, signInAsync, signOutAsync, } from '../core/index.js';
@@ -0,0 +1,20 @@
1
+ import type { IAccessibilityProps, IAriaProps, IDescriptor, IResponderProps } from '@symbiote-native/components';
2
+ import type { IStyleProp, ISymbioteEvent, IViewStyle } from '@symbiote-native/engine';
3
+ import type { AppleAuthenticationButtonStyle, AppleAuthenticationButtonType } from './types';
4
+ export type IAppleAuthenticationButtonProps = IAccessibilityProps & IAriaProps & IResponderProps & {
5
+ /** Call `signInAsync` in here */
6
+ onPress: () => void;
7
+ buttonType: AppleAuthenticationButtonType;
8
+ buttonStyle: AppleAuthenticationButtonStyle;
9
+ /** Works like `style.borderRadius` of a View */
10
+ cornerRadius?: number;
11
+ /** Needs a width and a height, or the button does not appear */
12
+ style?: IStyleProp<Omit<IViewStyle, 'backgroundColor' | 'borderRadius'>>;
13
+ testID?: string;
14
+ nativeID?: string;
15
+ onLayout?: (event: ISymbioteEvent) => void;
16
+ };
17
+ export declare const appleAuthenticationButtonViewName: () => string;
18
+ export declare function ensureAppleAuthenticationButtonRegistered(): boolean;
19
+ /** `null` means the caller renders nothing, the system button exists only on iOS */
20
+ export declare function renderAppleAuthenticationButton(props: object): IDescriptor | null;
@@ -0,0 +1,28 @@
1
+ // Ядро `AppleAuthenticationButton`: нативный view системной кнопки Sign in with Apple, только iOS
2
+ import { Platform, requireNativeViewManager } from 'expo-modules-core';
3
+ import { el } from '@symbiote-native/components';
4
+ import { defineExpoNativeView, isDevBuild } from '@symbiote-native/engine';
5
+ import { APPLE_AUTHENTICATION_MODULE_NAME } from './constants.js';
6
+ const PRESS_EVENT_PROP = 'onButtonPress';
7
+ // Регистрация идёт при рендере: побочный эффект барреля теряется в release
8
+ const buttonView = defineExpoNativeView(requireNativeViewManager, APPLE_AUTHENTICATION_MODULE_NAME);
9
+ export const appleAuthenticationButtonViewName = buttonView.name;
10
+ export function ensureAppleAuthenticationButtonRegistered() {
11
+ if (!Platform.select({ ios: true, default: false }))
12
+ return false;
13
+ return buttonView.ensureRegistered();
14
+ }
15
+ /** `null` means the caller renders nothing, the system button exists only on iOS */
16
+ export function renderAppleAuthenticationButton(props) {
17
+ if (!ensureAppleAuthenticationButtonRegistered()) {
18
+ if (isDevBuild()) {
19
+ console.warn("'AppleAuthenticationButton' is not available.");
20
+ }
21
+ return null;
22
+ }
23
+ const { onPress, ...viewProps } = Object.fromEntries(Object.entries(props));
24
+ return el(appleAuthenticationButtonViewName(), {
25
+ ...viewProps,
26
+ [PRESS_EVENT_PROP]: onPress,
27
+ });
28
+ }
@@ -0,0 +1,34 @@
1
+ import type { EventSubscription } from 'expo-modules-core';
2
+ import type { AppleAuthenticationCredentialState, IAppleAuthenticationCredential, IAppleAuthenticationFullName, IAppleAuthenticationFullNameFormatStyle, IAppleAuthenticationRefreshOptions, IAppleAuthenticationSignInOptions, IAppleAuthenticationSignOutOptions } from './types';
3
+ /**
4
+ * Whether the device's operating system supports Apple authentication
5
+ * @returns `true` when the system supports it, `false` otherwise
6
+ */
7
+ export declare function isAvailableAsync(): Promise<boolean>;
8
+ /**
9
+ * Starts the Apple authentication flow, which presents a modal over the app
10
+ * The credential carries the name and email only the first time a user signs in, store it
11
+ * @returns The credential, rejects with `ERR_REQUEST_CANCELED` when the user cancels
12
+ */
13
+ export declare function signInAsync(options?: IAppleAuthenticationSignInOptions): Promise<IAppleAuthenticationCredential>;
14
+ /**
15
+ * Refreshes the credentials of the logged-in user, the sign in modal shows first
16
+ * @returns The credential, rejects with `ERR_REQUEST_CANCELED` when the user cancels
17
+ */
18
+ export declare function refreshAsync(options: IAppleAuthenticationRefreshOptions): Promise<IAppleAuthenticationCredential>;
19
+ /**
20
+ * Ends the authenticated session, the sign in modal shows first
21
+ * Clearing the stored user data after `signInAsync` is the recommended way to sign out
22
+ * @returns The credential, rejects with `ERR_REQUEST_CANCELED` when the user cancels
23
+ */
24
+ export declare function signOutAsync(options: IAppleAuthenticationSignOutOptions): Promise<IAppleAuthenticationCredential>;
25
+ /**
26
+ * Whether the credential of a user is still valid or was revoked
27
+ * On the iOS simulator it always throws, test on a real device
28
+ * @param user The `user` field of an `IAppleAuthenticationCredential`
29
+ */
30
+ export declare function getCredentialStateAsync(user: string): Promise<AppleAuthenticationCredentialState>;
31
+ /** A locale-aware string of a person's name built from its tokenized portions */
32
+ export declare function formatFullName(fullName: IAppleAuthenticationFullName, formatStyle?: IAppleAuthenticationFullNameFormatStyle): string;
33
+ /** Calls the listener when the user revokes the credential of the app in the system settings */
34
+ export declare function addRevokeListener(listener: () => void): EventSubscription;
@@ -0,0 +1,85 @@
1
+ import { CodedError, UnavailabilityError } from 'expo-modules-core';
2
+ import { REVOKE_EVENT_NAME } from './constants.js';
3
+ import { expoAppleAuthentication } from './native-module.js';
4
+ import { AppleAuthenticationOperation } from './types.js';
5
+ const NATIVE_MODULE_NAME = 'expo-apple-authentication';
6
+ // Сообщение ссылается на имя вызванной функции, поэтому оно приходит параметром
7
+ async function requestCredential(functionName, request) {
8
+ if (!expoAppleAuthentication.requestAsync) {
9
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, functionName);
10
+ }
11
+ return expoAppleAuthentication.requestAsync(request);
12
+ }
13
+ // Вход и обновление возвращают токены, без них учётные данные бесполезны
14
+ async function requestCompleteCredential(functionName, request) {
15
+ const credential = await requestCredential(functionName, request);
16
+ if (!credential.authorizationCode ||
17
+ !credential.identityToken ||
18
+ !credential.user) {
19
+ throw new CodedError('ERR_REQUEST_FAILED', `The credential returned by \`${functionName}\` is missing one or more required fields.`);
20
+ }
21
+ return credential;
22
+ }
23
+ /**
24
+ * Whether the device's operating system supports Apple authentication
25
+ * @returns `true` when the system supports it, `false` otherwise
26
+ */
27
+ export async function isAvailableAsync() {
28
+ if (!expoAppleAuthentication.isAvailableAsync)
29
+ return false;
30
+ return expoAppleAuthentication.isAvailableAsync();
31
+ }
32
+ /**
33
+ * Starts the Apple authentication flow, which presents a modal over the app
34
+ * The credential carries the name and email only the first time a user signs in, store it
35
+ * @returns The credential, rejects with `ERR_REQUEST_CANCELED` when the user cancels
36
+ */
37
+ export async function signInAsync(options) {
38
+ return requestCompleteCredential('signInAsync', {
39
+ ...options,
40
+ requestedOperation: AppleAuthenticationOperation.LOGIN,
41
+ });
42
+ }
43
+ /**
44
+ * Refreshes the credentials of the logged-in user, the sign in modal shows first
45
+ * @returns The credential, rejects with `ERR_REQUEST_CANCELED` when the user cancels
46
+ */
47
+ export async function refreshAsync(options) {
48
+ return requestCompleteCredential('refreshAsync', {
49
+ ...options,
50
+ requestedOperation: AppleAuthenticationOperation.REFRESH,
51
+ });
52
+ }
53
+ /**
54
+ * Ends the authenticated session, the sign in modal shows first
55
+ * Clearing the stored user data after `signInAsync` is the recommended way to sign out
56
+ * @returns The credential, rejects with `ERR_REQUEST_CANCELED` when the user cancels
57
+ */
58
+ export async function signOutAsync(options) {
59
+ return requestCredential('signOutAsync', {
60
+ ...options,
61
+ requestedOperation: AppleAuthenticationOperation.LOGOUT,
62
+ });
63
+ }
64
+ /**
65
+ * Whether the credential of a user is still valid or was revoked
66
+ * On the iOS simulator it always throws, test on a real device
67
+ * @param user The `user` field of an `IAppleAuthenticationCredential`
68
+ */
69
+ export async function getCredentialStateAsync(user) {
70
+ if (!expoAppleAuthentication.getCredentialStateAsync) {
71
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getCredentialStateAsync');
72
+ }
73
+ return expoAppleAuthentication.getCredentialStateAsync(user);
74
+ }
75
+ /** A locale-aware string of a person's name built from its tokenized portions */
76
+ export function formatFullName(fullName, formatStyle) {
77
+ if (!expoAppleAuthentication.formatFullName) {
78
+ throw new UnavailabilityError(NATIVE_MODULE_NAME, 'formatFullName');
79
+ }
80
+ return expoAppleAuthentication.formatFullName(fullName, formatStyle);
81
+ }
82
+ /** Calls the listener when the user revokes the credential of the app in the system settings */
83
+ export function addRevokeListener(listener) {
84
+ return expoAppleAuthentication.addListener(REVOKE_EVENT_NAME, listener);
85
+ }
@@ -0,0 +1,2 @@
1
+ export declare const APPLE_AUTHENTICATION_MODULE_NAME = "ExpoAppleAuthentication";
2
+ export declare const REVOKE_EVENT_NAME = "Expo.appleIdCredentialRevoked";
@@ -0,0 +1,3 @@
1
+ // Отдельно от `native-module`: оно резолвит нативный модуль при импорте, а имя нужно и view
2
+ export const APPLE_AUTHENTICATION_MODULE_NAME = 'ExpoAppleAuthentication';
3
+ export const REVOKE_EVENT_NAME = 'Expo.appleIdCredentialRevoked';
@@ -0,0 +1,5 @@
1
+ export { addRevokeListener, formatFullName, getCredentialStateAsync, isAvailableAsync, refreshAsync, signInAsync, signOutAsync, } from './apple-authentication';
2
+ export { appleAuthenticationButtonViewName, ensureAppleAuthenticationButtonRegistered, renderAppleAuthenticationButton, type IAppleAuthenticationButtonProps, } from './apple-authentication-button';
3
+ export { APPLE_AUTHENTICATION_MODULE_NAME } from './constants';
4
+ export { AppleAuthenticationButtonStyle, AppleAuthenticationButtonType, AppleAuthenticationCredentialState, AppleAuthenticationOperation, AppleAuthenticationScope, AppleAuthenticationUserDetectionStatus, type IAppleAuthenticationCredential, type IAppleAuthenticationFullName, type IAppleAuthenticationFullNameFormatStyle, type IAppleAuthenticationRefreshOptions, type IAppleAuthenticationSignInOptions, type IAppleAuthenticationSignOutOptions, } from './types';
5
+ export type { EventSubscription } from 'expo-modules-core';
@@ -0,0 +1,4 @@
1
+ export { addRevokeListener, formatFullName, getCredentialStateAsync, isAvailableAsync, refreshAsync, signInAsync, signOutAsync, } from './apple-authentication.js';
2
+ export { appleAuthenticationButtonViewName, ensureAppleAuthenticationButtonRegistered, renderAppleAuthenticationButton, } from './apple-authentication-button.js';
3
+ export { APPLE_AUTHENTICATION_MODULE_NAME } from './constants.js';
4
+ export { AppleAuthenticationButtonStyle, AppleAuthenticationButtonType, AppleAuthenticationCredentialState, AppleAuthenticationOperation, AppleAuthenticationScope, AppleAuthenticationUserDetectionStatus, } from './types.js';
@@ -0,0 +1,10 @@
1
+ import type { EventSubscription } from 'expo-modules-core';
2
+ import type { IAppleAuthenticationCredential, IAppleAuthenticationFullName, IAppleAuthenticationFullNameFormatStyle, IAppleAuthenticationRequest, AppleAuthenticationCredentialState } from './types';
3
+ export type INativeAppleAuthenticationModule = {
4
+ addListener(eventName: string, listener: () => void): EventSubscription;
5
+ isAvailableAsync?(): Promise<boolean>;
6
+ requestAsync?(options: IAppleAuthenticationRequest): Promise<IAppleAuthenticationCredential>;
7
+ getCredentialStateAsync?(user: string): Promise<AppleAuthenticationCredentialState>;
8
+ formatFullName?(fullName: IAppleAuthenticationFullName, formatStyle?: IAppleAuthenticationFullNameFormatStyle): string;
9
+ };
10
+ export declare const expoAppleAuthentication: INativeAppleAuthenticationModule;
@@ -0,0 +1,8 @@
1
+ import { requireOptionalNativeModule } from 'expo-modules-core';
2
+ import { APPLE_AUTHENTICATION_MODULE_NAME } from './constants.js';
3
+ // Вместо `null` на неподдерживаемой платформе, чтобы `isAvailableAsync` отвечал `false`
4
+ const unsupportedModule = {
5
+ isAvailableAsync: () => Promise.resolve(false),
6
+ addListener: () => ({ remove: () => undefined }),
7
+ };
8
+ export const expoAppleAuthentication = requireOptionalNativeModule(APPLE_AUTHENTICATION_MODULE_NAME) ?? unsupportedModule;