@uploadista/server 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 (91) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/.turbo/turbo-check.log +34 -0
  3. package/LICENSE +21 -0
  4. package/README.md +503 -0
  5. package/dist/auth/cache.d.ts +87 -0
  6. package/dist/auth/cache.d.ts.map +1 -0
  7. package/dist/auth/cache.js +121 -0
  8. package/dist/auth/cache.test.d.ts +2 -0
  9. package/dist/auth/cache.test.d.ts.map +1 -0
  10. package/dist/auth/cache.test.js +209 -0
  11. package/dist/auth/get-auth-credentials.d.ts +73 -0
  12. package/dist/auth/get-auth-credentials.d.ts.map +1 -0
  13. package/dist/auth/get-auth-credentials.js +55 -0
  14. package/dist/auth/index.d.ts +2 -0
  15. package/dist/auth/index.d.ts.map +1 -0
  16. package/dist/auth/index.js +1 -0
  17. package/dist/auth/jwt/index.d.ts +38 -0
  18. package/dist/auth/jwt/index.d.ts.map +1 -0
  19. package/dist/auth/jwt/index.js +36 -0
  20. package/dist/auth/jwt/types.d.ts +77 -0
  21. package/dist/auth/jwt/types.d.ts.map +1 -0
  22. package/dist/auth/jwt/types.js +1 -0
  23. package/dist/auth/jwt/validate.d.ts +58 -0
  24. package/dist/auth/jwt/validate.d.ts.map +1 -0
  25. package/dist/auth/jwt/validate.js +226 -0
  26. package/dist/auth/jwt/validate.test.d.ts +2 -0
  27. package/dist/auth/jwt/validate.test.d.ts.map +1 -0
  28. package/dist/auth/jwt/validate.test.js +492 -0
  29. package/dist/auth/service.d.ts +63 -0
  30. package/dist/auth/service.d.ts.map +1 -0
  31. package/dist/auth/service.js +43 -0
  32. package/dist/auth/service.test.d.ts +2 -0
  33. package/dist/auth/service.test.d.ts.map +1 -0
  34. package/dist/auth/service.test.js +195 -0
  35. package/dist/auth/types.d.ts +38 -0
  36. package/dist/auth/types.d.ts.map +1 -0
  37. package/dist/auth/types.js +1 -0
  38. package/dist/cache.d.ts +87 -0
  39. package/dist/cache.d.ts.map +1 -0
  40. package/dist/cache.js +121 -0
  41. package/dist/cache.test.d.ts +2 -0
  42. package/dist/cache.test.d.ts.map +1 -0
  43. package/dist/cache.test.js +209 -0
  44. package/dist/cloudflare-config.d.ts +72 -0
  45. package/dist/cloudflare-config.d.ts.map +1 -0
  46. package/dist/cloudflare-config.js +67 -0
  47. package/dist/error-types.d.ts +138 -0
  48. package/dist/error-types.d.ts.map +1 -0
  49. package/dist/error-types.js +155 -0
  50. package/dist/hono-adapter.d.ts +48 -0
  51. package/dist/hono-adapter.d.ts.map +1 -0
  52. package/dist/hono-adapter.js +58 -0
  53. package/dist/http-utils.d.ts +148 -0
  54. package/dist/http-utils.d.ts.map +1 -0
  55. package/dist/http-utils.js +233 -0
  56. package/dist/index.d.ts +9 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +8 -0
  59. package/dist/layer-utils.d.ts +121 -0
  60. package/dist/layer-utils.d.ts.map +1 -0
  61. package/dist/layer-utils.js +80 -0
  62. package/dist/metrics/service.d.ts +26 -0
  63. package/dist/metrics/service.d.ts.map +1 -0
  64. package/dist/metrics/service.js +20 -0
  65. package/dist/plugins-typing.d.ts +11 -0
  66. package/dist/plugins-typing.d.ts.map +1 -0
  67. package/dist/plugins-typing.js +1 -0
  68. package/dist/service.d.ts +63 -0
  69. package/dist/service.d.ts.map +1 -0
  70. package/dist/service.js +43 -0
  71. package/dist/service.test.d.ts +2 -0
  72. package/dist/service.test.d.ts.map +1 -0
  73. package/dist/service.test.js +195 -0
  74. package/dist/types.d.ts +38 -0
  75. package/dist/types.d.ts.map +1 -0
  76. package/dist/types.js +1 -0
  77. package/package.json +47 -0
  78. package/src/auth/get-auth-credentials.ts +97 -0
  79. package/src/auth/index.ts +1 -0
  80. package/src/cache.test.ts +306 -0
  81. package/src/cache.ts +204 -0
  82. package/src/error-types.ts +172 -0
  83. package/src/http-utils.ts +264 -0
  84. package/src/index.ts +8 -0
  85. package/src/layer-utils.ts +184 -0
  86. package/src/plugins-typing.ts +57 -0
  87. package/src/service.test.ts +275 -0
  88. package/src/service.ts +78 -0
  89. package/src/types.ts +40 -0
  90. package/tsconfig.json +13 -0
  91. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins-typing.d.ts","sourceRoot":"","sources":["../src/plugins-typing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,MAAM,MAAM,iBAAiB,CAC3B,MAAM,SAAS,SAAS,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,IACtD,MAAM,CAAC,MAAM,CAAC,SAAS,KAAK,CAAC,KAAK,CAAC,MAAM,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,GAC/D,OAAO,GACP,KAAK,CAAC;AAEV,MAAM,MAAM,WAAW,CACrB,MAAM,SAAS,CACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,IAAI,KACpB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,IAC3C,UAAU,CAAC,MAAM,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,MAAM,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,GACzE,OAAO,GACP,KAAK,CAAC;AAEV,MAAM,MAAM,kBAAkB,CAC5B,MAAM,SAAS,CACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,IAAI,KACpB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,IAC3C,WAAW,CAAC,MAAM,CAAC,SAAS,IAAI,CAClC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,EACpB,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,EACpB,MAAM,CAAC,CACR,GACG,OAAO,CAAC,CAAC,EAAE,YAAY,CAAC,GACxB,KAAK,CAAC;AAEV,MAAM,MAAM,iBAAiB,CAC3B,MAAM,SAAS,CACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,IAAI,KACpB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,IAC3C,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,CAAC;AAEtD,MAAM,MAAM,eAAe,CACzB,MAAM,SAAS,CACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,IAAI,KACpB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAE7C,QAAQ,SAAS,SAAS,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,IACxD,OAAO,CACT,iBAAiB,CAAC,MAAM,CAAC,EACzB,iBAAiB,CAAC,QAAQ,CAAC,CAC5B,SAAS,KAAK,GACX,OAAO,GACP;IACE,gBAAgB,EAAE,OAAO,CACvB,iBAAiB,CAAC,MAAM,CAAC,EACzB,iBAAiB,CAAC,QAAQ,CAAC,CAC5B,CAAC;CACH,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,63 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import type { AuthContext } from "./types";
3
+ declare const AuthContextService_base: Context.TagClass<AuthContextService, "AuthContextService", {
4
+ /**
5
+ * Get the current client ID from auth context.
6
+ * Returns null if no authentication context is available.
7
+ */
8
+ readonly getClientId: () => Effect.Effect<string | null>;
9
+ /**
10
+ * Get the current auth metadata.
11
+ * Returns empty object if no authentication context or no metadata.
12
+ */
13
+ readonly getMetadata: () => Effect.Effect<Record<string, unknown>>;
14
+ /**
15
+ * Check if the current client has a specific permission.
16
+ * Returns false if no authentication context or permission not found.
17
+ */
18
+ readonly hasPermission: (permission: string) => Effect.Effect<boolean>;
19
+ /**
20
+ * Get the full authentication context if available.
21
+ * Returns null if no authentication context is available.
22
+ */
23
+ readonly getAuthContext: () => Effect.Effect<AuthContext | null>;
24
+ }>;
25
+ /**
26
+ * Authentication Context Service
27
+ *
28
+ * Provides access to the current authentication context throughout
29
+ * the upload and flow processing pipeline. The service is provided
30
+ * via Effect Layer and can be accessed using Effect.service().
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * import { Effect } from "effect";
35
+ * import { AuthContextService } from "@uploadista/server";
36
+ *
37
+ * const uploadHandler = Effect.gen(function* () {
38
+ * const authService = yield* AuthContextService;
39
+ * const clientId = yield* authService.getClientId();
40
+ * if (clientId) {
41
+ * console.log(`Processing upload for client: ${clientId}`);
42
+ * }
43
+ * });
44
+ * ```
45
+ */
46
+ export declare class AuthContextService extends AuthContextService_base {
47
+ }
48
+ /**
49
+ * Creates an AuthContextService Layer from an AuthContext.
50
+ * This is typically called by adapters after successful authentication.
51
+ *
52
+ * @param authContext - The authentication context from middleware
53
+ * @returns Effect Layer providing AuthContextService
54
+ */
55
+ export declare const AuthContextServiceLive: (authContext: AuthContext | null) => Layer.Layer<AuthContextService>;
56
+ /**
57
+ * No-auth implementation of AuthContextService.
58
+ * Returns null/empty values for all operations.
59
+ * Used when no authentication middleware is configured (backward compatibility).
60
+ */
61
+ export declare const NoAuthContextServiceLive: Layer.Layer<AuthContextService>;
62
+ export {};
63
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;;IA0BvC;;;OAGG;0BACmB,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;IAExD;;;OAGG;0BACmB,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAElE;;;OAGG;4BACqB,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;IAEtE;;;OAGG;6BACsB,MAAM,MAAM,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC;;AA9CpE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,kBAAmB,SAAQ,uBA2BrC;CAAG;AAEN;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GACjC,aAAa,WAAW,GAAG,IAAI,KAC9B,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAO7B,CAAC;AAEL;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,KAAK,CAAC,KAAK,CAAC,kBAAkB,CACvC,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ /**
3
+ * Authentication Context Service
4
+ *
5
+ * Provides access to the current authentication context throughout
6
+ * the upload and flow processing pipeline. The service is provided
7
+ * via Effect Layer and can be accessed using Effect.service().
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { Effect } from "effect";
12
+ * import { AuthContextService } from "@uploadista/server";
13
+ *
14
+ * const uploadHandler = Effect.gen(function* () {
15
+ * const authService = yield* AuthContextService;
16
+ * const clientId = yield* authService.getClientId();
17
+ * if (clientId) {
18
+ * console.log(`Processing upload for client: ${clientId}`);
19
+ * }
20
+ * });
21
+ * ```
22
+ */
23
+ export class AuthContextService extends Context.Tag("AuthContextService")() {
24
+ }
25
+ /**
26
+ * Creates an AuthContextService Layer from an AuthContext.
27
+ * This is typically called by adapters after successful authentication.
28
+ *
29
+ * @param authContext - The authentication context from middleware
30
+ * @returns Effect Layer providing AuthContextService
31
+ */
32
+ export const AuthContextServiceLive = (authContext) => Layer.succeed(AuthContextService, {
33
+ getClientId: () => Effect.succeed(authContext?.clientId ?? null),
34
+ getMetadata: () => Effect.succeed(authContext?.metadata ?? {}),
35
+ hasPermission: (permission) => Effect.succeed(authContext?.permissions?.includes(permission) ?? false),
36
+ getAuthContext: () => Effect.succeed(authContext),
37
+ });
38
+ /**
39
+ * No-auth implementation of AuthContextService.
40
+ * Returns null/empty values for all operations.
41
+ * Used when no authentication middleware is configured (backward compatibility).
42
+ */
43
+ export const NoAuthContextServiceLive = AuthContextServiceLive(null);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.test.d.ts","sourceRoot":"","sources":["../src/service.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,195 @@
1
+ import { Effect } from "effect";
2
+ import { describe, expect, it } from "vitest";
3
+ import { AuthContextService, AuthContextServiceLive, NoAuthContextServiceLive, } from "./service";
4
+ describe("AuthContextService", () => {
5
+ describe("AuthContextServiceLive", () => {
6
+ it("should return userId when auth context is provided", async () => {
7
+ const authContext = {
8
+ clientId: "user-123",
9
+ metadata: { role: "admin" },
10
+ permissions: ["upload:create", "flow:execute"],
11
+ };
12
+ const layer = AuthContextServiceLive(authContext);
13
+ const program = Effect.gen(function* () {
14
+ const service = yield* AuthContextService;
15
+ return yield* service.getClientId();
16
+ });
17
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
18
+ expect(result).toBe("user-123");
19
+ });
20
+ it("should return null when auth context is null", async () => {
21
+ const layer = AuthContextServiceLive(null);
22
+ const program = Effect.gen(function* () {
23
+ const service = yield* AuthContextService;
24
+ return yield* service.getClientId();
25
+ });
26
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
27
+ expect(result).toBeNull();
28
+ });
29
+ it("should return metadata when auth context is provided", async () => {
30
+ const authContext = {
31
+ clientId: "user-123",
32
+ metadata: { role: "admin", tier: "premium" },
33
+ permissions: [],
34
+ };
35
+ const layer = AuthContextServiceLive(authContext);
36
+ const program = Effect.gen(function* () {
37
+ const service = yield* AuthContextService;
38
+ return yield* service.getMetadata();
39
+ });
40
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
41
+ expect(result).toEqual({ role: "admin", tier: "premium" });
42
+ });
43
+ it("should return empty object when auth context has no metadata", async () => {
44
+ const authContext = {
45
+ clientId: "user-123",
46
+ };
47
+ const layer = AuthContextServiceLive(authContext);
48
+ const program = Effect.gen(function* () {
49
+ const service = yield* AuthContextService;
50
+ return yield* service.getMetadata();
51
+ });
52
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
53
+ expect(result).toEqual({});
54
+ });
55
+ it("should return empty object when auth context is null", async () => {
56
+ const layer = AuthContextServiceLive(null);
57
+ const program = Effect.gen(function* () {
58
+ const service = yield* AuthContextService;
59
+ return yield* service.getMetadata();
60
+ });
61
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
62
+ expect(result).toEqual({});
63
+ });
64
+ it("should return true for existing permission", async () => {
65
+ const authContext = {
66
+ clientId: "user-123",
67
+ permissions: ["upload:create", "flow:execute", "admin:read"],
68
+ };
69
+ const layer = AuthContextServiceLive(authContext);
70
+ const program = Effect.gen(function* () {
71
+ const service = yield* AuthContextService;
72
+ return yield* service.hasPermission("flow:execute");
73
+ });
74
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
75
+ expect(result).toBe(true);
76
+ });
77
+ it("should return false for non-existing permission", async () => {
78
+ const authContext = {
79
+ clientId: "user-123",
80
+ permissions: ["upload:create", "flow:execute"],
81
+ };
82
+ const layer = AuthContextServiceLive(authContext);
83
+ const program = Effect.gen(function* () {
84
+ const service = yield* AuthContextService;
85
+ return yield* service.hasPermission("admin:write");
86
+ });
87
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
88
+ expect(result).toBe(false);
89
+ });
90
+ it("should return false for permission check when no permissions array", async () => {
91
+ const authContext = {
92
+ clientId: "user-123",
93
+ };
94
+ const layer = AuthContextServiceLive(authContext);
95
+ const program = Effect.gen(function* () {
96
+ const service = yield* AuthContextService;
97
+ return yield* service.hasPermission("upload:create");
98
+ });
99
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
100
+ expect(result).toBe(false);
101
+ });
102
+ it("should return false for permission check when auth context is null", async () => {
103
+ const layer = AuthContextServiceLive(null);
104
+ const program = Effect.gen(function* () {
105
+ const service = yield* AuthContextService;
106
+ return yield* service.hasPermission("upload:create");
107
+ });
108
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
109
+ expect(result).toBe(false);
110
+ });
111
+ it("should return full auth context when provided", async () => {
112
+ const authContext = {
113
+ clientId: "user-123",
114
+ metadata: { role: "admin" },
115
+ permissions: ["upload:create"],
116
+ };
117
+ const layer = AuthContextServiceLive(authContext);
118
+ const program = Effect.gen(function* () {
119
+ const service = yield* AuthContextService;
120
+ return yield* service.getAuthContext();
121
+ });
122
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
123
+ expect(result).toEqual(authContext);
124
+ });
125
+ it("should return null auth context when not provided", async () => {
126
+ const layer = AuthContextServiceLive(null);
127
+ const program = Effect.gen(function* () {
128
+ const service = yield* AuthContextService;
129
+ return yield* service.getAuthContext();
130
+ });
131
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
132
+ expect(result).toBeNull();
133
+ });
134
+ });
135
+ describe("NoAuthContextServiceLive", () => {
136
+ it("should return null for getUserId", async () => {
137
+ const program = Effect.gen(function* () {
138
+ const service = yield* AuthContextService;
139
+ return yield* service.getClientId();
140
+ });
141
+ const result = await Effect.runPromise(program.pipe(Effect.provide(NoAuthContextServiceLive)));
142
+ expect(result).toBeNull();
143
+ });
144
+ it("should return empty object for getMetadata", async () => {
145
+ const program = Effect.gen(function* () {
146
+ const service = yield* AuthContextService;
147
+ return yield* service.getMetadata();
148
+ });
149
+ const result = await Effect.runPromise(program.pipe(Effect.provide(NoAuthContextServiceLive)));
150
+ expect(result).toEqual({});
151
+ });
152
+ it("should return false for any permission check", async () => {
153
+ const program = Effect.gen(function* () {
154
+ const service = yield* AuthContextService;
155
+ const result1 = yield* service.hasPermission("upload:create");
156
+ const result2 = yield* service.hasPermission("admin:write");
157
+ return { result1, result2 };
158
+ });
159
+ const result = await Effect.runPromise(program.pipe(Effect.provide(NoAuthContextServiceLive)));
160
+ expect(result.result1).toBe(false);
161
+ expect(result.result2).toBe(false);
162
+ });
163
+ it("should return null for getAuthContext", async () => {
164
+ const program = Effect.gen(function* () {
165
+ const service = yield* AuthContextService;
166
+ return yield* service.getAuthContext();
167
+ });
168
+ const result = await Effect.runPromise(program.pipe(Effect.provide(NoAuthContextServiceLive)));
169
+ expect(result).toBeNull();
170
+ });
171
+ });
172
+ describe("Effect Layer composition", () => {
173
+ it("should work in composed effect programs", async () => {
174
+ const authContext = {
175
+ clientId: "user-456",
176
+ metadata: { department: "engineering" },
177
+ permissions: ["flow:execute"],
178
+ };
179
+ const layer = AuthContextServiceLive(authContext);
180
+ const program = Effect.gen(function* () {
181
+ const service = yield* AuthContextService;
182
+ const clientId = yield* service.getClientId();
183
+ const metadata = yield* service.getMetadata();
184
+ const hasPermission = yield* service.hasPermission("flow:execute");
185
+ return { clientId, metadata, hasPermission };
186
+ });
187
+ const result = await Effect.runPromise(program.pipe(Effect.provide(layer)));
188
+ expect(result).toEqual({
189
+ clientId: "user-456",
190
+ metadata: { department: "engineering" },
191
+ hasPermission: true,
192
+ });
193
+ });
194
+ });
195
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Authentication context containing user identity and authorization metadata.
3
+ * This context is extracted from authentication middleware and made available
4
+ * throughout the upload and flow processing pipeline via Effect Layer.
5
+ */
6
+ export type AuthContext = {
7
+ /**
8
+ * Unique identifier for the authenticated user.
9
+ * This is typically extracted from JWT claims (sub), session data, or API key metadata.
10
+ */
11
+ clientId: string;
12
+ /**
13
+ * Optional metadata for authorization and tracking purposes.
14
+ * Can include rate limits, quotas, permissions, or custom application data.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * {
19
+ * permissions: ['upload:create', 'flow:execute'],
20
+ * rateLimit: { requests: 1000, period: 3600 },
21
+ * quota: { storage: 10737418240, used: 5368709120 }
22
+ * }
23
+ * ```
24
+ */
25
+ metadata?: Record<string, unknown>;
26
+ /**
27
+ * Optional list of permissions granted to the user.
28
+ * These can be used for fine-grained access control in the future.
29
+ */
30
+ permissions?: string[];
31
+ };
32
+ /**
33
+ * Result type for authentication middleware.
34
+ * - AuthContext: Successful authentication with user identity
35
+ * - null: Authentication failed or not authenticated
36
+ */
37
+ export type AuthResult = AuthContext | null;
38
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEnC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,IAAI,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@uploadista/server",
3
+ "type": "module",
4
+ "version": "0.0.3",
5
+ "description": "Core Server package for Uploadista",
6
+ "license": "MIT",
7
+ "author": "Uploadista",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./auth": {
15
+ "types": "./dist/auth/index.d.ts",
16
+ "import": "./dist/auth/index.js",
17
+ "default": "./dist/auth/index.js"
18
+ }
19
+ },
20
+ "dependencies": {
21
+ "effect": "3.18.4",
22
+ "zod": "4.1.12",
23
+ "@uploadista/core": "0.0.3"
24
+ },
25
+ "devDependencies": {
26
+ "@cloudflare/workers-types": "4.20251011.0",
27
+ "@types/express": "^5.0.0",
28
+ "@types/node": "24.8.1",
29
+ "typescript": "5.9.3",
30
+ "vitest": "3.2.4",
31
+ "@uploadista/typescript-config": "0.0.3"
32
+ },
33
+ "peerDependencies": {
34
+ "express": "^4.0.0 || ^5.0.0",
35
+ "hono": "^4.0.0"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc -b",
39
+ "format": "biome format --write ./src",
40
+ "lint": "biome lint --write ./src",
41
+ "check": "biome check --write ./src",
42
+ "test": "vitest",
43
+ "test:run": "vitest run",
44
+ "test:watch": "vitest --watch",
45
+ "clean": "rimraf -rf dist && rimraf -rf .turbo && rimraf tsconfig.tsbuildinfo"
46
+ }
47
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Response type for authentication credential requests.
3
+ * - `isValid: true` with token and expiration
4
+ * - `isValid: false` with error message
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * const response = await getAuthCredentials({
9
+ * uploadistaClientId: "my-client",
10
+ * uploadistaApiKey: "sk_..."
11
+ * });
12
+ * if (response.isValid) {
13
+ * console.log(`Token: ${response.data.token}`);
14
+ * } else {
15
+ * console.error(`Auth failed: ${response.error}`);
16
+ * }
17
+ * ```
18
+ */
19
+ export type AuthCredentialsResponse =
20
+ | {
21
+ isValid: true;
22
+ data: { token: string; expiresIn: number };
23
+ }
24
+ | {
25
+ isValid: false;
26
+ error: string;
27
+ };
28
+
29
+ /**
30
+ * Retrieve JWT authentication credentials from the Uploadista server.
31
+ * This function exchanges client credentials (ID + API key) for a signed JWT token.
32
+ *
33
+ * The JWT token is then used in subsequent API requests via the Authorization header.
34
+ * Tokens are time-limited and should be refreshed before expiration.
35
+ *
36
+ * @param params - Credential exchange parameters
37
+ * @param params.uploadistaClientId - Your Uploadista client ID
38
+ * @param params.uploadistaApiKey - Your Uploadista API key (secret)
39
+ * @param params.baseUrl - Uploadista server base URL (default: https://api.uploadista.com)
40
+ * @returns Promise resolving to authentication response with token or error
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * import { getAuthCredentials } from "@uploadista/server";
45
+ *
46
+ * // Get JWT token for API requests
47
+ * const response = await getAuthCredentials({
48
+ * uploadistaClientId: process.env.UPLOADISTA_CLIENT_ID,
49
+ * uploadistaApiKey: process.env.UPLOADISTA_API_KEY,
50
+ * });
51
+ *
52
+ * if (response.isValid) {
53
+ * // Use token in API requests
54
+ * const headers = {
55
+ * Authorization: `Bearer ${response.data.token}`,
56
+ * };
57
+ *
58
+ * // Token expires in response.data.expiresIn seconds
59
+ * setTimeout(
60
+ * () => {
61
+ * // Refresh token before expiration
62
+ * },
63
+ * response.data.expiresIn * 1000,
64
+ * );
65
+ * }
66
+ * ```
67
+ */
68
+ export const getAuthCredentials = async ({
69
+ uploadistaClientId,
70
+ uploadistaApiKey,
71
+ baseUrl = "https://api.uploadista.com",
72
+ }: {
73
+ uploadistaClientId: string;
74
+ uploadistaApiKey: string;
75
+ baseUrl?: string;
76
+ }): Promise<AuthCredentialsResponse> => {
77
+ const response = await fetch(
78
+ `${baseUrl}/uploadista/auth/jwt?apiKey=${uploadistaApiKey}&clientId=${uploadistaClientId}`,
79
+ {
80
+ method: "GET",
81
+ headers: {
82
+ "Content-Type": "application/json",
83
+ },
84
+ },
85
+ );
86
+
87
+ if (response.ok !== true) {
88
+ return { isValid: false, error: "Failed to get auth credentials" };
89
+ }
90
+
91
+ const data = (await response.json()) as { token: string; expiresIn: number };
92
+
93
+ return {
94
+ isValid: true,
95
+ data,
96
+ };
97
+ };
@@ -0,0 +1 @@
1
+ export * from "./get-auth-credentials";