release: WRNexusJS 0.8.0
Quality / quality (ubuntu-latest) (push) Failing after 21s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
2026-08-02 23:18:51 +05:30
parent 87507edf59
commit 586a6db8ff
625 changed files with 243608 additions and 11210 deletions
+83 -1
View File
@@ -12,6 +12,84 @@ export function parseDeepLink(value: string, schemes: string[] = []): DeepLink |
return null;
}
}
export interface DeepLinkSource {
current?(): Promise<string | undefined>;
subscribe(listener: (url: string) => void): void | (() => void);
}
/** Normalize initial and live native links and ignore malformed/unapproved schemes. */
export function listenDeepLinks(
source: DeepLinkSource,
listener: (link: DeepLink) => void,
schemes: string[] = [],
): () => void {
let active = true;
const emit = (value: string) => {
const link = parseDeepLink(value, schemes);
if (active && link) listener(link);
};
void source.current?.().then((value) => value && emit(value));
const unsubscribe = source.subscribe(emit);
return () => {
active = false;
unsubscribe?.();
};
}
export interface PushRegistration {
token: string;
platform?: string;
}
export interface PushAdapter {
permission(): Promise<"granted" | "denied" | "prompt" | "unavailable">;
requestPermission?(): Promise<"granted" | "denied">;
register(): Promise<PushRegistration>;
subscribe?(listener: (notification: unknown) => void): () => void;
}
export class PushNotifications {
constructor(private readonly adapter: PushAdapter) {}
async register(): Promise<PushRegistration> {
let permission = await this.adapter.permission();
if (permission === "prompt" && this.adapter.requestPermission)
permission = await this.adapter.requestPermission();
if (permission !== "granted") throw new Error("WRN-MOBILE-PUSH-PERMISSION-DENIED");
const registration = await this.adapter.register();
if (!registration.token.trim()) throw new Error("WRN-MOBILE-PUSH-EMPTY-TOKEN");
return registration;
}
subscribe(listener: (notification: unknown) => void): () => void {
return this.adapter.subscribe?.(listener) ?? (() => undefined);
}
}
export interface SecureStorageAdapter {
get(key: string): Promise<string | null>;
set(key: string, value: string): Promise<void>;
remove(key: string): Promise<void>;
}
export class SecureStorage {
constructor(
private readonly adapter: SecureStorageAdapter,
private readonly namespace = "wrnexus",
) {}
#key(key: string): string {
if (!/^[A-Za-z0-9._-]{1,128}$/.test(key)) throw new TypeError("WRN-MOBILE-STORAGE-KEY");
return `${this.namespace}:${key}`;
}
get(key: string): Promise<string | null> {
return this.adapter.get(this.#key(key));
}
set(key: string, value: string): Promise<void> {
return this.adapter.set(this.#key(key), value);
}
remove(key: string): Promise<void> {
return this.adapter.remove(this.#key(key));
}
}
export interface OfflineTask<T = unknown> {
id: string;
type: string;
@@ -85,7 +163,11 @@ export interface MobileEnvironment {
userAgent?: string;
}
export function mobileEnvironment(): MobileEnvironment {
const capacitor = (globalThis as any).Capacitor;
const capacitor = (
globalThis as typeof globalThis & {
Capacitor?: { isNativePlatform?: () => boolean; getPlatform?: () => string };
}
).Capacitor;
const native = capacitor?.isNativePlatform?.() === true;
return {
platform: capacitor?.getPlatform?.() ?? "web",
+13 -1
View File
@@ -90,9 +90,21 @@ export const mobile = {
whenNative,
};
export {
listenDeepLinks,
parseDeepLink,
memoryOfflineTaskStore,
OfflineQueue,
PushNotifications,
SecureStorage,
mobileEnvironment,
} from "./advanced.ts";
export type { DeepLink, OfflineTask, OfflineTaskStore, MobileEnvironment } from "./advanced.ts";
export type {
DeepLink,
DeepLinkSource,
OfflineTask,
OfflineTaskStore,
MobileEnvironment,
PushAdapter,
PushRegistration,
SecureStorageAdapter,
} from "./advanced.ts";