tempest-react-sdk 0.5.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +206 -35
- package/bin/create-tempest-app.mjs +248 -0
- package/bin/tempest.mjs +282 -0
- package/dist/styles.css +1 -1
- package/dist/sw.cjs +2 -0
- package/dist/sw.cjs.map +1 -0
- package/dist/sw.d.ts +103 -0
- package/dist/sw.js +95 -0
- package/dist/sw.js.map +1 -0
- package/dist/tempest-react-sdk.cjs +4 -4
- package/dist/tempest-react-sdk.cjs.map +1 -1
- package/dist/tempest-react-sdk.d.ts +1697 -7
- package/dist/tempest-react-sdk.js +4485 -2989
- package/dist/tempest-react-sdk.js.map +1 -1
- package/dist/vite.cjs +2 -0
- package/dist/vite.cjs.map +1 -0
- package/dist/vite.d.ts +62 -0
- package/dist/vite.js +46 -0
- package/dist/vite.js.map +1 -0
- package/package.json +34 -2
- package/template/README.md +37 -0
- package/template/_env.example +2 -0
- package/template/_gitignore +9 -0
- package/template/_prettierrc.json +9 -0
- package/template/eslint.config.js +44 -0
- package/template/index.html +12 -0
- package/template/package.json +38 -0
- package/template/src/App.tsx +15 -0
- package/template/src/layouts/RootLayout.tsx +28 -0
- package/template/src/lib/api.ts +17 -0
- package/template/src/main.tsx +10 -0
- package/template/src/pages/Dashboard.tsx +19 -0
- package/template/src/pages/Home.tsx +16 -0
- package/template/src/pages/Login.tsx +27 -0
- package/template/src/routes.tsx +27 -0
- package/template/src/stores/auth.ts +15 -0
- package/template/src/vite-env.d.ts +1 -0
- package/template/tsconfig.json +26 -0
- package/template/vite.config.ts +7 -0
- package/template-pwa/README.md +64 -0
- package/template-pwa/_env.example +7 -0
- package/template-pwa/index.html +22 -0
- package/template-pwa/package.json +6 -0
- package/template-pwa/public/icon-maskable.svg +4 -0
- package/template-pwa/public/icon.svg +4 -0
- package/template-pwa/public/manifest.webmanifest +35 -0
- package/template-pwa/src/main.tsx +36 -0
- package/template-pwa/src/pages/Dashboard.tsx +73 -0
- package/template-pwa/src/sw.ts +35 -0
- package/template-pwa/src/vite-env.d.ts +12 -0
- package/template-pwa/vite.sw.config.ts +27 -0
package/dist/sw.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install a `notificationclick` handler that focuses an existing client when
|
|
3
|
+
* possible and falls back to opening a new window.
|
|
4
|
+
*/
|
|
5
|
+
export declare function installNotificationClickHandler(options?: InstallNotificationClickHandlerOptions): void;
|
|
6
|
+
|
|
7
|
+
export declare interface InstallNotificationClickHandlerOptions {
|
|
8
|
+
/** Resolve the destination URL from the notification data. Default: `data.url`. */
|
|
9
|
+
resolveUrl?: (data: unknown) => string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Install a `push` event listener that parses the payload as JSON (with a
|
|
14
|
+
* plain-text fallback) and shows a notification.
|
|
15
|
+
*/
|
|
16
|
+
export declare function installPushHandler(options?: InstallPushHandlerOptions): void;
|
|
17
|
+
|
|
18
|
+
export declare interface InstallPushHandlerOptions {
|
|
19
|
+
/** Title used when the payload omits one. */
|
|
20
|
+
defaultTitle?: string;
|
|
21
|
+
/** Icon used when the payload omits one. */
|
|
22
|
+
defaultIcon?: string;
|
|
23
|
+
/** Badge image (mobile). */
|
|
24
|
+
defaultBadge?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Transform the raw payload before showing the notification. Return `null`
|
|
27
|
+
* to suppress the notification entirely (e.g. silent pings).
|
|
28
|
+
*/
|
|
29
|
+
transform?: (payload: PushPayload) => PushPayload | null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Install a `message` listener that activates a waiting worker when the host
|
|
34
|
+
* app sends `{ type: "SKIP_WAITING" }`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function installSkipWaitingListener(): void;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Service-worker context helpers for handling `push` and `notificationclick`
|
|
40
|
+
* events. Import these inside your own `sw.ts` — they expect to run in the
|
|
41
|
+
* service-worker global scope, not in the main thread.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* /// <reference lib="webworker" />
|
|
45
|
+
* import { installPushHandler, installNotificationClickHandler } from "tempest-react-sdk";
|
|
46
|
+
*
|
|
47
|
+
* installPushHandler({ defaultIcon: "/icons/Logo.png" });
|
|
48
|
+
* installNotificationClickHandler();
|
|
49
|
+
*/
|
|
50
|
+
export declare interface PushPayload {
|
|
51
|
+
title?: string;
|
|
52
|
+
body?: string;
|
|
53
|
+
icon?: string;
|
|
54
|
+
badge?: string;
|
|
55
|
+
image?: string;
|
|
56
|
+
tag?: string;
|
|
57
|
+
url?: string;
|
|
58
|
+
/** Arbitrary extra data forwarded to `event.notification.data`. */
|
|
59
|
+
data?: Record<string, unknown>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Register a service worker with consistent update-detection wiring.
|
|
64
|
+
*
|
|
65
|
+
* Skips silently when the runtime has no `serviceWorker` support. The host
|
|
66
|
+
* app keeps full control over the SW file — this helper only handles the
|
|
67
|
+
* boilerplate around `register()` and `updatefound`.
|
|
68
|
+
*
|
|
69
|
+
* @returns The registration when it succeeds, or `null` when unsupported.
|
|
70
|
+
*/
|
|
71
|
+
export declare function registerServiceWorker(options: RegisterServiceWorkerOptions): Promise<ServiceWorkerRegistration | null>;
|
|
72
|
+
|
|
73
|
+
export declare interface RegisterServiceWorkerOptions {
|
|
74
|
+
/** Public URL of the compiled service worker file (e.g. `/sw.js`). */
|
|
75
|
+
url: string;
|
|
76
|
+
/** SW scope (default: SW directory). */
|
|
77
|
+
scope?: string;
|
|
78
|
+
/** Called once the registration is active. */
|
|
79
|
+
onReady?: (registration: ServiceWorkerRegistration) => void;
|
|
80
|
+
/**
|
|
81
|
+
* Called when a new worker has finished installing while another worker
|
|
82
|
+
* still controls the page. The host app typically prompts the user to
|
|
83
|
+
* reload and then calls {@link skipWaiting} on the returned worker.
|
|
84
|
+
*/
|
|
85
|
+
onUpdate?: (waiting: ServiceWorker, registration: ServiceWorkerRegistration) => void;
|
|
86
|
+
/** Called on registration failure. */
|
|
87
|
+
onError?: (error: unknown) => void;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Tell a waiting worker to activate immediately. Pair with `onUpdate` to roll
|
|
92
|
+
* out updates after the user confirms a reload prompt.
|
|
93
|
+
*/
|
|
94
|
+
export declare function skipWaiting(worker: ServiceWorker): void;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Unregister all registered service workers for this origin.
|
|
98
|
+
*
|
|
99
|
+
* @returns Number of workers that were unregistered.
|
|
100
|
+
*/
|
|
101
|
+
export declare function unregisterAllServiceWorkers(): Promise<number>;
|
|
102
|
+
|
|
103
|
+
export { }
|
package/dist/sw.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
async function d(n) {
|
|
2
|
+
if (typeof navigator > "u" || !("serviceWorker" in navigator))
|
|
3
|
+
return null;
|
|
4
|
+
try {
|
|
5
|
+
const t = await navigator.serviceWorker.register(n.url, {
|
|
6
|
+
scope: n.scope
|
|
7
|
+
});
|
|
8
|
+
return t.active && n.onReady?.(t), t.addEventListener("updatefound", () => {
|
|
9
|
+
const i = t.installing;
|
|
10
|
+
i && i.addEventListener("statechange", () => {
|
|
11
|
+
i.state === "installed" && navigator.serviceWorker.controller && n.onUpdate?.(i, t);
|
|
12
|
+
});
|
|
13
|
+
}), t;
|
|
14
|
+
} catch (t) {
|
|
15
|
+
return n.onError?.(t), null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function g(n) {
|
|
19
|
+
n.postMessage({ type: "SKIP_WAITING" });
|
|
20
|
+
}
|
|
21
|
+
async function v() {
|
|
22
|
+
if (typeof navigator > "u" || !("serviceWorker" in navigator)) return 0;
|
|
23
|
+
const n = await navigator.serviceWorker.getRegistrations();
|
|
24
|
+
let t = 0;
|
|
25
|
+
for (const i of n)
|
|
26
|
+
await i.unregister() && (t += 1);
|
|
27
|
+
return t;
|
|
28
|
+
}
|
|
29
|
+
function l() {
|
|
30
|
+
return globalThis;
|
|
31
|
+
}
|
|
32
|
+
function y(n = {}) {
|
|
33
|
+
const t = l(), { defaultTitle: i = "Notificação", defaultIcon: e, defaultBadge: o, transform: s } = n;
|
|
34
|
+
t.addEventListener("push", (a) => {
|
|
35
|
+
if (!a.data) return;
|
|
36
|
+
let c;
|
|
37
|
+
try {
|
|
38
|
+
c = a.data.json();
|
|
39
|
+
} catch {
|
|
40
|
+
c = { title: i, body: a.data.text() };
|
|
41
|
+
}
|
|
42
|
+
const r = s ? s(c) : c;
|
|
43
|
+
if (!r) return;
|
|
44
|
+
const u = r.title ?? i, f = {
|
|
45
|
+
body: r.body,
|
|
46
|
+
icon: r.icon ?? e,
|
|
47
|
+
badge: r.badge ?? o,
|
|
48
|
+
image: r.image,
|
|
49
|
+
tag: r.tag,
|
|
50
|
+
data: { url: r.url ?? "/", ...r.data ?? {} }
|
|
51
|
+
};
|
|
52
|
+
a.waitUntil(t.registration.showNotification(u, f));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function p(n = {}) {
|
|
56
|
+
const t = l(), i = n.resolveUrl ?? ((e) => {
|
|
57
|
+
if (typeof e == "string") return e;
|
|
58
|
+
if (e && typeof e == "object" && "url" in e) {
|
|
59
|
+
const o = e.url;
|
|
60
|
+
return typeof o == "string" ? o : "/";
|
|
61
|
+
}
|
|
62
|
+
return "/";
|
|
63
|
+
});
|
|
64
|
+
t.addEventListener("notificationclick", (e) => {
|
|
65
|
+
e.notification.close();
|
|
66
|
+
const o = i(e.notification.data);
|
|
67
|
+
e.waitUntil(
|
|
68
|
+
(async () => {
|
|
69
|
+
const s = await t.clients.matchAll({
|
|
70
|
+
type: "window",
|
|
71
|
+
includeUncontrolled: !0
|
|
72
|
+
});
|
|
73
|
+
for (const a of s)
|
|
74
|
+
if (a.url.includes(o))
|
|
75
|
+
return a.focus();
|
|
76
|
+
return t.clients.openWindow(o);
|
|
77
|
+
})()
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function w() {
|
|
82
|
+
const n = l();
|
|
83
|
+
n.addEventListener("message", (t) => {
|
|
84
|
+
t.data?.type === "SKIP_WAITING" && n.skipWaiting();
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
export {
|
|
88
|
+
p as installNotificationClickHandler,
|
|
89
|
+
y as installPushHandler,
|
|
90
|
+
w as installSkipWaitingListener,
|
|
91
|
+
d as registerServiceWorker,
|
|
92
|
+
g as skipWaiting,
|
|
93
|
+
v as unregisterAllServiceWorkers
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=sw.js.map
|
package/dist/sw.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sw.js","sources":["../src/sw/register-service-worker.ts","../src/sw/create-push-handler.ts"],"sourcesContent":["export interface RegisterServiceWorkerOptions {\n /** Public URL of the compiled service worker file (e.g. `/sw.js`). */\n url: string;\n /** SW scope (default: SW directory). */\n scope?: string;\n /** Called once the registration is active. */\n onReady?: (registration: ServiceWorkerRegistration) => void;\n /**\n * Called when a new worker has finished installing while another worker\n * still controls the page. The host app typically prompts the user to\n * reload and then calls {@link skipWaiting} on the returned worker.\n */\n onUpdate?: (waiting: ServiceWorker, registration: ServiceWorkerRegistration) => void;\n /** Called on registration failure. */\n onError?: (error: unknown) => void;\n}\n\n/**\n * Register a service worker with consistent update-detection wiring.\n *\n * Skips silently when the runtime has no `serviceWorker` support. The host\n * app keeps full control over the SW file — this helper only handles the\n * boilerplate around `register()` and `updatefound`.\n *\n * @returns The registration when it succeeds, or `null` when unsupported.\n */\nexport async function registerServiceWorker(\n options: RegisterServiceWorkerOptions,\n): Promise<ServiceWorkerRegistration | null> {\n if (typeof navigator === \"undefined\" || !(\"serviceWorker\" in navigator)) {\n return null;\n }\n\n try {\n const registration = await navigator.serviceWorker.register(options.url, {\n scope: options.scope,\n });\n\n if (registration.active) options.onReady?.(registration);\n\n registration.addEventListener(\"updatefound\", () => {\n const installing = registration.installing;\n if (!installing) return;\n installing.addEventListener(\"statechange\", () => {\n if (installing.state === \"installed\" && navigator.serviceWorker.controller) {\n options.onUpdate?.(installing, registration);\n }\n });\n });\n\n return registration;\n } catch (error) {\n options.onError?.(error);\n return null;\n }\n}\n\n/**\n * Tell a waiting worker to activate immediately. Pair with `onUpdate` to roll\n * out updates after the user confirms a reload prompt.\n */\nexport function skipWaiting(worker: ServiceWorker): void {\n worker.postMessage({ type: \"SKIP_WAITING\" });\n}\n\n/**\n * Unregister all registered service workers for this origin.\n *\n * @returns Number of workers that were unregistered.\n */\nexport async function unregisterAllServiceWorkers(): Promise<number> {\n if (typeof navigator === \"undefined\" || !(\"serviceWorker\" in navigator)) return 0;\n const registrations = await navigator.serviceWorker.getRegistrations();\n let count = 0;\n for (const registration of registrations) {\n const result = await registration.unregister();\n if (result) count += 1;\n }\n return count;\n}\n","/**\n * Service-worker context helpers for handling `push` and `notificationclick`\n * events. Import these inside your own `sw.ts` — they expect to run in the\n * service-worker global scope, not in the main thread.\n *\n * @example\n * /// <reference lib=\"webworker\" />\n * import { installPushHandler, installNotificationClickHandler } from \"tempest-react-sdk\";\n *\n * installPushHandler({ defaultIcon: \"/icons/Logo.png\" });\n * installNotificationClickHandler();\n */\n\ninterface SwGlobal {\n registration: {\n showNotification(title: string, options?: NotificationOptions): Promise<void>;\n };\n clients: {\n matchAll(options: { type: \"window\"; includeUncontrolled?: boolean }): Promise<\n {\n url: string;\n focused: boolean;\n focus(): Promise<unknown>;\n navigate(url: string): Promise<unknown>;\n }[]\n >;\n openWindow(url: string): Promise<unknown>;\n };\n addEventListener(\n type: \"push\",\n listener: (event: {\n data: { json(): unknown; text(): string } | null;\n waitUntil(promise: Promise<unknown>): void;\n }) => void,\n ): void;\n addEventListener(\n type: \"notificationclick\",\n listener: (event: {\n notification: { close(): void; data?: unknown };\n waitUntil(promise: Promise<unknown>): void;\n }) => void,\n ): void;\n skipWaiting(): Promise<void>;\n}\n\nfunction getSwScope(): SwGlobal {\n return globalThis as unknown as SwGlobal;\n}\n\nexport interface PushPayload {\n title?: string;\n body?: string;\n icon?: string;\n badge?: string;\n image?: string;\n tag?: string;\n url?: string;\n /** Arbitrary extra data forwarded to `event.notification.data`. */\n data?: Record<string, unknown>;\n}\n\nexport interface InstallPushHandlerOptions {\n /** Title used when the payload omits one. */\n defaultTitle?: string;\n /** Icon used when the payload omits one. */\n defaultIcon?: string;\n /** Badge image (mobile). */\n defaultBadge?: string;\n /**\n * Transform the raw payload before showing the notification. Return `null`\n * to suppress the notification entirely (e.g. silent pings).\n */\n transform?: (payload: PushPayload) => PushPayload | null;\n}\n\n/**\n * Install a `push` event listener that parses the payload as JSON (with a\n * plain-text fallback) and shows a notification.\n */\nexport function installPushHandler(options: InstallPushHandlerOptions = {}): void {\n const sw = getSwScope();\n const { defaultTitle = \"Notificação\", defaultIcon, defaultBadge, transform } = options;\n\n sw.addEventListener(\"push\", (event) => {\n if (!event.data) return;\n\n let raw: PushPayload;\n try {\n raw = event.data.json() as PushPayload;\n } catch {\n raw = { title: defaultTitle, body: event.data.text() };\n }\n\n const payload = transform ? transform(raw) : raw;\n if (!payload) return;\n\n const title = payload.title ?? defaultTitle;\n const notification: NotificationOptions & { image?: string } = {\n body: payload.body,\n icon: payload.icon ?? defaultIcon,\n badge: payload.badge ?? defaultBadge,\n image: payload.image,\n tag: payload.tag,\n data: { url: payload.url ?? \"/\", ...(payload.data ?? {}) },\n };\n\n event.waitUntil(sw.registration.showNotification(title, notification));\n });\n}\n\nexport interface InstallNotificationClickHandlerOptions {\n /** Resolve the destination URL from the notification data. Default: `data.url`. */\n resolveUrl?: (data: unknown) => string;\n}\n\n/**\n * Install a `notificationclick` handler that focuses an existing client when\n * possible and falls back to opening a new window.\n */\nexport function installNotificationClickHandler(\n options: InstallNotificationClickHandlerOptions = {},\n): void {\n const sw = getSwScope();\n const resolveUrl =\n options.resolveUrl ??\n ((data: unknown) => {\n if (typeof data === \"string\") return data;\n if (data && typeof data === \"object\" && \"url\" in data) {\n const url = (data as Record<string, unknown>).url;\n return typeof url === \"string\" ? url : \"/\";\n }\n return \"/\";\n });\n\n sw.addEventListener(\"notificationclick\", (event) => {\n event.notification.close();\n const target = resolveUrl(event.notification.data);\n\n event.waitUntil(\n (async () => {\n const clients = await sw.clients.matchAll({\n type: \"window\",\n includeUncontrolled: true,\n });\n for (const client of clients) {\n if (client.url.includes(target)) {\n return client.focus();\n }\n }\n return sw.clients.openWindow(target);\n })(),\n );\n });\n}\n\n/**\n * Install a `message` listener that activates a waiting worker when the host\n * app sends `{ type: \"SKIP_WAITING\" }`.\n */\nexport function installSkipWaitingListener(): void {\n const sw = getSwScope() as SwGlobal & {\n addEventListener(\n type: \"message\",\n listener: (event: { data?: { type?: string } }) => void,\n ): void;\n };\n sw.addEventListener(\"message\", (event) => {\n if (event.data?.type === \"SKIP_WAITING\") {\n void sw.skipWaiting();\n }\n });\n}\n"],"names":["registerServiceWorker","options","registration","installing","error","skipWaiting","worker","unregisterAllServiceWorkers","registrations","count","getSwScope","installPushHandler","sw","defaultTitle","defaultIcon","defaultBadge","transform","event","raw","payload","title","notification","installNotificationClickHandler","resolveUrl","data","url","target","clients","client","installSkipWaitingListener"],"mappings":"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"}
|