@uploadista/server 0.1.3 → 0.2.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uploadista/server",
3
3
  "type": "module",
4
- "version": "0.1.3",
4
+ "version": "0.2.0",
5
5
  "description": "Core Server package for Uploadista",
6
6
  "license": "MIT",
7
7
  "author": "Uploadista",
@@ -20,23 +20,23 @@
20
20
  }
21
21
  },
22
22
  "dependencies": {
23
- "@uploadista/core": "0.1.3",
24
- "@uploadista/observability": "0.1.3",
25
- "@uploadista/event-broadcaster-memory": "0.1.3",
26
- "@uploadista/event-emitter-websocket": "0.1.3"
23
+ "@uploadista/core": "0.2.0",
24
+ "@uploadista/event-broadcaster-memory": "0.2.0",
25
+ "@uploadista/observability": "0.2.0",
26
+ "@uploadista/event-emitter-websocket": "0.2.0"
27
27
  },
28
28
  "devDependencies": {
29
- "@cloudflare/workers-types": "4.20260131.0",
29
+ "@cloudflare/workers-types": "4.20260213.0",
30
30
  "@effect/vitest": "0.27.0",
31
31
  "@types/express": "^5.0.0",
32
32
  "@types/node": "24.10.9",
33
- "effect": "3.19.15",
33
+ "effect": "3.19.17",
34
34
  "tsd": "0.33.0",
35
- "tsdown": "0.20.1",
35
+ "tsdown": "0.20.3",
36
36
  "typescript": "5.9.3",
37
37
  "vitest": "4.0.18",
38
38
  "zod": "4.3.6",
39
- "@uploadista/typescript-config": "0.1.3"
39
+ "@uploadista/typescript-config": "0.2.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "effect": "^3.0.0",
@@ -195,7 +195,7 @@ export const handleUploadChunk = (req: UploadChunkRequest) =>
195
195
  metricsService.recordUpload(clientId, fileResult.size, authMetadata),
196
196
  );
197
197
 
198
- // Execute onUploadComplete hook for usage tracking
198
+ // Execute onUploadComplete hook for usage tracking and billing
199
199
  const duration = Date.now() - startTime;
200
200
  yield* Effect.forkDaemon(
201
201
  usageHookService.onUploadComplete({
@@ -205,6 +205,15 @@ export const handleUploadChunk = (req: UploadChunkRequest) =>
205
205
  uploadId,
206
206
  fileSize: fileResult.size,
207
207
  duration,
208
+ storageId: fileResult.storage?.id,
209
+ url: fileResult.url,
210
+ fileName: fileResult.metadata?.fileName as string | undefined,
211
+ flowContext: fileResult.flow
212
+ ? {
213
+ flowId: fileResult.flow.flowId,
214
+ jobId: fileResult.flow.jobId,
215
+ }
216
+ : undefined,
208
217
  },
209
218
  }),
210
219
  );
@@ -2,6 +2,7 @@ import type { PluginLayer, UploadistaError } from "@uploadista/core";
2
2
  import {
3
3
  deadLetterQueueService,
4
4
  type Flow,
5
+ FlowLifecycleHook,
5
6
  FlowProvider,
6
7
  FlowWaitUntil,
7
8
  kvCircuitBreakerStoreLayer,
@@ -24,7 +25,7 @@ import { handleFlowError } from "../http-utils";
24
25
  import { createFlowEngineLayer, createUploadEngineLayer } from "../layer-utils";
25
26
  import { AuthContextServiceLive } from "../service";
26
27
  import type { AuthContext } from "../types";
27
- import { UsageHookServiceLive } from "../usage-hooks/service";
28
+ import { UsageHookService, UsageHookServiceLive } from "../usage-hooks/service";
28
29
  import { handleUploadistaRequest } from "./http-handlers/http-handlers";
29
30
  import type { ExtractFlowPluginRequirements } from "./plugin-types";
30
31
  import type { NotFoundResponse } from "./routes";
@@ -291,6 +292,27 @@ export const createUploadistaServer = async <
291
292
  // Create usage hook layer (defaults to no-op if not configured)
292
293
  const usageHookLayer = UsageHookServiceLive(usageHooks);
293
294
 
295
+ // Bridge UsageHookService.onFlowComplete to FlowLifecycleHook
296
+ // so the flow engine can call it reliably from the execution daemon
297
+ const flowLifecycleHookLayer = Layer.effect(
298
+ FlowLifecycleHook,
299
+ Effect.gen(function* () {
300
+ const usageHookService = yield* UsageHookService;
301
+ return {
302
+ onComplete: (ctx) =>
303
+ usageHookService.onFlowComplete({
304
+ clientId: ctx.clientId ?? "",
305
+ operation: "flow",
306
+ metadata: {
307
+ jobId: ctx.jobId,
308
+ flowId: ctx.flowId,
309
+ status: ctx.status === "completed" ? "success" : "failed",
310
+ },
311
+ }),
312
+ };
313
+ }),
314
+ ).pipe(Layer.provide(usageHookLayer));
315
+
294
316
  /**
295
317
  * Merge all server layers including plugins.
296
318
  *
@@ -304,6 +326,7 @@ export const createUploadistaServer = async <
304
326
  effectiveMetricsLayer,
305
327
  authCacheLayer,
306
328
  usageHookLayer,
329
+ flowLifecycleHookLayer,
307
330
  ...plugins,
308
331
  ...(circuitBreakerStoreLayer ? [circuitBreakerStoreLayer] : []),
309
332
  ...(dlqLayer ? [dlqLayer] : []),
@@ -64,6 +64,15 @@ export interface UploadUsageMetadata extends BaseUsageMetadata {
64
64
  uploadId?: string;
65
65
  /** Duration of the upload in milliseconds */
66
66
  duration?: number;
67
+ /** Storage configuration identifier (for database persistence) */
68
+ storageId?: string;
69
+ /** URL of the uploaded file (for database persistence) */
70
+ url?: string;
71
+ /** Flow context if this upload was initiated as part of a flow (for double-counting prevention) */
72
+ flowContext?: {
73
+ flowId: string;
74
+ jobId: string;
75
+ };
67
76
  }
68
77
 
69
78
  /**