@uploadista/server 0.0.20-beta.6 → 0.0.20-beta.7
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/dist/index.cjs +2 -2
- package/dist/index.d.cts +157 -157
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +157 -157
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
- package/src/core/http-handlers/flow-http-handlers.ts +1 -1
- package/src/core/plugin-types.ts +9 -9
- package/src/core/routes.ts +4 -1
- package/src/core/server.ts +1 -3
- package/src/permissions/errors.ts +3 -1
- package/src/permissions/index.ts +2 -2
- package/src/permissions/types.ts +3 -12
- package/src/plugins-typing.ts +12 -10
- package/src/service.ts +9 -4
- package/src/usage-hooks/index.ts +1 -1
- package/src/usage-hooks/service.ts +51 -59
- package/src/usage-hooks/types.ts +2 -4
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uploadista/server",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.20-beta.
|
|
4
|
+
"version": "0.0.20-beta.7",
|
|
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.0.20-beta.
|
|
24
|
-
"@uploadista/event-
|
|
25
|
-
"@uploadista/
|
|
26
|
-
"@uploadista/
|
|
23
|
+
"@uploadista/core": "0.0.20-beta.7",
|
|
24
|
+
"@uploadista/event-broadcaster-memory": "0.0.20-beta.7",
|
|
25
|
+
"@uploadista/event-emitter-websocket": "0.0.20-beta.7",
|
|
26
|
+
"@uploadista/observability": "0.0.20-beta.7"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@cloudflare/workers-types": "4.
|
|
29
|
+
"@cloudflare/workers-types": "4.20251211.0",
|
|
30
30
|
"@effect/vitest": "0.27.0",
|
|
31
31
|
"@types/express": "^5.0.0",
|
|
32
|
-
"@types/node": "24.10.
|
|
33
|
-
"effect": "3.19.
|
|
32
|
+
"@types/node": "24.10.3",
|
|
33
|
+
"effect": "3.19.11",
|
|
34
34
|
"tsd": "0.33.0",
|
|
35
35
|
"tsdown": "0.17.2",
|
|
36
36
|
"typescript": "5.9.3",
|
|
37
37
|
"vitest": "4.0.15",
|
|
38
38
|
"zod": "4.1.13",
|
|
39
|
-
"@uploadista/typescript-config": "0.0.20-beta.
|
|
39
|
+
"@uploadista/typescript-config": "0.0.20-beta.7"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"effect": "^3.0.0",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { FlowServer } from "@uploadista/core/flow";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
3
|
import { AuthCacheService } from "../../cache";
|
|
4
|
-
import { PERMISSIONS } from "../../permissions/types";
|
|
5
4
|
import { QuotaExceededError } from "../../permissions/errors";
|
|
5
|
+
import { PERMISSIONS } from "../../permissions/types";
|
|
6
6
|
import { AuthContextService } from "../../service";
|
|
7
7
|
import { UsageHookService } from "../../usage-hooks/service";
|
|
8
8
|
import type {
|
package/src/core/plugin-types.ts
CHANGED
|
@@ -187,12 +187,13 @@ export type ExtractFlowPluginRequirements<
|
|
|
187
187
|
clientId: string | null,
|
|
188
188
|
) => Effect.Effect<unknown, unknown, unknown>,
|
|
189
189
|
// biome-ignore lint/suspicious/noExplicitAny: Conditional type inference requires any for error and requirements parameters
|
|
190
|
-
> =
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
190
|
+
> =
|
|
191
|
+
ReturnType<TFlowFn> extends Effect.Effect<infer TFlow, any, any>
|
|
192
|
+
? // biome-ignore lint/suspicious/noExplicitAny: Conditional type inference requires any for input and output schema parameters
|
|
193
|
+
TFlow extends Flow<any, any, infer TRequirements>
|
|
194
|
+
? Exclude<TRequirements, never> // Exclude UploadServer is handled by FlowPluginRequirements in core
|
|
195
|
+
: never
|
|
196
|
+
: never;
|
|
196
197
|
|
|
197
198
|
/**
|
|
198
199
|
* Helper type to infer plugin requirements from a flow function.
|
|
@@ -204,9 +205,8 @@ export type ExtractFlowPluginRequirements<
|
|
|
204
205
|
* // Requirements = ImagePlugin | ZipPlugin
|
|
205
206
|
* ```
|
|
206
207
|
*/
|
|
207
|
-
export type InferFlowRequirements<T> =
|
|
208
|
-
? R
|
|
209
|
-
: never;
|
|
208
|
+
export type InferFlowRequirements<T> =
|
|
209
|
+
T extends TypeSafeFlowFunction<infer R> ? R : never;
|
|
210
210
|
|
|
211
211
|
/**
|
|
212
212
|
* Converts PluginLayer types to Layer.Layer<any, never, any> for runtime use.
|
package/src/core/routes.ts
CHANGED
|
@@ -190,7 +190,10 @@ export type DlqListResponse = UploadistaStandardResponse<
|
|
|
190
190
|
export type DlqGetRequest = UploadistaRoute<"dlq-get"> & {
|
|
191
191
|
itemId: string;
|
|
192
192
|
};
|
|
193
|
-
export type DlqGetResponse = UploadistaStandardResponse<
|
|
193
|
+
export type DlqGetResponse = UploadistaStandardResponse<
|
|
194
|
+
"dlq-get",
|
|
195
|
+
DeadLetterItem
|
|
196
|
+
>;
|
|
194
197
|
|
|
195
198
|
export type DlqRetryRequest = UploadistaRoute<"dlq-retry"> & {
|
|
196
199
|
itemId: string;
|
package/src/core/server.ts
CHANGED
|
@@ -314,9 +314,7 @@ export const createUploadistaServer = async <
|
|
|
314
314
|
* This must be included in the runtime layer (not per-request) so that the
|
|
315
315
|
* BatchSpanProcessor can aggregate spans across requests and flush them properly.
|
|
316
316
|
*/
|
|
317
|
-
const tracingLayer = withTracing
|
|
318
|
-
? observabilityLayer ?? NodeSdkLive
|
|
319
|
-
: null;
|
|
317
|
+
const tracingLayer = withTracing ? (observabilityLayer ?? NodeSdkLive) : null;
|
|
320
318
|
|
|
321
319
|
/**
|
|
322
320
|
* Type Casting Rationale for Plugin System
|
|
@@ -64,7 +64,9 @@ export class AuthenticationRequiredError extends AdapterError {
|
|
|
64
64
|
* ```
|
|
65
65
|
*/
|
|
66
66
|
export class OrganizationMismatchError extends AdapterError {
|
|
67
|
-
constructor(
|
|
67
|
+
constructor(
|
|
68
|
+
message = "Access denied: resource belongs to another organization",
|
|
69
|
+
) {
|
|
68
70
|
super(message, 403, "ORGANIZATION_MISMATCH");
|
|
69
71
|
this.name = "OrganizationMismatchError";
|
|
70
72
|
}
|
package/src/permissions/index.ts
CHANGED
package/src/permissions/types.ts
CHANGED
|
@@ -121,22 +121,13 @@ export const PERMISSION_SETS = {
|
|
|
121
121
|
ADMIN: [ENGINE_PERMISSIONS.ALL] as const,
|
|
122
122
|
|
|
123
123
|
/** Organization owner - all flow and upload permissions */
|
|
124
|
-
ORGANIZATION_OWNER: [
|
|
125
|
-
FLOW_PERMISSIONS.ALL,
|
|
126
|
-
UPLOAD_PERMISSIONS.ALL,
|
|
127
|
-
] as const,
|
|
124
|
+
ORGANIZATION_OWNER: [FLOW_PERMISSIONS.ALL, UPLOAD_PERMISSIONS.ALL] as const,
|
|
128
125
|
|
|
129
126
|
/** Organization member - same as owner for now */
|
|
130
|
-
ORGANIZATION_MEMBER: [
|
|
131
|
-
FLOW_PERMISSIONS.ALL,
|
|
132
|
-
UPLOAD_PERMISSIONS.ALL,
|
|
133
|
-
] as const,
|
|
127
|
+
ORGANIZATION_MEMBER: [FLOW_PERMISSIONS.ALL, UPLOAD_PERMISSIONS.ALL] as const,
|
|
134
128
|
|
|
135
129
|
/** API key - limited to execute flows and create uploads */
|
|
136
|
-
API_KEY: [
|
|
137
|
-
FLOW_PERMISSIONS.EXECUTE,
|
|
138
|
-
UPLOAD_PERMISSIONS.CREATE,
|
|
139
|
-
] as const,
|
|
130
|
+
API_KEY: [FLOW_PERMISSIONS.EXECUTE, UPLOAD_PERMISSIONS.CREATE] as const,
|
|
140
131
|
} as const;
|
|
141
132
|
|
|
142
133
|
/**
|
package/src/plugins-typing.ts
CHANGED
|
@@ -50,9 +50,10 @@ export type FlowSuccess<
|
|
|
50
50
|
flowId: string,
|
|
51
51
|
clientId: string | null,
|
|
52
52
|
) => Effect.Effect<unknown, unknown, unknown>,
|
|
53
|
-
> =
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
> =
|
|
54
|
+
ReturnType<TFlows> extends Effect.Effect<infer Success, unknown, unknown>
|
|
55
|
+
? Success
|
|
56
|
+
: never;
|
|
56
57
|
|
|
57
58
|
/**
|
|
58
59
|
* @deprecated Use `ExtractFlowPluginRequirements` from `@uploadista/server/core/plugin-types` instead.
|
|
@@ -75,13 +76,14 @@ export type FlowRequirementsOf<
|
|
|
75
76
|
flowId: string,
|
|
76
77
|
clientId: string | null,
|
|
77
78
|
) => Effect.Effect<unknown, unknown, unknown>,
|
|
78
|
-
> =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
> =
|
|
80
|
+
FlowSuccess<TFlows> extends Flow<
|
|
81
|
+
z.ZodSchema<unknown>,
|
|
82
|
+
z.ZodSchema<unknown>,
|
|
83
|
+
infer R
|
|
84
|
+
>
|
|
85
|
+
? Exclude<R, UploadServer>
|
|
86
|
+
: never;
|
|
85
87
|
|
|
86
88
|
/**
|
|
87
89
|
* @deprecated Use `ExtractFlowPluginRequirements` from `@uploadista/server/core/plugin-types` instead.
|
package/src/service.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { Context, Effect, Layer } from "effect";
|
|
2
|
-
import type { AuthContext } from "./types";
|
|
3
2
|
import {
|
|
4
|
-
|
|
3
|
+
AuthenticationRequiredError,
|
|
4
|
+
AuthorizationError,
|
|
5
|
+
} from "./permissions/errors";
|
|
6
|
+
import {
|
|
5
7
|
hasAnyPermission as matchHasAnyPermission,
|
|
8
|
+
hasPermission as matchHasPermission,
|
|
6
9
|
} from "./permissions/matcher";
|
|
7
|
-
import {
|
|
10
|
+
import type { AuthContext } from "./types";
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
* Authentication Context Service
|
|
@@ -154,7 +157,9 @@ export const AuthContextServiceLive = (
|
|
|
154
157
|
hasAnyPermission: (requiredPermissions: readonly string[]) =>
|
|
155
158
|
bypassAuth
|
|
156
159
|
? Effect.succeed(true)
|
|
157
|
-
: Effect.succeed(
|
|
160
|
+
: Effect.succeed(
|
|
161
|
+
matchHasAnyPermission(permissions, requiredPermissions),
|
|
162
|
+
),
|
|
158
163
|
|
|
159
164
|
requirePermission: (permission: string) =>
|
|
160
165
|
Effect.gen(function* () {
|
package/src/usage-hooks/index.ts
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
import { Context, Effect, Layer } from "effect";
|
|
8
8
|
import type {
|
|
9
|
+
FlowUsageContext,
|
|
10
|
+
UploadUsageContext,
|
|
9
11
|
UsageHookConfig,
|
|
10
12
|
UsageHookResult,
|
|
11
|
-
UploadUsageContext,
|
|
12
|
-
FlowUsageContext,
|
|
13
13
|
} from "./types";
|
|
14
|
-
import {
|
|
14
|
+
import { continueResult, DEFAULT_USAGE_HOOK_TIMEOUT } from "./types";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Usage Hook Service
|
|
@@ -70,22 +70,20 @@ export const UsageHookServiceLive = (
|
|
|
70
70
|
return Effect.succeed(continueResult());
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
return hooks
|
|
74
|
-
|
|
75
|
-
.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
),
|
|
88
|
-
);
|
|
73
|
+
return hooks.onUploadStart(ctx).pipe(
|
|
74
|
+
// Add timeout - proceed on timeout (fail-open)
|
|
75
|
+
Effect.timeout(timeout),
|
|
76
|
+
Effect.map((result) => result ?? continueResult()),
|
|
77
|
+
// On any error, log and continue (fail-open for availability)
|
|
78
|
+
Effect.catchAll((error) =>
|
|
79
|
+
Effect.gen(function* () {
|
|
80
|
+
yield* Effect.logWarning(
|
|
81
|
+
`onUploadStart hook failed: ${error}. Proceeding with upload.`,
|
|
82
|
+
);
|
|
83
|
+
return continueResult();
|
|
84
|
+
}),
|
|
85
|
+
),
|
|
86
|
+
);
|
|
89
87
|
},
|
|
90
88
|
|
|
91
89
|
onUploadComplete: (ctx: UploadUsageContext) => {
|
|
@@ -93,19 +91,17 @@ export const UsageHookServiceLive = (
|
|
|
93
91
|
return Effect.void;
|
|
94
92
|
}
|
|
95
93
|
|
|
96
|
-
return hooks
|
|
97
|
-
|
|
98
|
-
.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
Effect.logWarning(
|
|
105
|
-
`onUploadComplete hook failed: ${error}. Upload already completed.`,
|
|
106
|
-
),
|
|
94
|
+
return hooks.onUploadComplete(ctx).pipe(
|
|
95
|
+
// Add timeout
|
|
96
|
+
Effect.timeout(timeout),
|
|
97
|
+
Effect.asVoid,
|
|
98
|
+
// On any error, just log (fire-and-forget)
|
|
99
|
+
Effect.catchAll((error) =>
|
|
100
|
+
Effect.logWarning(
|
|
101
|
+
`onUploadComplete hook failed: ${error}. Upload already completed.`,
|
|
107
102
|
),
|
|
108
|
-
)
|
|
103
|
+
),
|
|
104
|
+
);
|
|
109
105
|
},
|
|
110
106
|
|
|
111
107
|
onFlowStart: (ctx: FlowUsageContext) => {
|
|
@@ -113,22 +109,20 @@ export const UsageHookServiceLive = (
|
|
|
113
109
|
return Effect.succeed(continueResult());
|
|
114
110
|
}
|
|
115
111
|
|
|
116
|
-
return hooks
|
|
117
|
-
|
|
118
|
-
.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
),
|
|
131
|
-
);
|
|
112
|
+
return hooks.onFlowStart(ctx).pipe(
|
|
113
|
+
// Add timeout - proceed on timeout (fail-open)
|
|
114
|
+
Effect.timeout(timeout),
|
|
115
|
+
Effect.map((result) => result ?? continueResult()),
|
|
116
|
+
// On any error, log and continue (fail-open for availability)
|
|
117
|
+
Effect.catchAll((error) =>
|
|
118
|
+
Effect.gen(function* () {
|
|
119
|
+
yield* Effect.logWarning(
|
|
120
|
+
`onFlowStart hook failed: ${error}. Proceeding with flow.`,
|
|
121
|
+
);
|
|
122
|
+
return continueResult();
|
|
123
|
+
}),
|
|
124
|
+
),
|
|
125
|
+
);
|
|
132
126
|
},
|
|
133
127
|
|
|
134
128
|
onFlowComplete: (ctx: FlowUsageContext) => {
|
|
@@ -136,19 +130,17 @@ export const UsageHookServiceLive = (
|
|
|
136
130
|
return Effect.void;
|
|
137
131
|
}
|
|
138
132
|
|
|
139
|
-
return hooks
|
|
140
|
-
|
|
141
|
-
.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
Effect.logWarning(
|
|
148
|
-
`onFlowComplete hook failed: ${error}. Flow already completed.`,
|
|
149
|
-
),
|
|
133
|
+
return hooks.onFlowComplete(ctx).pipe(
|
|
134
|
+
// Add timeout
|
|
135
|
+
Effect.timeout(timeout),
|
|
136
|
+
Effect.asVoid,
|
|
137
|
+
// On any error, just log (fire-and-forget)
|
|
138
|
+
Effect.catchAll((error) =>
|
|
139
|
+
Effect.logWarning(
|
|
140
|
+
`onFlowComplete hook failed: ${error}. Flow already completed.`,
|
|
150
141
|
),
|
|
151
|
-
)
|
|
142
|
+
),
|
|
143
|
+
);
|
|
152
144
|
},
|
|
153
145
|
});
|
|
154
146
|
};
|
package/src/usage-hooks/types.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Used for usage tracking, quota enforcement, and billing integration.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Effect } from "effect";
|
|
8
|
+
import type { Effect } from "effect";
|
|
9
9
|
|
|
10
10
|
// ============================================================================
|
|
11
11
|
// Usage Hook Result Types
|
|
@@ -144,9 +144,7 @@ export type OnFlowStartHook = (
|
|
|
144
144
|
* Hook called after flow completes (success, failure, or cancellation).
|
|
145
145
|
* Used for recording usage. Errors are logged but don't fail the response.
|
|
146
146
|
*/
|
|
147
|
-
export type OnFlowCompleteHook = (
|
|
148
|
-
ctx: FlowUsageContext,
|
|
149
|
-
) => Effect.Effect<void>;
|
|
147
|
+
export type OnFlowCompleteHook = (ctx: FlowUsageContext) => Effect.Effect<void>;
|
|
150
148
|
|
|
151
149
|
// ============================================================================
|
|
152
150
|
// Usage Hooks Configuration
|