@uploadista/server 0.0.18-beta.17 → 0.0.18-beta.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,151 +0,0 @@
1
- /**
2
- * Permission Types and Constants
3
- *
4
- * Defines the permission model for fine-grained access control in the uploadista engine.
5
- * Permissions follow a hierarchical format: `resource:action` with support for wildcards.
6
- */
7
-
8
- // ============================================================================
9
- // Engine Permissions - Admin operations
10
- // ============================================================================
11
-
12
- /**
13
- * Engine permissions for administrative operations.
14
- * These control access to health, readiness, metrics, and DLQ endpoints.
15
- */
16
- export const ENGINE_PERMISSIONS = {
17
- /** Full admin access to all engine operations */
18
- ALL: "engine:*",
19
- /** Access health endpoint */
20
- HEALTH: "engine:health",
21
- /** Access readiness endpoint */
22
- READINESS: "engine:readiness",
23
- /** Access metrics endpoint */
24
- METRICS: "engine:metrics",
25
- /** Full DLQ access (implies read and write) */
26
- DLQ: "engine:dlq",
27
- /** Read DLQ entries */
28
- DLQ_READ: "engine:dlq:read",
29
- /** Retry/delete DLQ entries */
30
- DLQ_WRITE: "engine:dlq:write",
31
- } as const;
32
-
33
- // ============================================================================
34
- // Flow Permissions - Flow execution operations
35
- // ============================================================================
36
-
37
- /**
38
- * Flow permissions for flow execution operations.
39
- */
40
- export const FLOW_PERMISSIONS = {
41
- /** Full access to all flow operations */
42
- ALL: "flow:*",
43
- /** Execute flows */
44
- EXECUTE: "flow:execute",
45
- /** Cancel running flows */
46
- CANCEL: "flow:cancel",
47
- /** Check flow status */
48
- STATUS: "flow:status",
49
- } as const;
50
-
51
- // ============================================================================
52
- // Upload Permissions - File upload operations
53
- // ============================================================================
54
-
55
- /**
56
- * Upload permissions for file upload operations.
57
- */
58
- export const UPLOAD_PERMISSIONS = {
59
- /** Full access to all upload operations */
60
- ALL: "upload:*",
61
- /** Create uploads */
62
- CREATE: "upload:create",
63
- /** Read upload status */
64
- READ: "upload:read",
65
- /** Cancel uploads */
66
- CANCEL: "upload:cancel",
67
- } as const;
68
-
69
- // ============================================================================
70
- // Combined Permissions Object
71
- // ============================================================================
72
-
73
- /**
74
- * All available permissions organized by category.
75
- *
76
- * @example
77
- * ```typescript
78
- * import { PERMISSIONS } from "@uploadista/server";
79
- *
80
- * const adminPermissions = [PERMISSIONS.ENGINE.ALL];
81
- * const userPermissions = [PERMISSIONS.FLOW.ALL, PERMISSIONS.UPLOAD.ALL];
82
- * ```
83
- */
84
- export const PERMISSIONS = {
85
- ENGINE: ENGINE_PERMISSIONS,
86
- FLOW: FLOW_PERMISSIONS,
87
- UPLOAD: UPLOAD_PERMISSIONS,
88
- } as const;
89
-
90
- // ============================================================================
91
- // Permission Type Definitions
92
- // ============================================================================
93
-
94
- /** All engine permission strings */
95
- export type EnginePermission =
96
- (typeof ENGINE_PERMISSIONS)[keyof typeof ENGINE_PERMISSIONS];
97
-
98
- /** All flow permission strings */
99
- export type FlowPermission =
100
- (typeof FLOW_PERMISSIONS)[keyof typeof FLOW_PERMISSIONS];
101
-
102
- /** All upload permission strings */
103
- export type UploadPermission =
104
- (typeof UPLOAD_PERMISSIONS)[keyof typeof UPLOAD_PERMISSIONS];
105
-
106
- /**
107
- * Union type of all valid permission strings.
108
- * Includes standard permissions and allows custom permissions via string.
109
- */
110
- export type Permission =
111
- | EnginePermission
112
- | FlowPermission
113
- | UploadPermission
114
- | (string & {}); // Allow custom permissions while maintaining autocomplete
115
-
116
- /**
117
- * Predefined permission sets for common use cases.
118
- */
119
- export const PERMISSION_SETS = {
120
- /** Full admin access - all engine, flow, and upload permissions */
121
- ADMIN: [ENGINE_PERMISSIONS.ALL] as const,
122
-
123
- /** Organization owner - all flow and upload permissions */
124
- ORGANIZATION_OWNER: [
125
- FLOW_PERMISSIONS.ALL,
126
- UPLOAD_PERMISSIONS.ALL,
127
- ] as const,
128
-
129
- /** Organization member - same as owner for now */
130
- ORGANIZATION_MEMBER: [
131
- FLOW_PERMISSIONS.ALL,
132
- UPLOAD_PERMISSIONS.ALL,
133
- ] as const,
134
-
135
- /** API key - limited to execute flows and create uploads */
136
- API_KEY: [
137
- FLOW_PERMISSIONS.EXECUTE,
138
- UPLOAD_PERMISSIONS.CREATE,
139
- ] as const,
140
- } as const;
141
-
142
- /**
143
- * Hierarchical permission relationships.
144
- * When a parent permission is granted, all child permissions are implied.
145
- */
146
- export const PERMISSION_HIERARCHY: Record<string, readonly string[]> = {
147
- [ENGINE_PERMISSIONS.DLQ]: [
148
- ENGINE_PERMISSIONS.DLQ_READ,
149
- ENGINE_PERMISSIONS.DLQ_WRITE,
150
- ],
151
- } as const;
@@ -1,8 +0,0 @@
1
- /**
2
- * Usage Hooks Module
3
- *
4
- * Exports all usage hook types and services.
5
- */
6
-
7
- export * from "./types";
8
- export * from "./service";
@@ -1,162 +0,0 @@
1
- /**
2
- * Usage Hook Service
3
- *
4
- * Effect service for executing usage tracking hooks with timeout handling.
5
- */
6
-
7
- import { Context, Effect, Layer } from "effect";
8
- import type {
9
- UsageHookConfig,
10
- UsageHookResult,
11
- UploadUsageContext,
12
- FlowUsageContext,
13
- } from "./types";
14
- import { DEFAULT_USAGE_HOOK_TIMEOUT, continueResult } from "./types";
15
-
16
- /**
17
- * Usage Hook Service
18
- *
19
- * Provides methods to execute usage hooks during upload and flow processing.
20
- * Handles timeout and error recovery gracefully.
21
- */
22
- export class UsageHookService extends Context.Tag("UsageHookService")<
23
- UsageHookService,
24
- {
25
- /**
26
- * Execute onUploadStart hook if configured.
27
- * Returns continue result if no hook is configured or on error/timeout.
28
- */
29
- readonly onUploadStart: (
30
- ctx: UploadUsageContext,
31
- ) => Effect.Effect<UsageHookResult>;
32
-
33
- /**
34
- * Execute onUploadComplete hook if configured.
35
- * Errors are logged but swallowed (fire-and-forget).
36
- */
37
- readonly onUploadComplete: (ctx: UploadUsageContext) => Effect.Effect<void>;
38
-
39
- /**
40
- * Execute onFlowStart hook if configured.
41
- * Returns continue result if no hook is configured or on error/timeout.
42
- */
43
- readonly onFlowStart: (
44
- ctx: FlowUsageContext,
45
- ) => Effect.Effect<UsageHookResult>;
46
-
47
- /**
48
- * Execute onFlowComplete hook if configured.
49
- * Errors are logged but swallowed (fire-and-forget).
50
- */
51
- readonly onFlowComplete: (ctx: FlowUsageContext) => Effect.Effect<void>;
52
- }
53
- >() {}
54
-
55
- /**
56
- * Creates a UsageHookService Layer from configuration.
57
- *
58
- * @param config - Usage hook configuration with optional hooks and timeout
59
- * @returns Effect Layer providing UsageHookService
60
- */
61
- export const UsageHookServiceLive = (
62
- config?: UsageHookConfig,
63
- ): Layer.Layer<UsageHookService> => {
64
- const hooks = config?.hooks;
65
- const timeout = config?.timeout ?? DEFAULT_USAGE_HOOK_TIMEOUT;
66
-
67
- return Layer.succeed(UsageHookService, {
68
- onUploadStart: (ctx: UploadUsageContext) => {
69
- if (!hooks?.onUploadStart) {
70
- return Effect.succeed(continueResult());
71
- }
72
-
73
- return hooks
74
- .onUploadStart(ctx)
75
- .pipe(
76
- // Add timeout - proceed on timeout (fail-open)
77
- Effect.timeout(timeout),
78
- Effect.map((result) => result ?? continueResult()),
79
- // On any error, log and continue (fail-open for availability)
80
- Effect.catchAll((error) =>
81
- Effect.gen(function* () {
82
- yield* Effect.logWarning(
83
- `onUploadStart hook failed: ${error}. Proceeding with upload.`,
84
- );
85
- return continueResult();
86
- }),
87
- ),
88
- );
89
- },
90
-
91
- onUploadComplete: (ctx: UploadUsageContext) => {
92
- if (!hooks?.onUploadComplete) {
93
- return Effect.void;
94
- }
95
-
96
- return hooks
97
- .onUploadComplete(ctx)
98
- .pipe(
99
- // Add timeout
100
- Effect.timeout(timeout),
101
- Effect.asVoid,
102
- // On any error, just log (fire-and-forget)
103
- Effect.catchAll((error) =>
104
- Effect.logWarning(
105
- `onUploadComplete hook failed: ${error}. Upload already completed.`,
106
- ),
107
- ),
108
- );
109
- },
110
-
111
- onFlowStart: (ctx: FlowUsageContext) => {
112
- if (!hooks?.onFlowStart) {
113
- return Effect.succeed(continueResult());
114
- }
115
-
116
- return hooks
117
- .onFlowStart(ctx)
118
- .pipe(
119
- // Add timeout - proceed on timeout (fail-open)
120
- Effect.timeout(timeout),
121
- Effect.map((result) => result ?? continueResult()),
122
- // On any error, log and continue (fail-open for availability)
123
- Effect.catchAll((error) =>
124
- Effect.gen(function* () {
125
- yield* Effect.logWarning(
126
- `onFlowStart hook failed: ${error}. Proceeding with flow.`,
127
- );
128
- return continueResult();
129
- }),
130
- ),
131
- );
132
- },
133
-
134
- onFlowComplete: (ctx: FlowUsageContext) => {
135
- if (!hooks?.onFlowComplete) {
136
- return Effect.void;
137
- }
138
-
139
- return hooks
140
- .onFlowComplete(ctx)
141
- .pipe(
142
- // Add timeout
143
- Effect.timeout(timeout),
144
- Effect.asVoid,
145
- // On any error, just log (fire-and-forget)
146
- Effect.catchAll((error) =>
147
- Effect.logWarning(
148
- `onFlowComplete hook failed: ${error}. Flow already completed.`,
149
- ),
150
- ),
151
- );
152
- },
153
- });
154
- };
155
-
156
- /**
157
- * No-op implementation of UsageHookService.
158
- * All hooks are no-ops that return continue/void.
159
- * Used when no usage hooks are configured (default backward compatibility).
160
- */
161
- export const NoUsageHookServiceLive: Layer.Layer<UsageHookService> =
162
- UsageHookServiceLive();
@@ -1,221 +0,0 @@
1
- /**
2
- * Usage Hook Types
3
- *
4
- * Types for lifecycle hooks that fire during upload and flow processing.
5
- * Used for usage tracking, quota enforcement, and billing integration.
6
- */
7
-
8
- import { Effect } from "effect";
9
-
10
- // ============================================================================
11
- // Usage Hook Result Types
12
- // ============================================================================
13
-
14
- /**
15
- * Result of a usage hook that can abort processing.
16
- * Used by onUploadStart and onFlowStart hooks.
17
- */
18
- export type UsageHookResult =
19
- | { readonly action: "continue" }
20
- | {
21
- readonly action: "abort";
22
- readonly reason: string;
23
- readonly code?: string;
24
- };
25
-
26
- /**
27
- * Helper to create a continue result.
28
- */
29
- export const continueResult = (): UsageHookResult => ({ action: "continue" });
30
-
31
- /**
32
- * Helper to create an abort result.
33
- */
34
- export const abortResult = (
35
- reason: string,
36
- code?: string,
37
- ): UsageHookResult => ({
38
- action: "abort",
39
- reason,
40
- code,
41
- });
42
-
43
- // ============================================================================
44
- // Usage Context Types
45
- // ============================================================================
46
-
47
- /**
48
- * Base metadata shared across all usage contexts.
49
- */
50
- export interface BaseUsageMetadata {
51
- /** File size in bytes (if known) */
52
- fileSize?: number;
53
- /** MIME type of the file */
54
- mimeType?: string;
55
- /** Original file name */
56
- fileName?: string;
57
- }
58
-
59
- /**
60
- * Metadata specific to upload operations.
61
- */
62
- export interface UploadUsageMetadata extends BaseUsageMetadata {
63
- /** Unique upload identifier */
64
- uploadId?: string;
65
- /** Duration of the upload in milliseconds */
66
- duration?: number;
67
- }
68
-
69
- /**
70
- * Metadata specific to flow operations.
71
- */
72
- export interface FlowUsageMetadata extends BaseUsageMetadata {
73
- /** Flow identifier being executed */
74
- flowId?: string;
75
- /** Unique job identifier */
76
- jobId?: string;
77
- /** Number of nodes in the flow */
78
- nodeCount?: number;
79
- /** Total size of input files */
80
- inputFileSize?: number;
81
- /** Total size of output files (on complete) */
82
- outputSize?: number;
83
- /** Number of nodes that were executed (on complete) */
84
- nodesExecuted?: number;
85
- /** Duration of flow execution in milliseconds (on complete) */
86
- duration?: number;
87
- /** Flow completion status (on complete) */
88
- status?: "success" | "failed" | "cancelled";
89
- }
90
-
91
- /**
92
- * Context passed to usage hooks containing client and operation information.
93
- */
94
- export interface UsageContext<
95
- TMetadata extends BaseUsageMetadata = BaseUsageMetadata,
96
- > {
97
- /** Organization/client identifier */
98
- clientId: string;
99
- /** Type of operation */
100
- operation: "upload" | "flow";
101
- /** Operation-specific metadata */
102
- metadata: TMetadata;
103
- }
104
-
105
- /**
106
- * Upload-specific usage context.
107
- */
108
- export type UploadUsageContext = UsageContext<UploadUsageMetadata>;
109
-
110
- /**
111
- * Flow-specific usage context.
112
- */
113
- export type FlowUsageContext = UsageContext<FlowUsageMetadata>;
114
-
115
- // ============================================================================
116
- // Usage Hook Function Types
117
- // ============================================================================
118
-
119
- /**
120
- * Hook called before upload processing begins.
121
- * Can return abort to reject the upload (e.g., quota exceeded).
122
- */
123
- export type OnUploadStartHook = (
124
- ctx: UploadUsageContext,
125
- ) => Effect.Effect<UsageHookResult>;
126
-
127
- /**
128
- * Hook called after upload completes successfully.
129
- * Used for recording usage. Errors are logged but don't fail the upload.
130
- */
131
- export type OnUploadCompleteHook = (
132
- ctx: UploadUsageContext,
133
- ) => Effect.Effect<void>;
134
-
135
- /**
136
- * Hook called before flow execution begins.
137
- * Can return abort to reject the flow (e.g., subscription expired).
138
- */
139
- export type OnFlowStartHook = (
140
- ctx: FlowUsageContext,
141
- ) => Effect.Effect<UsageHookResult>;
142
-
143
- /**
144
- * Hook called after flow completes (success, failure, or cancellation).
145
- * Used for recording usage. Errors are logged but don't fail the response.
146
- */
147
- export type OnFlowCompleteHook = (
148
- ctx: FlowUsageContext,
149
- ) => Effect.Effect<void>;
150
-
151
- // ============================================================================
152
- // Usage Hooks Configuration
153
- // ============================================================================
154
-
155
- /**
156
- * Configuration for usage tracking hooks.
157
- * All hooks are optional - unconfigured hooks are no-ops.
158
- *
159
- * @example
160
- * ```typescript
161
- * const usageHooks: UsageHooks = {
162
- * onUploadStart: (ctx) => Effect.gen(function* () {
163
- * const hasQuota = yield* checkQuota(ctx.clientId, ctx.metadata.fileSize);
164
- * if (!hasQuota) {
165
- * return abortResult("Storage quota exceeded", "QUOTA_EXCEEDED");
166
- * }
167
- * return continueResult();
168
- * }),
169
- * onUploadComplete: (ctx) => Effect.gen(function* () {
170
- * yield* recordUsage(ctx.clientId, ctx.metadata.fileSize);
171
- * }),
172
- * };
173
- * ```
174
- */
175
- export interface UsageHooks {
176
- /**
177
- * Called before upload processing begins.
178
- * Return abort to reject the upload.
179
- */
180
- onUploadStart?: OnUploadStartHook;
181
-
182
- /**
183
- * Called after upload completes successfully.
184
- * Errors are logged but don't fail the upload.
185
- */
186
- onUploadComplete?: OnUploadCompleteHook;
187
-
188
- /**
189
- * Called before flow execution begins.
190
- * Return abort to reject the flow.
191
- */
192
- onFlowStart?: OnFlowStartHook;
193
-
194
- /**
195
- * Called after flow completes (success, failure, or cancellation).
196
- * Errors are logged but don't fail the response.
197
- */
198
- onFlowComplete?: OnFlowCompleteHook;
199
- }
200
-
201
- /**
202
- * Configuration for the usage hook service.
203
- */
204
- export interface UsageHookConfig {
205
- /**
206
- * The usage hooks to execute.
207
- */
208
- hooks?: UsageHooks;
209
-
210
- /**
211
- * Timeout for hook execution in milliseconds.
212
- * If a hook takes longer than this, it will be considered failed.
213
- * Default: 5000ms (5 seconds)
214
- */
215
- timeout?: number;
216
- }
217
-
218
- /**
219
- * Default timeout for usage hooks (5 seconds).
220
- */
221
- export const DEFAULT_USAGE_HOOK_TIMEOUT = 5000;