release: WRNexusJS 0.4.0
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/mobile",
|
||||
"version": "0.3.6",
|
||||
"version": "0.4.0",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user