@nicnocquee/dataqueue 1.33.0 → 1.34.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.
@@ -0,0 +1,189 @@
1
+ ---
2
+ name: dataqueue-react
3
+ description: React SDK and Dashboard patterns for DataQueue — useJob hook, DataqueueProvider, admin dashboard.
4
+ ---
5
+
6
+ # DataQueue React & Dashboard Patterns
7
+
8
+ ## React SDK — @nicnocquee/dataqueue-react
9
+
10
+ ### Installation
11
+
12
+ ```bash
13
+ npm install @nicnocquee/dataqueue-react
14
+ ```
15
+
16
+ Requires React 18+.
17
+
18
+ ### useJob Hook
19
+
20
+ Poll a job's status and progress from the browser.
21
+
22
+ ```tsx
23
+ 'use client';
24
+ import { useJob } from '@nicnocquee/dataqueue-react';
25
+
26
+ function JobTracker({ jobId }: { jobId: number }) {
27
+ const { status, progress, data, isLoading, error } = useJob(jobId, {
28
+ fetcher: (id) =>
29
+ fetch(`/api/jobs/${id}`)
30
+ .then((r) => r.json())
31
+ .then((d) => d.job),
32
+ pollingInterval: 1000,
33
+ onComplete: (job) => toast.success('Done!'),
34
+ onFailed: (job) => toast.error('Failed'),
35
+ onStatusChange: (newStatus, oldStatus) => {
36
+ console.log(`${oldStatus} → ${newStatus}`);
37
+ },
38
+ });
39
+
40
+ if (isLoading) return <p>Loading...</p>;
41
+ if (error) return <p>Error: {error.message}</p>;
42
+
43
+ return (
44
+ <div>
45
+ <p>Status: {status}</p>
46
+ <progress value={progress ?? 0} max={100} />
47
+ </div>
48
+ );
49
+ }
50
+ ```
51
+
52
+ Polling stops automatically on terminal statuses (`completed`, `failed`, `cancelled`).
53
+
54
+ ### DataqueueProvider
55
+
56
+ Avoid repeating `fetcher` and `pollingInterval` by wrapping your app in a provider.
57
+
58
+ ```tsx
59
+ 'use client';
60
+ import { DataqueueProvider } from '@nicnocquee/dataqueue-react';
61
+
62
+ const fetcher = (id: number) =>
63
+ fetch(`/api/jobs/${id}`)
64
+ .then((r) => r.json())
65
+ .then((d) => d.job);
66
+
67
+ export function Providers({ children }: { children: React.ReactNode }) {
68
+ return (
69
+ <DataqueueProvider fetcher={fetcher} pollingInterval={2000}>
70
+ {children}
71
+ </DataqueueProvider>
72
+ );
73
+ }
74
+ ```
75
+
76
+ Then use `useJob` without config:
77
+
78
+ ```tsx
79
+ const { status, progress } = useJob(jobId);
80
+ ```
81
+
82
+ ### API Route for Job Fetching (Next.js)
83
+
84
+ ```typescript
85
+ // app/api/jobs/[id]/route.ts
86
+ import { getJobQueue } from '@/lib/queue';
87
+ import { NextResponse } from 'next/server';
88
+
89
+ export async function GET(
90
+ _request: Request,
91
+ { params }: { params: Promise<{ id: string }> },
92
+ ) {
93
+ const { id } = await params;
94
+ const jobQueue = getJobQueue();
95
+ const job = await jobQueue.getJob(Number(id));
96
+ if (!job) {
97
+ return NextResponse.json({ error: 'Job not found' }, { status: 404 });
98
+ }
99
+ return NextResponse.json({ job });
100
+ }
101
+ ```
102
+
103
+ ### useJob Return Value
104
+
105
+ | Field | Type | Description |
106
+ | ----------- | ------------------- | ------------------------------- |
107
+ | `data` | `JobData \| null` | Latest job data from fetcher |
108
+ | `status` | `JobStatus \| null` | Current job status |
109
+ | `progress` | `number \| null` | Progress percentage (0–100) |
110
+ | `isLoading` | `boolean` | True until first fetch resolves |
111
+ | `error` | `Error \| null` | Last fetch error |
112
+
113
+ ## Dashboard — @nicnocquee/dataqueue-dashboard
114
+
115
+ ### Installation
116
+
117
+ ```bash
118
+ npm install @nicnocquee/dataqueue-dashboard
119
+ ```
120
+
121
+ ### Setup (Next.js App Router)
122
+
123
+ Create a single catch-all route:
124
+
125
+ ```typescript
126
+ // app/admin/dataqueue/[[...path]]/route.ts
127
+ import { createDataqueueDashboard } from '@nicnocquee/dataqueue-dashboard/next';
128
+ import { getJobQueue, jobHandlers } from '@/lib/queue';
129
+
130
+ const { GET, POST } = createDataqueueDashboard({
131
+ jobQueue: getJobQueue(),
132
+ jobHandlers,
133
+ basePath: '/admin/dataqueue',
134
+ });
135
+
136
+ export { GET, POST };
137
+ ```
138
+
139
+ Visit `/admin/dataqueue` to open the dashboard.
140
+
141
+ The `basePath` must match the route file directory. For example, `app/jobs/dashboard/[[...path]]/route.ts` requires `basePath: '/jobs/dashboard'`.
142
+
143
+ ### Dashboard Features
144
+
145
+ - Jobs list with status filter tabs, pagination, auto-refresh
146
+ - Job detail view with payload, error history, step data, events timeline
147
+ - Inline actions: cancel pending/waiting jobs, retry failed/cancelled jobs
148
+ - Process Jobs button for one-shot processing (useful in dev)
149
+
150
+ ### Protecting the Dashboard
151
+
152
+ Wrap the handlers with your auth logic:
153
+
154
+ ```typescript
155
+ const dashboard = createDataqueueDashboard({
156
+ jobQueue: getJobQueue(),
157
+ jobHandlers,
158
+ basePath: '/admin/dataqueue',
159
+ });
160
+
161
+ export async function GET(req: Request, ctx: any) {
162
+ const session = await auth();
163
+ if (!session?.user?.isAdmin) {
164
+ return new Response('Unauthorized', { status: 401 });
165
+ }
166
+ return dashboard.GET(req, ctx);
167
+ }
168
+
169
+ export async function POST(req: Request, ctx: any) {
170
+ const session = await auth();
171
+ if (!session?.user?.isAdmin) {
172
+ return new Response('Unauthorized', { status: 401 });
173
+ }
174
+ return dashboard.POST(req, ctx);
175
+ }
176
+ ```
177
+
178
+ ### Progress Tracking from Handlers
179
+
180
+ Report progress via `ctx.setProgress(percent)` (0–100). The value persists to the database and is exposed via `getJob()` and the `useJob` hook's `progress` field.
181
+
182
+ ```typescript
183
+ const handler = async (payload, signal, ctx) => {
184
+ for (let i = 0; i < chunks.length; i++) {
185
+ await processChunk(chunks[i]);
186
+ await ctx.setProgress(Math.round(((i + 1) / chunks.length) * 100));
187
+ }
188
+ };
189
+ ```