@jayethian/axiom 0.1.0 → 0.1.2

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.
@@ -1,96 +0,0 @@
1
- import { AxiomStorageAdapter } from '../adapters';
2
- import { AxiomConfig, QueuedRequest } from '../types';
3
-
4
- export class SyncManager {
5
- private isSyncing = false;
6
-
7
- constructor(
8
- private storage: AxiomStorageAdapter,
9
- private config: AxiomConfig
10
- ) {}
11
-
12
- /**
13
- * The master trigger. Call this when the OS reports network is back online.
14
- */
15
- public async flushQueue(): Promise<void> {
16
- // Prevent overlapping syncs if the network toggles rapidly
17
- if (this.isSyncing) return;
18
- this.isSyncing = true;
19
-
20
- try {
21
- const pending = await this.storage.getAll();
22
-
23
- if (pending.length === 0) {
24
- this.isSyncing = false;
25
- return;
26
- }
27
-
28
- console.log(`[Axiom] Network restored. Syncing ${pending.length} queued requests...`);
29
-
30
- // We process sequentially to maintain the order of user actions
31
- for (const request of pending) {
32
- await this.processRequest(request);
33
- }
34
-
35
- } finally {
36
- this.isSyncing = false;
37
- }
38
- }
39
-
40
- /**
41
- * Attempts to execute a single saved request.
42
- */
43
- private async processRequest(request: QueuedRequest): Promise<void> {
44
- let reqToSync = request;
45
-
46
- // MITIGATION 1: Just-in-Time Headers (Refresh Auth Tokens)
47
- if (this.config.onBeforeSync) {
48
- try {
49
- reqToSync = await this.config.onBeforeSync(request);
50
- } catch (error) {
51
- console.error(`[Axiom] onBeforeSync failed for ${request.id}. Skipping.`);
52
- return;
53
- }
54
- }
55
-
56
- try {
57
- const response = await fetch(reqToSync.url, {
58
- method: reqToSync.method,
59
- headers: reqToSync.headers,
60
- body: reqToSync.body
61
- });
62
-
63
- // If it's a success OR a permanent 400 error (like bad data), remove it.
64
- if (response.ok || (response.status >= 400 && response.status < 500)) {
65
- await this.storage.remove(reqToSync.id);
66
- console.log(`[Axiom] Request ${reqToSync.id} synced successfully.`);
67
- } else {
68
- // It's a 500 Server Error. Treat as a failure and retry later.
69
- await this.handleFailure(reqToSync);
70
- }
71
- } catch (error) {
72
- // Network dropped again mid-sync.
73
- await this.handleFailure(reqToSync);
74
- }
75
- }
76
-
77
- /**
78
- * MITIGATION 2: The Dead Letter Queue logic
79
- */
80
- private async handleFailure(request: QueuedRequest): Promise<void> {
81
- request.retryCount += 1;
82
- const maxRetries = this.config.maxRetries || 3;
83
-
84
- if (request.retryCount >= maxRetries) {
85
- console.warn(`[Axiom] Request ${request.id} failed ${maxRetries} times. Moving to Dead Letter.`);
86
- await this.storage.remove(request.id);
87
-
88
- if (this.config.onDeadLetter) {
89
- this.config.onDeadLetter(request, new Error('Max retries exceeded'));
90
- }
91
- } else {
92
- // Save the updated retry count back to storage
93
- await this.storage.save(request);
94
- }
95
- }
96
- }
package/src/index.ts DELETED
@@ -1,6 +0,0 @@
1
- export * from './types';
2
- export * from './adapters';
3
- export * from './adapters/memory';
4
- export { axiom, AxiomEngine } from './engine/fetcher';
5
- export { AxiomProvider } from './react/AxiomProvider';
6
- export { useAxiomQueue } from './react/useAxiomQueue';
@@ -1,57 +0,0 @@
1
- import React, { createContext, useContext, useEffect, useState } from 'react';
2
- import { axiom } from '../engine/fetcher';
3
- import { AxiomConfig } from '../types';
4
- import { AxiomStorageAdapter } from '../adapters';
5
-
6
- interface AxiomContextType {
7
- isOnline: boolean;
8
- forceSync: () => Promise<void>;
9
- }
10
-
11
- // Create a safe default context
12
- const AxiomContext = createContext<AxiomContextType>({
13
- isOnline: true,
14
- forceSync: async () => {},
15
- });
16
-
17
- export const AxiomProvider: React.FC<{
18
- config: AxiomConfig;
19
- storageAdapter?: AxiomStorageAdapter;
20
- /** * A function that takes a callback, calls it whenever network state changes,
21
- * and returns an unsubscribe function.
22
- */
23
- networkListener: (callback: (isOnline: boolean) => void) => any;
24
- children: React.ReactNode;
25
- }> = ({ config, storageAdapter, networkListener, children }) => {
26
- const [isOnline, setIsOnline] = useState(true);
27
-
28
- useEffect(() => {
29
- // 1. Boot up the Axiom engine
30
- axiom.create(config, storageAdapter);
31
-
32
- // 2. Attach the OS-level network listener
33
- const unsubscribe = networkListener((onlineStatus) => {
34
- setIsOnline(onlineStatus);
35
-
36
- // 3. The Magic: If the internet comes back, automatically flush the queue
37
- if (onlineStatus) {
38
- axiom.forceSync();
39
- }
40
- });
41
-
42
- // Cleanup listener on unmount
43
- return () => {
44
- if (typeof unsubscribe === 'function') {
45
- unsubscribe();
46
- }
47
- };
48
- }, [config, storageAdapter, networkListener]);
49
-
50
- return (
51
- <AxiomContext.Provider value={{ isOnline, forceSync: () => axiom.forceSync() }}>
52
- {children}
53
- </AxiomContext.Provider>
54
- );
55
- };
56
-
57
- export const useAxiomContext = () => useContext(AxiomContext);
@@ -1,12 +0,0 @@
1
- import { useAxiomContext } from './AxiomProvider';
2
-
3
- export function useAxiomQueue() {
4
- const { isOnline, forceSync } = useAxiomContext();
5
-
6
- return {
7
- /** Boolean indicating if the device currently has an active connection */
8
- isOnline,
9
- /** Manually trigger the background sync manager */
10
- forceSync,
11
- };
12
- }
package/src/types.ts DELETED
@@ -1,20 +0,0 @@
1
- export type RequestPriority = 'urgent' | 'background';
2
-
3
- export interface QueuedRequest {
4
- id: string;
5
- timestamp: number;
6
- url: string;
7
- method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
8
- headers: Record<string, string>;
9
- body?: string;
10
- priority: RequestPriority;
11
- retryCount: number;
12
- }
13
-
14
- export interface AxiomConfig {
15
- baseURL?: string;
16
- defaultHeaders?: Record<string, string>;
17
- maxRetries?: number;
18
- onBeforeSync?: (request: QueuedRequest) => Promise<QueuedRequest>;
19
- onDeadLetter?: (request: QueuedRequest, error: Error) => void;
20
- }
package/tsconfig.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "strict": true,
7
- "jsx": "react-jsx",
8
- "esModuleInterop": true,
9
- "skipLibCheck": true,
10
- "forceConsistentCasingInFileNames": true,
11
- "declaration": true,
12
- "ignoreDeprecations": "6.0"
13
- },
14
- "include": ["src/**/*"],
15
- "exclude": ["node_modules", "dist", "tests"]
16
- }