release: WRNexusJS 0.4.0

This commit is contained in:
2026-07-27 12:42:18 +05:30
parent 8b728a3e5d
commit 30e5721e84
250 changed files with 10065 additions and 3923 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/mobile",
"version": "0.3.6",
"version": "0.4.0",
"type": "module",
"main": "src/index.ts",
"exports": {
+96
View File
@@ -0,0 +1,96 @@
export interface DeepLink {
url: URL;
path: string;
query: URLSearchParams;
}
export function parseDeepLink(value: string, schemes: string[] = []): DeepLink | null {
try {
const url = new URL(value);
if (schemes.length && !schemes.includes(url.protocol.replace(/:$/, ""))) return null;
return { url, path: url.pathname || "/", query: url.searchParams };
} catch {
return null;
}
}
export interface OfflineTask<T = unknown> {
id: string;
type: string;
payload: T;
createdAt: number;
attempts: number;
}
export interface OfflineTaskStore {
load(): Promise<OfflineTask[]>;
save(tasks: OfflineTask[]): Promise<void>;
}
export function memoryOfflineTaskStore(): OfflineTaskStore {
let tasks: OfflineTask[] = [];
return {
async load() {
return structuredClone(tasks);
},
async save(next) {
tasks = structuredClone(next);
},
};
}
export class OfflineQueue {
readonly #handlers = new Map<string, (payload: unknown) => Promise<void>>();
constructor(private readonly store: OfflineTaskStore = memoryOfflineTaskStore()) {}
process<T>(type: string, handler: (payload: T) => Promise<void>): void {
this.#handlers.set(type, handler as (payload: unknown) => Promise<void>);
}
async add<T>(type: string, payload: T): Promise<OfflineTask<T>> {
const tasks = await this.store.load();
const task = { id: crypto.randomUUID(), type, payload, createdAt: Date.now(), attempts: 0 };
tasks.push(task);
await this.store.save(tasks);
return task;
}
async sync(limit = 20): Promise<{ completed: number; failed: number }> {
const tasks = await this.store.load();
const remaining: OfflineTask[] = [];
let completed = 0,
failed = 0;
for (const task of tasks) {
if (completed + failed >= limit) {
remaining.push(task);
continue;
}
const handler = this.#handlers.get(task.type);
if (!handler) {
remaining.push(task);
continue;
}
try {
task.attempts++;
await handler(task.payload);
completed++;
} catch {
failed++;
remaining.push(task);
}
}
await this.store.save(remaining);
return { completed, failed };
}
async size(): Promise<number> {
return (await this.store.load()).length;
}
}
export interface MobileEnvironment {
platform: string;
native: boolean;
online: boolean;
userAgent?: string;
}
export function mobileEnvironment(): MobileEnvironment {
const capacitor = (globalThis as any).Capacitor;
const native = capacitor?.isNativePlatform?.() === true;
return {
platform: capacitor?.getPlatform?.() ?? "web",
native,
online: typeof navigator === "undefined" ? true : navigator.onLine,
userAgent: typeof navigator === "undefined" ? undefined : navigator.userAgent,
};
}
+7
View File
@@ -89,3 +89,10 @@ export const mobile = {
invoke,
whenNative,
};
export {
parseDeepLink,
memoryOfflineTaskStore,
OfflineQueue,
mobileEnvironment,
} from "./advanced.ts";
export type { DeepLink, OfflineTask, OfflineTaskStore, MobileEnvironment } from "./advanced.ts";