@molecule/app-solid 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/LICENSE +115 -0
- package/README.md +2543 -0
- package/dist/context.d.ts +82 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +141 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/primitives/async-state.d.ts +46 -0
- package/dist/primitives/async-state.d.ts.map +1 -0
- package/dist/primitives/async-state.js +83 -0
- package/dist/primitives/async-state.js.map +1 -0
- package/dist/primitives/auth.d.ts +85 -0
- package/dist/primitives/auth.d.ts.map +1 -0
- package/dist/primitives/auth.js +147 -0
- package/dist/primitives/auth.js.map +1 -0
- package/dist/primitives/capacitor-app.d.ts +46 -0
- package/dist/primitives/capacitor-app.d.ts.map +1 -0
- package/dist/primitives/capacitor-app.js +57 -0
- package/dist/primitives/capacitor-app.js.map +1 -0
- package/dist/primitives/change-password.d.ts +36 -0
- package/dist/primitives/change-password.d.ts.map +1 -0
- package/dist/primitives/change-password.js +32 -0
- package/dist/primitives/change-password.js.map +1 -0
- package/dist/primitives/device.d.ts +48 -0
- package/dist/primitives/device.d.ts.map +1 -0
- package/dist/primitives/device.js +47 -0
- package/dist/primitives/device.js.map +1 -0
- package/dist/primitives/forms.d.ts +193 -0
- package/dist/primitives/forms.d.ts.map +1 -0
- package/dist/primitives/forms.js +309 -0
- package/dist/primitives/forms.js.map +1 -0
- package/dist/primitives/http.d.ts +176 -0
- package/dist/primitives/http.d.ts.map +1 -0
- package/dist/primitives/http.js +254 -0
- package/dist/primitives/http.js.map +1 -0
- package/dist/primitives/i18n.d.ts +146 -0
- package/dist/primitives/i18n.d.ts.map +1 -0
- package/dist/primitives/i18n.js +223 -0
- package/dist/primitives/i18n.js.map +1 -0
- package/dist/primitives/index.d.ts +27 -0
- package/dist/primitives/index.d.ts.map +1 -0
- package/dist/primitives/index.js +27 -0
- package/dist/primitives/index.js.map +1 -0
- package/dist/primitives/logger.d.ts +143 -0
- package/dist/primitives/logger.d.ts.map +1 -0
- package/dist/primitives/logger.js +165 -0
- package/dist/primitives/logger.js.map +1 -0
- package/dist/primitives/login.d.ts +37 -0
- package/dist/primitives/login.d.ts.map +1 -0
- package/dist/primitives/login.js +32 -0
- package/dist/primitives/login.js.map +1 -0
- package/dist/primitives/oauth.d.ts +102 -0
- package/dist/primitives/oauth.d.ts.map +1 -0
- package/dist/primitives/oauth.js +232 -0
- package/dist/primitives/oauth.js.map +1 -0
- package/dist/primitives/password-reset.d.ts +46 -0
- package/dist/primitives/password-reset.d.ts.map +1 -0
- package/dist/primitives/password-reset.js +49 -0
- package/dist/primitives/password-reset.js.map +1 -0
- package/dist/primitives/platform.d.ts +48 -0
- package/dist/primitives/platform.d.ts.map +1 -0
- package/dist/primitives/platform.js +47 -0
- package/dist/primitives/platform.js.map +1 -0
- package/dist/primitives/promise.d.ts +46 -0
- package/dist/primitives/promise.d.ts.map +1 -0
- package/dist/primitives/promise.js +104 -0
- package/dist/primitives/promise.js.map +1 -0
- package/dist/primitives/push.d.ts +52 -0
- package/dist/primitives/push.d.ts.map +1 -0
- package/dist/primitives/push.js +72 -0
- package/dist/primitives/push.js.map +1 -0
- package/dist/primitives/router.d.ts +170 -0
- package/dist/primitives/router.d.ts.map +1 -0
- package/dist/primitives/router.js +251 -0
- package/dist/primitives/router.js.map +1 -0
- package/dist/primitives/signup.d.ts +37 -0
- package/dist/primitives/signup.d.ts.map +1 -0
- package/dist/primitives/signup.js +32 -0
- package/dist/primitives/signup.js.map +1 -0
- package/dist/primitives/state.d.ts +132 -0
- package/dist/primitives/state.d.ts.map +1 -0
- package/dist/primitives/state.js +167 -0
- package/dist/primitives/state.js.map +1 -0
- package/dist/primitives/storage.d.ts +132 -0
- package/dist/primitives/storage.d.ts.map +1 -0
- package/dist/primitives/storage.js +275 -0
- package/dist/primitives/storage.js.map +1 -0
- package/dist/primitives/theme.d.ts +106 -0
- package/dist/primitives/theme.d.ts.map +1 -0
- package/dist/primitives/theme.js +187 -0
- package/dist/primitives/theme.js.map +1 -0
- package/dist/primitives/version.d.ts +50 -0
- package/dist/primitives/version.d.ts.map +1 -0
- package/dist/primitives/version.js +62 -0
- package/dist/primitives/version.js.map +1 -0
- package/dist/provider.d.ts +36 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.jsx +71 -0
- package/dist/provider.jsx.map +1 -0
- package/dist/types.d.ts +82 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solid.js primitive for OAuth authentication.
|
|
3
|
+
*
|
|
4
|
+
* Builds provider initiation URLs, starts the full-page redirect flow, and
|
|
5
|
+
* automatically handles the OAuth callback: when the page loads with a `code`
|
|
6
|
+
* (+ optional `state`) URL parameter and a stashed provider, the code is
|
|
7
|
+
* exchanged for a session via `POST {baseURL}{loginEndpoint}`.
|
|
8
|
+
*
|
|
9
|
+
* Session establishment prefers an auth client — an explicit
|
|
10
|
+
* {@link CreateOAuthOptions.authClient} override, else the surrounding
|
|
11
|
+
* `MoleculeProvider`'s client. Without any client, the code exchange itself
|
|
12
|
+
* has already established the httpOnly-cookie session server-side, so a
|
|
13
|
+
* user-carrying response still counts as a successful login.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import { getOwner, onMount } from 'solid-js';
|
|
18
|
+
import { getAuthClient } from '../context.js';
|
|
19
|
+
/**
|
|
20
|
+
* Creates OAuth helpers.
|
|
21
|
+
*
|
|
22
|
+
* Automatically handles OAuth callbacks by detecting `code` and `state` URL
|
|
23
|
+
* parameters and exchanging them for a session:
|
|
24
|
+
* - Inside a Solid owner (component setup / `createRoot`), the callback
|
|
25
|
+
* handling is deferred to `onMount` so it runs client-side after mount.
|
|
26
|
+
* - Outside an owner (a plain function call, e.g. bootstrap code), it runs
|
|
27
|
+
* immediately at creation, browser-guarded.
|
|
28
|
+
*
|
|
29
|
+
* @param options - OAuth configuration
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```tsx
|
|
33
|
+
* const { providers, getOAuthUrl, redirect } = createOAuth({
|
|
34
|
+
* baseURL: 'https://api.example.com',
|
|
35
|
+
* oauthProviders: ['github', 'google'],
|
|
36
|
+
* onSuccess: () => navigate('/dashboard'),
|
|
37
|
+
* onError: (error) => setErrorMessage(error),
|
|
38
|
+
* })
|
|
39
|
+
*
|
|
40
|
+
* return (
|
|
41
|
+
* <For each={providers()}>
|
|
42
|
+
* {(provider) => (
|
|
43
|
+
* <button onClick={() => redirect(provider)}>
|
|
44
|
+
* Login with {provider}
|
|
45
|
+
* </button>
|
|
46
|
+
* )}
|
|
47
|
+
* </For>
|
|
48
|
+
* )
|
|
49
|
+
* ```
|
|
50
|
+
* @returns The created instance.
|
|
51
|
+
*/
|
|
52
|
+
export function createOAuth(options) {
|
|
53
|
+
const baseURL = options?.baseURL ?? '';
|
|
54
|
+
const oauthEndpoint = options?.oauthEndpoint ?? '/oauth';
|
|
55
|
+
const loginEndpoint = options?.loginEndpoint ?? '/users/log-in/oauth';
|
|
56
|
+
const providersList = options?.oauthProviders ?? [];
|
|
57
|
+
const providers = () => providersList;
|
|
58
|
+
// Resolve the auth client once at creation: an explicit override wins;
|
|
59
|
+
// otherwise fall back to the surrounding MoleculeProvider context.
|
|
60
|
+
let authClient = options?.authClient ?? null;
|
|
61
|
+
if (!authClient) {
|
|
62
|
+
try {
|
|
63
|
+
authClient = getAuthClient();
|
|
64
|
+
}
|
|
65
|
+
catch (_error) {
|
|
66
|
+
// Intentional noop: created outside a MoleculeProvider (or without auth
|
|
67
|
+
// configured). The helper still works — handleCallback falls back to the
|
|
68
|
+
// server-established httpOnly-cookie session (see its JSDoc).
|
|
69
|
+
authClient = null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const getOAuthUrl = (provider) => {
|
|
73
|
+
// Encode the provider as a single path segment so a (future) caller passing an
|
|
74
|
+
// untrusted value can never inject a path/query/scheme into the opened URL —
|
|
75
|
+
// defense-in-depth on top of the upstream static provider allowlist. Plain
|
|
76
|
+
// provider names ('github', 'google') pass through unchanged.
|
|
77
|
+
return `${baseURL}${oauthEndpoint}/${encodeURIComponent(provider)}`;
|
|
78
|
+
};
|
|
79
|
+
/** Stash which provider initiated the flow so the callback knows it's ours. */
|
|
80
|
+
const stashProvider = (provider) => {
|
|
81
|
+
try {
|
|
82
|
+
sessionStorage.setItem('oauth_provider', provider);
|
|
83
|
+
}
|
|
84
|
+
catch (_error) {
|
|
85
|
+
/* SSR-safe — sessionStorage is unavailable in SSR/sandboxed environments */
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Append the current page's PATH as `redirect_to` so the api's initiation
|
|
90
|
+
* endpoint (`GET /users/oauth/:provider`) builds a provider `redirect_uri`
|
|
91
|
+
* that lands the callback back on THIS page — the one with `createOAuth`
|
|
92
|
+
* mounted (e.g. `/login`) — instead of the app root, where nothing may be
|
|
93
|
+
* listening for the `code` param. Path only (no origin/query): the server
|
|
94
|
+
* validates it as a same-origin absolute path, so it can never become an
|
|
95
|
+
* open redirect. Servers that predate the param simply ignore it.
|
|
96
|
+
*/
|
|
97
|
+
const withReturnPath = (url) => {
|
|
98
|
+
const path = typeof window !== 'undefined' ? window.location.pathname : '';
|
|
99
|
+
if (!path || path === '/')
|
|
100
|
+
return url;
|
|
101
|
+
return `${url}${url.includes('?') ? '&' : '?'}redirect_to=${encodeURIComponent(path)}`;
|
|
102
|
+
};
|
|
103
|
+
const redirect = (provider) => {
|
|
104
|
+
stashProvider(provider);
|
|
105
|
+
window.location.href = withReturnPath(getOAuthUrl(provider));
|
|
106
|
+
};
|
|
107
|
+
/** Surface a failure message to the configured error callback. */
|
|
108
|
+
const surfaceError = (error) => {
|
|
109
|
+
options?.onError?.(error);
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Establish the authenticated session from an exchange result: seed the
|
|
113
|
+
* access token + user and let `initialize()` flip `authenticated`. Mirrors
|
|
114
|
+
* what `authClient.login()` does for password login. Returns whether a user
|
|
115
|
+
* was set (a result with no user is not a real session).
|
|
116
|
+
*/
|
|
117
|
+
const establishSession = async (client, token, user) => {
|
|
118
|
+
// Seed the token via the auth client's configured token storage adapter
|
|
119
|
+
// (in-memory by default) — NOT localStorage directly. Writing the bearer
|
|
120
|
+
// token to localStorage violates the in-memory-default storage contract and
|
|
121
|
+
// makes it JS-readable (XSS-exfiltratable).
|
|
122
|
+
if (token)
|
|
123
|
+
client.setAccessToken(token);
|
|
124
|
+
if (user && typeof user === 'object') {
|
|
125
|
+
client.setUser(user);
|
|
126
|
+
await client.initialize();
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
};
|
|
131
|
+
const handleCallback = async () => {
|
|
132
|
+
if (typeof window === 'undefined')
|
|
133
|
+
return;
|
|
134
|
+
const params = new URLSearchParams(window.location.search);
|
|
135
|
+
const code = params.get('code');
|
|
136
|
+
const state = params.get('state');
|
|
137
|
+
if (!code)
|
|
138
|
+
return;
|
|
139
|
+
// Retrieve the provider that initiated the flow
|
|
140
|
+
let provider = null;
|
|
141
|
+
try {
|
|
142
|
+
provider = sessionStorage.getItem('oauth_provider');
|
|
143
|
+
}
|
|
144
|
+
catch (_error) {
|
|
145
|
+
/* SSR-safe — sessionStorage is unavailable in SSR/sandboxed environments */
|
|
146
|
+
}
|
|
147
|
+
if (!provider)
|
|
148
|
+
return;
|
|
149
|
+
// Clean up URL (remove code/state params) and sessionStorage
|
|
150
|
+
const cleanUrl = new URL(window.location.href);
|
|
151
|
+
cleanUrl.searchParams.delete('code');
|
|
152
|
+
cleanUrl.searchParams.delete('state');
|
|
153
|
+
window.history.replaceState({}, '', cleanUrl.toString());
|
|
154
|
+
try {
|
|
155
|
+
sessionStorage.removeItem('oauth_provider');
|
|
156
|
+
}
|
|
157
|
+
catch (_error) {
|
|
158
|
+
/* SSR-safe — sessionStorage is unavailable in SSR/sandboxed environments */
|
|
159
|
+
}
|
|
160
|
+
// Exchange code for session
|
|
161
|
+
try {
|
|
162
|
+
const response = await fetch(`${baseURL}${loginEndpoint}`, {
|
|
163
|
+
method: 'POST',
|
|
164
|
+
headers: { 'Content-Type': 'application/json' },
|
|
165
|
+
credentials: 'include', // Send cookies (oauth_state) for state validation
|
|
166
|
+
body: JSON.stringify({
|
|
167
|
+
server: provider,
|
|
168
|
+
code,
|
|
169
|
+
state: state || undefined,
|
|
170
|
+
redirect_uri: window.location.origin,
|
|
171
|
+
}),
|
|
172
|
+
});
|
|
173
|
+
if (!response.ok) {
|
|
174
|
+
const data = (await response.json().catch(() => null));
|
|
175
|
+
surfaceError(data && typeof data.error === 'string' && data.error ? data.error : 'OAuth login failed');
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const data = await response.json().catch(() => null);
|
|
179
|
+
// Store the token from the response
|
|
180
|
+
const authHeader = response.headers.get('authorization') || response.headers.get('set-authorization');
|
|
181
|
+
const token = authHeader ? authHeader.replace('Bearer ', '') : null;
|
|
182
|
+
// The authenticated user is `props` (molecule resource convention) or `user`
|
|
183
|
+
// (generic AuthResult). OAuth issues no refresh token, so we carry the token +
|
|
184
|
+
// user to whoever will own the session.
|
|
185
|
+
const user = data && typeof data === 'object'
|
|
186
|
+
? (data.props ??
|
|
187
|
+
data.user ??
|
|
188
|
+
null)
|
|
189
|
+
: null;
|
|
190
|
+
if (authClient) {
|
|
191
|
+
const ok = await establishSession(authClient, token, user);
|
|
192
|
+
if (ok)
|
|
193
|
+
options?.onSuccess?.();
|
|
194
|
+
else
|
|
195
|
+
surfaceError('OAuth login failed');
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
// No auth client available: the server already established the
|
|
199
|
+
// httpOnly-cookie session during the code exchange, so a user-carrying
|
|
200
|
+
// response still counts as a successful login. A response with no user
|
|
201
|
+
// means no session was established — surface the failure.
|
|
202
|
+
if (user && typeof user === 'object')
|
|
203
|
+
options?.onSuccess?.();
|
|
204
|
+
else
|
|
205
|
+
surfaceError('OAuth login failed');
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
surfaceError(err instanceof Error && err.message ? err.message : 'OAuth login failed');
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
// Auto-handle the OAuth callback:
|
|
212
|
+
// - Inside a Solid owner (component setup / createRoot), defer to onMount
|
|
213
|
+
// so the exchange runs client-side after the component mounts.
|
|
214
|
+
// - Outside an owner (plain function call — e.g. bootstrap code), run
|
|
215
|
+
// immediately, browser-guarded. handleCallback itself no-ops unless the
|
|
216
|
+
// URL carries a `code` param and a provider was stashed.
|
|
217
|
+
if (getOwner()) {
|
|
218
|
+
onMount(() => {
|
|
219
|
+
void handleCallback();
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
else if (typeof window !== 'undefined') {
|
|
223
|
+
void handleCallback();
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
providers,
|
|
227
|
+
getOAuthUrl,
|
|
228
|
+
redirect,
|
|
229
|
+
handleCallback,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/primitives/oauth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solid.js primitive for password reset with async state tracking.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { Accessor } from 'solid-js';
|
|
7
|
+
import type { PasswordResetConfirm, PasswordResetRequest } from '@molecule/app-auth';
|
|
8
|
+
import type { PromiseState } from '@molecule/app-utilities';
|
|
9
|
+
/**
|
|
10
|
+
* Return type for createPasswordReset primitive.
|
|
11
|
+
*/
|
|
12
|
+
export interface CreatePasswordResetReturn {
|
|
13
|
+
requestState: Accessor<PromiseState<void>>;
|
|
14
|
+
confirmState: Accessor<PromiseState<void>>;
|
|
15
|
+
requestReset: (data: PasswordResetRequest) => Promise<void>;
|
|
16
|
+
confirmReset: (data: PasswordResetConfirm) => Promise<void>;
|
|
17
|
+
reset: () => void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates a password reset primitive with async state tracking.
|
|
21
|
+
*
|
|
22
|
+
* @returns Password reset state and actions
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* const { requestState, confirmState, requestReset, confirmReset } = createPasswordReset()
|
|
27
|
+
*
|
|
28
|
+
* // Request phase
|
|
29
|
+
* <button
|
|
30
|
+
* onClick={() => requestReset({ email: email() })}
|
|
31
|
+
* disabled={requestState().status === 'pending'}
|
|
32
|
+
* >
|
|
33
|
+
* Send Reset Email
|
|
34
|
+
* </button>
|
|
35
|
+
*
|
|
36
|
+
* // Confirm phase
|
|
37
|
+
* <button
|
|
38
|
+
* onClick={() => confirmReset({ token: token(), password: password() })}
|
|
39
|
+
* disabled={confirmState().status === 'pending'}
|
|
40
|
+
* >
|
|
41
|
+
* Reset Password
|
|
42
|
+
* </button>
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function createPasswordReset(): CreatePasswordResetReturn;
|
|
46
|
+
//# sourceMappingURL=password-reset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-reset.d.ts","sourceRoot":"","sources":["../../src/primitives/password-reset.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACpF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAK3D;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;IAC1C,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;IAC1C,YAAY,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,YAAY,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,mBAAmB,IAAI,yBAAyB,CAiB/D"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solid.js primitive for password reset with async state tracking.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { getAuthClient } from '../context.js';
|
|
7
|
+
import { createPromise } from './promise.js';
|
|
8
|
+
/**
|
|
9
|
+
* Creates a password reset primitive with async state tracking.
|
|
10
|
+
*
|
|
11
|
+
* @returns Password reset state and actions
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* const { requestState, confirmState, requestReset, confirmReset } = createPasswordReset()
|
|
16
|
+
*
|
|
17
|
+
* // Request phase
|
|
18
|
+
* <button
|
|
19
|
+
* onClick={() => requestReset({ email: email() })}
|
|
20
|
+
* disabled={requestState().status === 'pending'}
|
|
21
|
+
* >
|
|
22
|
+
* Send Reset Email
|
|
23
|
+
* </button>
|
|
24
|
+
*
|
|
25
|
+
* // Confirm phase
|
|
26
|
+
* <button
|
|
27
|
+
* onClick={() => confirmReset({ token: token(), password: password() })}
|
|
28
|
+
* disabled={confirmState().status === 'pending'}
|
|
29
|
+
* >
|
|
30
|
+
* Reset Password
|
|
31
|
+
* </button>
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function createPasswordReset() {
|
|
35
|
+
const client = getAuthClient();
|
|
36
|
+
const request = createPromise((data) => client.requestPasswordReset(data));
|
|
37
|
+
const confirm = createPromise((data) => client.confirmPasswordReset(data));
|
|
38
|
+
return {
|
|
39
|
+
requestState: request.state,
|
|
40
|
+
confirmState: confirm.state,
|
|
41
|
+
requestReset: request.call,
|
|
42
|
+
confirmReset: confirm.call,
|
|
43
|
+
reset: () => {
|
|
44
|
+
request.reset();
|
|
45
|
+
confirm.reset();
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=password-reset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-reset.js","sourceRoot":"","sources":["../../src/primitives/password-reset.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAa5C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,MAAM,GAAG,aAAa,EAAE,CAAA;IAE9B,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,IAA0B,EAAE,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAA;IAEhG,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,IAA0B,EAAE,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAA;IAEhG,OAAO;QACL,YAAY,EAAE,OAAO,CAAC,KAAK;QAC3B,YAAY,EAAE,OAAO,CAAC,KAAK;QAC3B,YAAY,EAAE,OAAO,CAAC,IAAI;QAC1B,YAAY,EAAE,OAAO,CAAC,IAAI;QAC1B,KAAK,EAAE,GAAG,EAAE;YACV,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,OAAO,CAAC,KAAK,EAAE,CAAA;QACjB,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solid.js primitives for platform detection.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { Platform } from '@molecule/app-platform';
|
|
7
|
+
/**
|
|
8
|
+
* Platform primitives return type.
|
|
9
|
+
*/
|
|
10
|
+
export interface PlatformPrimitives {
|
|
11
|
+
platform: Platform;
|
|
12
|
+
isNative: boolean;
|
|
13
|
+
isMobile: boolean;
|
|
14
|
+
isDesktop: boolean;
|
|
15
|
+
isWeb: boolean;
|
|
16
|
+
isDevelopment: boolean;
|
|
17
|
+
isProduction: boolean;
|
|
18
|
+
isPlatform: (...platforms: Platform[]) => boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Create platform primitives for detecting the current platform.
|
|
22
|
+
*
|
|
23
|
+
* This is a static primitive (no reactive signals) since the platform
|
|
24
|
+
* does not change during the lifecycle of the app.
|
|
25
|
+
*
|
|
26
|
+
* @returns Platform primitives object
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* import { createPlatform } from '@molecule/app-solid'
|
|
31
|
+
*
|
|
32
|
+
* function PlatformInfo() {
|
|
33
|
+
* const { platform, isWeb, isMobile, isPlatform } = createPlatform()
|
|
34
|
+
*
|
|
35
|
+
* return (
|
|
36
|
+
* <div>
|
|
37
|
+
* <p>Platform: {platform}</p>
|
|
38
|
+
* <p>Is Web: {isWeb ? 'Yes' : 'No'}</p>
|
|
39
|
+
* <Show when={isPlatform('ios', 'android')}>
|
|
40
|
+
* <p>Running on mobile native</p>
|
|
41
|
+
* </Show>
|
|
42
|
+
* </div>
|
|
43
|
+
* )
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function createPlatform(): PlatformPrimitives;
|
|
48
|
+
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/primitives/platform.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAGtD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,QAAQ,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,OAAO,CAAA;IACd,aAAa,EAAE,OAAO,CAAA;IACtB,YAAY,EAAE,OAAO,CAAA;IACrB,UAAU,EAAE,CAAC,GAAG,SAAS,EAAE,QAAQ,EAAE,KAAK,OAAO,CAAA;CAClD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,cAAc,IAAI,kBAAkB,CAanD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solid.js primitives for platform detection.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { isPlatform, platform } from '@molecule/app-platform';
|
|
7
|
+
/**
|
|
8
|
+
* Create platform primitives for detecting the current platform.
|
|
9
|
+
*
|
|
10
|
+
* This is a static primitive (no reactive signals) since the platform
|
|
11
|
+
* does not change during the lifecycle of the app.
|
|
12
|
+
*
|
|
13
|
+
* @returns Platform primitives object
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* import { createPlatform } from '@molecule/app-solid'
|
|
18
|
+
*
|
|
19
|
+
* function PlatformInfo() {
|
|
20
|
+
* const { platform, isWeb, isMobile, isPlatform } = createPlatform()
|
|
21
|
+
*
|
|
22
|
+
* return (
|
|
23
|
+
* <div>
|
|
24
|
+
* <p>Platform: {platform}</p>
|
|
25
|
+
* <p>Is Web: {isWeb ? 'Yes' : 'No'}</p>
|
|
26
|
+
* <Show when={isPlatform('ios', 'android')}>
|
|
27
|
+
* <p>Running on mobile native</p>
|
|
28
|
+
* </Show>
|
|
29
|
+
* </div>
|
|
30
|
+
* )
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function createPlatform() {
|
|
35
|
+
const info = platform();
|
|
36
|
+
return {
|
|
37
|
+
platform: info.platform,
|
|
38
|
+
isNative: info.isNative,
|
|
39
|
+
isMobile: info.isMobile,
|
|
40
|
+
isDesktop: info.isDesktop,
|
|
41
|
+
isWeb: info.isWeb,
|
|
42
|
+
isDevelopment: info.isDevelopment,
|
|
43
|
+
isProduction: info.isProduction,
|
|
44
|
+
isPlatform: (...platforms) => isPlatform(...platforms),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=platform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/primitives/platform.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAgB7D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAA;IAEvB,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,UAAU,EAAE,CAAC,GAAG,SAAS,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;KACvD,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solid.js primitive for tracking async function state.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { PromiseState } from '@molecule/app-utilities';
|
|
7
|
+
/**
|
|
8
|
+
* Promise state accessor with actions.
|
|
9
|
+
*/
|
|
10
|
+
export interface CreatePromiseReturn<T> {
|
|
11
|
+
state: () => PromiseState<T>;
|
|
12
|
+
call: (...args: any[]) => Promise<T>;
|
|
13
|
+
cancel: (message?: string) => void;
|
|
14
|
+
reset: () => void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Primitive that wraps an async function with reactive state tracking.
|
|
18
|
+
*
|
|
19
|
+
* @param asyncFn - The async function to wrap
|
|
20
|
+
* @returns Object with state accessor, call, cancel, and reset functions
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* import { createPromise } from '@molecule/app-solid'
|
|
25
|
+
*
|
|
26
|
+
* function UserLoader() {
|
|
27
|
+
* const { state, call } = createPromise((id: string) => fetchUser(id))
|
|
28
|
+
*
|
|
29
|
+
* return (
|
|
30
|
+
* <div>
|
|
31
|
+
* <button onClick={() => call('123')} disabled={state().status === 'pending'}>
|
|
32
|
+
* {state().status === 'pending' ? 'Loading...' : 'Fetch User'}
|
|
33
|
+
* </button>
|
|
34
|
+
* <Show when={state().value}>
|
|
35
|
+
* <div>{state().value!.name}</div>
|
|
36
|
+
* </Show>
|
|
37
|
+
* <Show when={state().error}>
|
|
38
|
+
* <div>Error: {state().error!.message}</div>
|
|
39
|
+
* </Show>
|
|
40
|
+
* </div>
|
|
41
|
+
* )
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function createPromise<T extends (...args: any[]) => Promise<any>>(asyncFn: T): CreatePromiseReturn<Awaited<ReturnType<T>>>;
|
|
46
|
+
//# sourceMappingURL=promise.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promise.d.ts","sourceRoot":"","sources":["../../src/primitives/promise.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,yBAAyB,CAAA;AAE1E;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,CAAA;IAC5B,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;IACpC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,EACtE,OAAO,EAAE,CAAC,GACT,mBAAmB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CA8E7C"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solid.js primitive for tracking async function state.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
7
|
+
import { batch, createSignal, onCleanup } from 'solid-js';
|
|
8
|
+
const INITIAL_STATE = {
|
|
9
|
+
status: 'idle',
|
|
10
|
+
value: null,
|
|
11
|
+
error: null,
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Primitive that wraps an async function with reactive state tracking.
|
|
15
|
+
*
|
|
16
|
+
* @param asyncFn - The async function to wrap
|
|
17
|
+
* @returns Object with state accessor, call, cancel, and reset functions
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* import { createPromise } from '@molecule/app-solid'
|
|
22
|
+
*
|
|
23
|
+
* function UserLoader() {
|
|
24
|
+
* const { state, call } = createPromise((id: string) => fetchUser(id))
|
|
25
|
+
*
|
|
26
|
+
* return (
|
|
27
|
+
* <div>
|
|
28
|
+
* <button onClick={() => call('123')} disabled={state().status === 'pending'}>
|
|
29
|
+
* {state().status === 'pending' ? 'Loading...' : 'Fetch User'}
|
|
30
|
+
* </button>
|
|
31
|
+
* <Show when={state().value}>
|
|
32
|
+
* <div>{state().value!.name}</div>
|
|
33
|
+
* </Show>
|
|
34
|
+
* <Show when={state().error}>
|
|
35
|
+
* <div>Error: {state().error!.message}</div>
|
|
36
|
+
* </Show>
|
|
37
|
+
* </div>
|
|
38
|
+
* )
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function createPromise(asyncFn) {
|
|
43
|
+
const [state, setState] = createSignal(INITIAL_STATE);
|
|
44
|
+
let callId = 0;
|
|
45
|
+
let cleaned = false;
|
|
46
|
+
onCleanup(() => {
|
|
47
|
+
cleaned = true;
|
|
48
|
+
});
|
|
49
|
+
const call = (...args) => {
|
|
50
|
+
callId += 1;
|
|
51
|
+
const thisCallId = callId;
|
|
52
|
+
batch(() => {
|
|
53
|
+
setState({
|
|
54
|
+
status: 'pending',
|
|
55
|
+
value: null,
|
|
56
|
+
error: null,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
return asyncFn(...args).then((resolved) => {
|
|
60
|
+
if (thisCallId === callId && !cleaned) {
|
|
61
|
+
batch(() => {
|
|
62
|
+
setState({
|
|
63
|
+
status: 'resolved',
|
|
64
|
+
value: resolved,
|
|
65
|
+
error: null,
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return resolved;
|
|
70
|
+
}, (err) => {
|
|
71
|
+
const rejection = err instanceof Error ? err : new Error(String(err));
|
|
72
|
+
if (thisCallId === callId && !cleaned) {
|
|
73
|
+
batch(() => {
|
|
74
|
+
setState({
|
|
75
|
+
status: 'rejected',
|
|
76
|
+
value: null,
|
|
77
|
+
error: rejection,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
throw rejection;
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
const cancel = (message) => {
|
|
85
|
+
callId += 1;
|
|
86
|
+
if (!cleaned) {
|
|
87
|
+
batch(() => {
|
|
88
|
+
setState({
|
|
89
|
+
status: 'rejected',
|
|
90
|
+
value: null,
|
|
91
|
+
error: message ? new Error(message) : null,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const reset = () => {
|
|
97
|
+
callId += 1;
|
|
98
|
+
if (!cleaned) {
|
|
99
|
+
setState(INITIAL_STATE);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return { state, call, cancel, reset };
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=promise.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promise.js","sourceRoot":"","sources":["../../src/primitives/promise.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,uDAAuD;AACvD,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAczD,MAAM,aAAa,GAAwB;IACzC,MAAM,EAAE,MAAuB;IAC/B,KAAK,EAAE,IAAI;IACX,KAAK,EAAE,IAAI;CACZ,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAU;IAIV,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,YAAY,CAAkB,aAAgC,CAAC,CAAA;IAEzF,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,IAAI,OAAO,GAAG,KAAK,CAAA;IAEnB,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,GAAG,IAAI,CAAA;IAChB,CAAC,CAAC,CAAA;IAEF,MAAM,IAAI,GAAG,CAAC,GAAG,IAAW,EAAc,EAAE;QAC1C,MAAM,IAAI,CAAC,CAAA;QACX,MAAM,UAAU,GAAG,MAAM,CAAA;QAEzB,KAAK,CAAC,GAAG,EAAE;YACT,QAAQ,CAAC;gBACP,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE,IAAI;gBACX,KAAK,EAAE,IAAI;aACZ,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,OAAO,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAC1B,CAAC,QAAW,EAAE,EAAE;YACd,IAAI,UAAU,KAAK,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;gBACtC,KAAK,CAAC,GAAG,EAAE;oBACT,QAAQ,CAAC;wBACP,MAAM,EAAE,UAAU;wBAClB,KAAK,EAAE,QAAQ;wBACf,KAAK,EAAE,IAAI;qBACZ,CAAC,CAAA;gBACJ,CAAC,CAAC,CAAA;YACJ,CAAC;YACD,OAAO,QAAQ,CAAA;QACjB,CAAC,EACD,CAAC,GAAY,EAAE,EAAE;YACf,MAAM,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;YAErE,IAAI,UAAU,KAAK,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;gBACtC,KAAK,CAAC,GAAG,EAAE;oBACT,QAAQ,CAAC;wBACP,MAAM,EAAE,UAAU;wBAClB,KAAK,EAAE,IAAI;wBACX,KAAK,EAAE,SAAS;qBACjB,CAAC,CAAA;gBACJ,CAAC,CAAC,CAAA;YACJ,CAAC;YAED,MAAM,SAAS,CAAA;QACjB,CAAC,CACF,CAAA;IACH,CAAC,CAAA;IAED,MAAM,MAAM,GAAG,CAAC,OAAgB,EAAQ,EAAE;QACxC,MAAM,IAAI,CAAC,CAAA;QAEX,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,KAAK,CAAC,GAAG,EAAE;gBACT,QAAQ,CAAC;oBACP,MAAM,EAAE,UAAU;oBAClB,KAAK,EAAE,IAAI;oBACX,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI;iBAC3C,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,MAAM,IAAI,CAAC,CAAA;QAEX,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,QAAQ,CAAC,aAAgC,CAAC,CAAA;QAC5C,CAAC;IACH,CAAC,CAAA;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;AACvC,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solid.js primitives for push notifications.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { type Accessor } from 'solid-js';
|
|
7
|
+
import type { NotificationActionListener, NotificationReceivedListener, PermissionStatus, PushRegisterOptions, PushToken, TokenChangeListener } from '@molecule/app-push';
|
|
8
|
+
/**
|
|
9
|
+
* Push primitives return type.
|
|
10
|
+
*/
|
|
11
|
+
export interface PushPrimitives {
|
|
12
|
+
permission: Accessor<PermissionStatus | null>;
|
|
13
|
+
token: Accessor<PushToken | null>;
|
|
14
|
+
checkPermission: () => Promise<PermissionStatus>;
|
|
15
|
+
requestPermission: () => Promise<PermissionStatus>;
|
|
16
|
+
register: (options?: PushRegisterOptions) => Promise<PushToken>;
|
|
17
|
+
unregister: () => Promise<void>;
|
|
18
|
+
onNotificationReceived: (listener: NotificationReceivedListener) => () => void;
|
|
19
|
+
onNotificationAction: (listener: NotificationActionListener) => () => void;
|
|
20
|
+
onTokenChange: (listener: TokenChangeListener) => () => void;
|
|
21
|
+
setBadge: (count: number) => Promise<void>;
|
|
22
|
+
clearBadge: () => Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Create push notification primitives.
|
|
26
|
+
*
|
|
27
|
+
* @returns Push primitives object
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* import { createPush } from '@molecule/app-solid'
|
|
32
|
+
*
|
|
33
|
+
* function NotificationButton() {
|
|
34
|
+
* const { permission, requestPermission, register } = createPush()
|
|
35
|
+
*
|
|
36
|
+
* const handleEnable = async () => {
|
|
37
|
+
* const status = await requestPermission()
|
|
38
|
+
* if (status === 'granted') {
|
|
39
|
+
* await register()
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
*
|
|
43
|
+
* return (
|
|
44
|
+
* <Show when={permission() !== 'granted'}>
|
|
45
|
+
* <button onClick={handleEnable}>Enable Notifications</button>
|
|
46
|
+
* </Show>
|
|
47
|
+
* )
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function createPush(): PushPrimitives;
|
|
52
|
+
//# sourceMappingURL=push.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/primitives/push.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,QAAQ,EAAgB,MAAM,UAAU,CAAA;AAEtD,OAAO,KAAK,EACV,0BAA0B,EAC1B,4BAA4B,EAC5B,gBAAgB,EAChB,mBAAmB,EACnB,SAAS,EACT,mBAAmB,EACpB,MAAM,oBAAoB,CAAA;AAG3B;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,QAAQ,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAC7C,KAAK,EAAE,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC,CAAA;IACjC,eAAe,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAChD,iBAAiB,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAClD,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,SAAS,CAAC,CAAA;IAC/D,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/B,sBAAsB,EAAE,CAAC,QAAQ,EAAE,4BAA4B,KAAK,MAAM,IAAI,CAAA;IAC9E,oBAAoB,EAAE,CAAC,QAAQ,EAAE,0BAA0B,KAAK,MAAM,IAAI,CAAA;IAC1E,aAAa,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,MAAM,IAAI,CAAA;IAC5D,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,UAAU,IAAI,cAAc,CA0C3C"}
|