@uploadista/observability 0.0.3

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.
Files changed (118) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/.turbo/turbo-check.log +0 -0
  3. package/LICENSE +21 -0
  4. package/dist/core/errors.d.ts +8 -0
  5. package/dist/core/errors.d.ts.map +1 -0
  6. package/dist/core/errors.js +108 -0
  7. package/dist/core/index.d.ts +8 -0
  8. package/dist/core/index.d.ts.map +1 -0
  9. package/dist/core/index.js +8 -0
  10. package/dist/core/layers.d.ts +104 -0
  11. package/dist/core/layers.d.ts.map +1 -0
  12. package/dist/core/layers.js +110 -0
  13. package/dist/core/logging.d.ts +18 -0
  14. package/dist/core/logging.d.ts.map +1 -0
  15. package/dist/core/logging.js +41 -0
  16. package/dist/core/metrics.d.ts +37 -0
  17. package/dist/core/metrics.d.ts.map +1 -0
  18. package/dist/core/metrics.js +72 -0
  19. package/dist/core/testing.d.ts +43 -0
  20. package/dist/core/testing.d.ts.map +1 -0
  21. package/dist/core/testing.js +93 -0
  22. package/dist/core/tracing.d.ts +19 -0
  23. package/dist/core/tracing.d.ts.map +1 -0
  24. package/dist/core/tracing.js +43 -0
  25. package/dist/core/utilities.d.ts +11 -0
  26. package/dist/core/utilities.d.ts.map +1 -0
  27. package/dist/core/utilities.js +41 -0
  28. package/dist/flow/errors.d.ts +15 -0
  29. package/dist/flow/errors.d.ts.map +1 -0
  30. package/dist/flow/errors.js +66 -0
  31. package/dist/flow/index.d.ts +6 -0
  32. package/dist/flow/index.d.ts.map +1 -0
  33. package/dist/flow/index.js +6 -0
  34. package/dist/flow/layers.d.ts +40 -0
  35. package/dist/flow/layers.d.ts.map +1 -0
  36. package/dist/flow/layers.js +94 -0
  37. package/dist/flow/metrics.d.ts +52 -0
  38. package/dist/flow/metrics.d.ts.map +1 -0
  39. package/dist/flow/metrics.js +89 -0
  40. package/dist/flow/testing.d.ts +11 -0
  41. package/dist/flow/testing.d.ts.map +1 -0
  42. package/dist/flow/testing.js +27 -0
  43. package/dist/flow/tracing.d.ts +35 -0
  44. package/dist/flow/tracing.d.ts.map +1 -0
  45. package/dist/flow/tracing.js +42 -0
  46. package/dist/index.d.ts +8 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +14 -0
  49. package/dist/service/metrics.d.ts +23 -0
  50. package/dist/service/metrics.d.ts.map +1 -0
  51. package/dist/service/metrics.js +17 -0
  52. package/dist/storage/azure.d.ts +47 -0
  53. package/dist/storage/azure.d.ts.map +1 -0
  54. package/dist/storage/azure.js +89 -0
  55. package/dist/storage/filesystem.d.ts +47 -0
  56. package/dist/storage/filesystem.d.ts.map +1 -0
  57. package/dist/storage/filesystem.js +70 -0
  58. package/dist/storage/gcs.d.ts +47 -0
  59. package/dist/storage/gcs.d.ts.map +1 -0
  60. package/dist/storage/gcs.js +90 -0
  61. package/dist/storage/index.d.ts +5 -0
  62. package/dist/storage/index.d.ts.map +1 -0
  63. package/dist/storage/index.js +5 -0
  64. package/dist/storage/s3.d.ts +47 -0
  65. package/dist/storage/s3.d.ts.map +1 -0
  66. package/dist/storage/s3.js +67 -0
  67. package/dist/test-observability.d.ts +12 -0
  68. package/dist/test-observability.d.ts.map +1 -0
  69. package/dist/test-observability.js +153 -0
  70. package/dist/upload/errors.d.ts +16 -0
  71. package/dist/upload/errors.d.ts.map +1 -0
  72. package/dist/upload/errors.js +107 -0
  73. package/dist/upload/index.d.ts +6 -0
  74. package/dist/upload/index.d.ts.map +1 -0
  75. package/dist/upload/index.js +6 -0
  76. package/dist/upload/layers.d.ts +32 -0
  77. package/dist/upload/layers.d.ts.map +1 -0
  78. package/dist/upload/layers.js +63 -0
  79. package/dist/upload/metrics.d.ts +46 -0
  80. package/dist/upload/metrics.d.ts.map +1 -0
  81. package/dist/upload/metrics.js +80 -0
  82. package/dist/upload/testing.d.ts +32 -0
  83. package/dist/upload/testing.d.ts.map +1 -0
  84. package/dist/upload/testing.js +52 -0
  85. package/dist/upload/tracing.d.ts +25 -0
  86. package/dist/upload/tracing.d.ts.map +1 -0
  87. package/dist/upload/tracing.js +35 -0
  88. package/package.json +37 -0
  89. package/src/core/errors.ts +187 -0
  90. package/src/core/index.ts +9 -0
  91. package/src/core/layers.ts +205 -0
  92. package/src/core/logging.ts +81 -0
  93. package/src/core/metrics.ts +108 -0
  94. package/src/core/testing.ts +142 -0
  95. package/src/core/tracing.ts +67 -0
  96. package/src/core/utilities.ts +133 -0
  97. package/src/flow/errors.ts +95 -0
  98. package/src/flow/index.ts +17 -0
  99. package/src/flow/layers.ts +131 -0
  100. package/src/flow/metrics.ts +130 -0
  101. package/src/flow/testing.ts +33 -0
  102. package/src/flow/tracing.ts +72 -0
  103. package/src/index.ts +31 -0
  104. package/src/service/metrics.ts +31 -0
  105. package/src/storage/azure.ts +163 -0
  106. package/src/storage/filesystem.ts +153 -0
  107. package/src/storage/gcs.ts +161 -0
  108. package/src/storage/index.ts +5 -0
  109. package/src/storage/s3.ts +136 -0
  110. package/src/test-observability.ts +234 -0
  111. package/src/upload/errors.ts +166 -0
  112. package/src/upload/index.ts +12 -0
  113. package/src/upload/layers.ts +88 -0
  114. package/src/upload/metrics.ts +118 -0
  115. package/src/upload/testing.ts +60 -0
  116. package/src/upload/tracing.ts +58 -0
  117. package/tsconfig.json +10 -0
  118. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,166 @@
1
+ import { Effect, Metric } from "effect";
2
+ import type { UploadServerMetrics } from "./metrics.js";
3
+
4
+ // ============================================================================
5
+ // Upload Error Classification and Tracking
6
+ // ============================================================================
7
+
8
+ export type UploadErrorCategory =
9
+ | "network_error"
10
+ | "authentication_error"
11
+ | "authorization_error"
12
+ | "validation_error"
13
+ | "size_limit_error"
14
+ | "storage_error"
15
+ | "abort_error"
16
+ | "unknown_error";
17
+
18
+ /**
19
+ * Classify upload errors into standard categories
20
+ */
21
+ export const classifyUploadError = (error: unknown): UploadErrorCategory => {
22
+ if (!error || typeof error !== "object") return "unknown_error";
23
+
24
+ const errorCode = "code" in error ? error.code : undefined;
25
+ const errorName = "name" in error ? error.name : undefined;
26
+ const errorMessage =
27
+ error instanceof Error ? error.message.toLowerCase() : "";
28
+
29
+ // Abort errors
30
+ if (
31
+ errorCode === "ABORTED" ||
32
+ errorName === "AbortError" ||
33
+ errorMessage.includes("abort")
34
+ ) {
35
+ return "abort_error";
36
+ }
37
+
38
+ // Size limit errors
39
+ if (
40
+ errorCode === "FILE_TOO_LARGE" ||
41
+ errorCode === "LIMIT_FILE_SIZE" ||
42
+ errorCode === "RequestEntityTooLarge" ||
43
+ errorMessage.includes("too large") ||
44
+ errorMessage.includes("size limit") ||
45
+ errorMessage.includes("max size")
46
+ ) {
47
+ return "size_limit_error";
48
+ }
49
+
50
+ // Validation errors
51
+ if (
52
+ errorCode === "INVALID_FILE" ||
53
+ errorCode === "INVALID_METADATA" ||
54
+ errorCode === "VALIDATION_ERROR" ||
55
+ errorMessage.includes("validation") ||
56
+ errorMessage.includes("invalid")
57
+ ) {
58
+ return "validation_error";
59
+ }
60
+
61
+ // Network errors
62
+ if (
63
+ errorCode === "NetworkError" ||
64
+ errorCode === "ECONNRESET" ||
65
+ errorCode === "ENOTFOUND" ||
66
+ errorCode === "ETIMEDOUT" ||
67
+ errorMessage.includes("network") ||
68
+ errorMessage.includes("timeout")
69
+ ) {
70
+ return "network_error";
71
+ }
72
+
73
+ // Authentication errors
74
+ if (
75
+ errorCode === "UNAUTHORIZED" ||
76
+ errorCode === "AuthenticationFailed" ||
77
+ errorName === "AuthenticationError" ||
78
+ errorMessage.includes("authentication") ||
79
+ errorMessage.includes("unauthorized")
80
+ ) {
81
+ return "authentication_error";
82
+ }
83
+
84
+ // Authorization errors
85
+ if (
86
+ errorCode === "FORBIDDEN" ||
87
+ errorCode === "AccessDenied" ||
88
+ errorName === "AuthorizationError" ||
89
+ errorMessage.includes("forbidden") ||
90
+ errorMessage.includes("permission")
91
+ ) {
92
+ return "authorization_error";
93
+ }
94
+
95
+ // Storage errors
96
+ if (
97
+ errorCode === "FILE_WRITE_ERROR" ||
98
+ errorCode === "STORAGE_ERROR" ||
99
+ errorMessage.includes("storage") ||
100
+ errorMessage.includes("write error")
101
+ ) {
102
+ return "storage_error";
103
+ }
104
+
105
+ return "unknown_error";
106
+ };
107
+
108
+ /**
109
+ * Track upload errors with metrics and structured logging
110
+ */
111
+ export const trackUploadError = (
112
+ metrics: UploadServerMetrics,
113
+ operation: string,
114
+ error: unknown,
115
+ context: Record<string, unknown> = {},
116
+ ) =>
117
+ Effect.gen(function* () {
118
+ const errorCategory = classifyUploadError(error);
119
+
120
+ // Record error metrics
121
+ const errorMetric = metrics.uploadFailedTotal.pipe(
122
+ Metric.tagged("operation", operation),
123
+ Metric.tagged("error_category", errorCategory),
124
+ );
125
+ yield* errorMetric(Effect.succeed(1));
126
+
127
+ // Create detailed error context
128
+ const errorDetails = {
129
+ operation,
130
+ error_category: errorCategory,
131
+ error_type: typeof error,
132
+ error_message: error instanceof Error ? error.message : String(error),
133
+ error_code:
134
+ error && typeof error === "object" && "code" in error
135
+ ? String(error.code)
136
+ : undefined,
137
+ error_name:
138
+ error && typeof error === "object" && "name" in error
139
+ ? String(error.name)
140
+ : undefined,
141
+ ...context,
142
+ };
143
+
144
+ // Log structured error
145
+ yield* Effect.logError(`Upload ${operation} failed`).pipe(
146
+ Effect.annotateLogs(errorDetails),
147
+ );
148
+ });
149
+
150
+ /**
151
+ * Create a custom error classifier for upload operations
152
+ */
153
+ export const createUploadErrorClassifier = (
154
+ customErrorMapping?: (error: unknown) => UploadErrorCategory | null,
155
+ ) => {
156
+ return (error: unknown): UploadErrorCategory => {
157
+ // Try custom mapping first
158
+ if (customErrorMapping) {
159
+ const customResult = customErrorMapping(error);
160
+ if (customResult !== null) return customResult;
161
+ }
162
+
163
+ // Fall back to generic classification
164
+ return classifyUploadError(error);
165
+ };
166
+ };
@@ -0,0 +1,12 @@
1
+ // Upload observability exports
2
+ export * from "./metrics.js";
3
+ export * from "./tracing.js";
4
+ export {
5
+ makeUploadObservabilityLive,
6
+ UploadObservabilityLive,
7
+ getUploadMetrics,
8
+ withUploadDuration,
9
+ withChunkDuration,
10
+ } from "./layers.js";
11
+ export * from "./errors.js";
12
+ export * from "./testing.js";
@@ -0,0 +1,88 @@
1
+ import { Effect, Layer, Metric } from "effect";
2
+ import {
3
+ makeUploadObservabilityLayer,
4
+ UploadObservability,
5
+ } from "../core/layers.js";
6
+ import { createUploadServerMetrics } from "./metrics.js";
7
+
8
+ // ============================================================================
9
+ // Upload Observability Layer Implementation
10
+ // ============================================================================
11
+
12
+ /**
13
+ * Create a live upload observability layer with full metrics
14
+ */
15
+ export const makeUploadObservabilityLive = (
16
+ serviceName = "uploadista-upload-server",
17
+ ): Layer.Layer<UploadObservability> => {
18
+ const metrics = createUploadServerMetrics();
19
+
20
+ return Layer.succeed(UploadObservability, {
21
+ serviceName,
22
+ enabled: true,
23
+ metrics: {
24
+ uploadCreated: Effect.succeed(metrics.uploadCreatedTotal).pipe(
25
+ Effect.flatMap((metric) => Metric.increment(metric)),
26
+ ),
27
+ uploadCompleted: Effect.succeed(metrics.uploadCompletedTotal).pipe(
28
+ Effect.flatMap((metric) => Metric.increment(metric)),
29
+ ),
30
+ uploadFailed: Effect.succeed(metrics.uploadFailedTotal).pipe(
31
+ Effect.flatMap((metric) => Metric.increment(metric)),
32
+ ),
33
+ chunkUploaded: Effect.succeed(metrics.chunkUploadedTotal).pipe(
34
+ Effect.flatMap((metric) => Metric.increment(metric)),
35
+ ),
36
+ },
37
+ });
38
+ };
39
+
40
+ /**
41
+ * Default live upload observability layer
42
+ */
43
+ export const UploadObservabilityLive = makeUploadObservabilityLive();
44
+
45
+ /**
46
+ * No-op upload observability layer (for testing or disabled observability)
47
+ */
48
+ export const UploadObservabilityDisabled = makeUploadObservabilityLayer(false);
49
+
50
+ /**
51
+ * Helper to get upload metrics from context
52
+ */
53
+ export const getUploadMetrics = Effect.gen(function* () {
54
+ const obs = yield* UploadObservability;
55
+ return obs.metrics;
56
+ });
57
+
58
+ /**
59
+ * Helper to track upload duration
60
+ */
61
+ export const withUploadDuration = <A, E, R>(
62
+ effect: Effect.Effect<A, E, R>,
63
+ ): Effect.Effect<A, E, R | UploadObservability> => {
64
+ const metrics = createUploadServerMetrics();
65
+ return Effect.gen(function* () {
66
+ const startTime = Date.now();
67
+ const result = yield* effect;
68
+ const duration = (Date.now() - startTime) / 1000; // Convert to seconds
69
+ yield* Metric.update(metrics.uploadDurationHistogram, duration);
70
+ return result;
71
+ }).pipe(Effect.withSpan("upload-operation"));
72
+ };
73
+
74
+ /**
75
+ * Helper to track chunk upload duration
76
+ */
77
+ export const withChunkDuration = <A, E, R>(
78
+ effect: Effect.Effect<A, E, R>,
79
+ ): Effect.Effect<A, E, R> => {
80
+ const metrics = createUploadServerMetrics();
81
+ return Effect.gen(function* () {
82
+ const startTime = Date.now();
83
+ const result = yield* effect;
84
+ const duration = (Date.now() - startTime) / 1000; // Convert to seconds
85
+ yield* Metric.update(metrics.chunkUploadDurationHistogram, duration);
86
+ return result;
87
+ }).pipe(Effect.withSpan("chunk-upload"));
88
+ };
@@ -0,0 +1,118 @@
1
+ import { Metric, MetricBoundaries } from "effect";
2
+
3
+ // ============================================================================
4
+ // Upload Server Metrics
5
+ // ============================================================================
6
+
7
+ /**
8
+ * Upload server metrics for tracking upload operations
9
+ */
10
+ export const createUploadServerMetrics = () => ({
11
+ // Counter metrics
12
+ uploadCreatedTotal: Metric.counter("upload_created_total", {
13
+ description: "Total number of uploads created",
14
+ }),
15
+
16
+ uploadCompletedTotal: Metric.counter("upload_completed_total", {
17
+ description: "Total number of uploads completed successfully",
18
+ }),
19
+
20
+ uploadFailedTotal: Metric.counter("upload_failed_total", {
21
+ description: "Total number of uploads that failed",
22
+ }),
23
+
24
+ chunkUploadedTotal: Metric.counter("chunk_uploaded_total", {
25
+ description: "Total number of chunks uploaded",
26
+ }),
27
+
28
+ uploadFromUrlTotal: Metric.counter("upload_from_url_total", {
29
+ description: "Total number of URL-based uploads",
30
+ }),
31
+
32
+ uploadFromUrlSuccessTotal: Metric.counter("upload_from_url_success_total", {
33
+ description: "Total number of successful URL-based uploads",
34
+ }),
35
+
36
+ uploadFromUrlFailedTotal: Metric.counter("upload_from_url_failed_total", {
37
+ description: "Total number of failed URL-based uploads",
38
+ }),
39
+
40
+ // Histogram metrics
41
+ uploadDurationHistogram: Metric.histogram(
42
+ "upload_duration_seconds",
43
+ MetricBoundaries.exponential({
44
+ start: 0.01, // 10ms
45
+ factor: 2,
46
+ count: 20, // Up to ~10 seconds
47
+ }),
48
+ "Duration of complete upload operations in seconds",
49
+ ),
50
+
51
+ chunkUploadDurationHistogram: Metric.histogram(
52
+ "chunk_upload_duration_seconds",
53
+ MetricBoundaries.exponential({
54
+ start: 0.001, // 1ms
55
+ factor: 2,
56
+ count: 15, // Up to ~32 seconds
57
+ }),
58
+ "Duration of individual chunk uploads in seconds",
59
+ ),
60
+
61
+ uploadFileSizeHistogram: Metric.histogram(
62
+ "upload_file_size_bytes",
63
+ MetricBoundaries.exponential({
64
+ start: 1024, // 1KB
65
+ factor: 2,
66
+ count: 25, // Up to ~33GB
67
+ }),
68
+ "Size of uploaded files in bytes",
69
+ ),
70
+
71
+ chunkSizeHistogram: Metric.histogram(
72
+ "chunk_size_bytes",
73
+ MetricBoundaries.linear({
74
+ start: 262_144, // 256KB
75
+ width: 262_144, // 256KB increments
76
+ count: 20, // Up to ~5MB
77
+ }),
78
+ "Size of uploaded chunks in bytes",
79
+ ),
80
+
81
+ // Gauge metrics
82
+ activeUploadsGauge: Metric.gauge("active_uploads", {
83
+ description: "Number of currently active uploads",
84
+ }),
85
+
86
+ uploadThroughputGauge: Metric.gauge("upload_throughput_bytes_per_second", {
87
+ description: "Current upload throughput in bytes per second",
88
+ }),
89
+
90
+ // Summary metrics for latency percentiles
91
+ uploadLatencySummary: Metric.summary({
92
+ name: "upload_latency_seconds",
93
+ maxAge: "10 minutes",
94
+ maxSize: 1000,
95
+ error: 0.01,
96
+ quantiles: [0.5, 0.9, 0.95, 0.99],
97
+ description: "Upload operation latency percentiles",
98
+ }),
99
+
100
+ chunkLatencySummary: Metric.summary({
101
+ name: "chunk_latency_seconds",
102
+ maxAge: "10 minutes",
103
+ maxSize: 1000,
104
+ error: 0.01,
105
+ quantiles: [0.5, 0.9, 0.95, 0.99],
106
+ description: "Chunk upload latency percentiles",
107
+ }),
108
+ });
109
+
110
+ /**
111
+ * Type for upload server metrics
112
+ */
113
+ export type UploadServerMetrics = ReturnType<typeof createUploadServerMetrics>;
114
+
115
+ /**
116
+ * Default upload server metrics instance
117
+ */
118
+ export const uploadServerMetrics = createUploadServerMetrics();
@@ -0,0 +1,60 @@
1
+ import { Layer } from "effect";
2
+ import { UploadObservability } from "../core/layers.js";
3
+ import { createUploadServerMetrics } from "./metrics.js";
4
+
5
+ // ============================================================================
6
+ // Upload Observability Testing Utilities
7
+ // ============================================================================
8
+
9
+ /**
10
+ * Create a test upload observability layer that doesn't actually emit metrics
11
+ * but validates that the observability system is wired correctly
12
+ */
13
+ export const UploadObservabilityTest = Layer.succeed(UploadObservability, {
14
+ serviceName: "uploadista-upload-server-test",
15
+ enabled: true,
16
+ metrics: {
17
+ uploadCreated: () => Promise.resolve(),
18
+ uploadCompleted: () => Promise.resolve(),
19
+ uploadFailed: () => Promise.resolve(),
20
+ chunkUploaded: () => Promise.resolve(),
21
+ } as any,
22
+ });
23
+
24
+ /**
25
+ * Get metrics for validation (useful for testing metric definitions)
26
+ */
27
+ export const getTestMetrics = () => createUploadServerMetrics();
28
+
29
+ /**
30
+ * Validate that all required metrics exist
31
+ */
32
+ export const validateMetricsExist = () => {
33
+ const metrics = getTestMetrics();
34
+
35
+ const requiredMetrics = [
36
+ "uploadCreatedTotal",
37
+ "uploadCompletedTotal",
38
+ "uploadFailedTotal",
39
+ "chunkUploadedTotal",
40
+ "uploadFromUrlTotal",
41
+ "uploadFromUrlSuccessTotal",
42
+ "uploadFromUrlFailedTotal",
43
+ "uploadDurationHistogram",
44
+ "chunkUploadDurationHistogram",
45
+ "uploadFileSizeHistogram",
46
+ "chunkSizeHistogram",
47
+ "activeUploadsGauge",
48
+ "uploadThroughputGauge",
49
+ "uploadLatencySummary",
50
+ "chunkLatencySummary",
51
+ ];
52
+
53
+ const missingMetrics = requiredMetrics.filter((name) => !(name in metrics));
54
+
55
+ if (missingMetrics.length > 0) {
56
+ throw new Error(`Missing required metrics: ${missingMetrics.join(", ")}`);
57
+ }
58
+
59
+ return true;
60
+ };
@@ -0,0 +1,58 @@
1
+ import { Effect } from "effect";
2
+
3
+ // ============================================================================
4
+ // Upload Tracing Utilities
5
+ // ============================================================================
6
+
7
+ /**
8
+ * Wrap an Effect with an upload operation span
9
+ */
10
+ export const withUploadSpan =
11
+ <A, E, R>(operation: string, attributes?: Record<string, unknown>) =>
12
+ (effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
13
+ effect.pipe(
14
+ Effect.withSpan(`upload-${operation}`, {
15
+ attributes: {
16
+ "upload.operation": operation,
17
+ ...attributes,
18
+ },
19
+ }),
20
+ );
21
+
22
+ /**
23
+ * Add upload context to the current span
24
+ */
25
+ export const withUploadContext = (context: {
26
+ uploadId?: string;
27
+ fileName?: string;
28
+ fileSize?: number;
29
+ storageId?: string;
30
+ mimeType?: string;
31
+ }) =>
32
+ Effect.annotateCurrentSpan({
33
+ "upload.id": context.uploadId ?? "unknown",
34
+ "upload.file_name": context.fileName ?? "unknown",
35
+ "upload.file_size": context.fileSize?.toString() ?? "0",
36
+ "upload.storage_id": context.storageId ?? "unknown",
37
+ "upload.mime_type": context.mimeType ?? "unknown",
38
+ });
39
+
40
+ /**
41
+ * Add chunk context to the current span
42
+ */
43
+ export const withChunkContext = (context: {
44
+ uploadId: string;
45
+ chunkSize: number;
46
+ offset: number;
47
+ totalSize?: number;
48
+ }) =>
49
+ Effect.annotateCurrentSpan({
50
+ "chunk.upload_id": context.uploadId,
51
+ "chunk.size": context.chunkSize.toString(),
52
+ "chunk.offset": context.offset.toString(),
53
+ "chunk.total_size": context.totalSize?.toString() ?? "0",
54
+ "chunk.progress":
55
+ context.totalSize && context.totalSize > 0
56
+ ? ((context.offset / context.totalSize) * 100).toFixed(2)
57
+ : "0",
58
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "@uploadista/typescript-config/base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "types": ["node"]
7
+ },
8
+ "include": ["src/**/*"],
9
+ "exclude": ["node_modules", "dist"]
10
+ }
@@ -0,0 +1 @@
1
+ {"root":["./src/index.ts","./src/test-observability.ts","./src/core/errors.ts","./src/core/index.ts","./src/core/layers.ts","./src/core/logging.ts","./src/core/metrics.ts","./src/core/testing.ts","./src/core/tracing.ts","./src/core/utilities.ts","./src/flow/errors.ts","./src/flow/index.ts","./src/flow/layers.ts","./src/flow/metrics.ts","./src/flow/testing.ts","./src/flow/tracing.ts","./src/service/metrics.ts","./src/storage/azure.ts","./src/storage/filesystem.ts","./src/storage/gcs.ts","./src/storage/index.ts","./src/storage/s3.ts","./src/upload/errors.ts","./src/upload/index.ts","./src/upload/layers.ts","./src/upload/metrics.ts","./src/upload/testing.ts","./src/upload/tracing.ts"],"version":"5.9.3"}