@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,121 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ /**
3
+ * Auth Cache Service
4
+ *
5
+ * Provides caching of authentication contexts for upload and flow jobs.
6
+ * This allows subsequent operations (chunk uploads, flow continuations)
7
+ * to reuse the auth context from the initial request without re-authenticating.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { Effect } from "effect";
12
+ * import { AuthCacheService } from "@uploadista/server";
13
+ *
14
+ * const handler = Effect.gen(function* () {
15
+ * const authCache = yield* AuthCacheService;
16
+ * const authContext = { userId: "user-123" };
17
+ *
18
+ * // Cache auth for upload
19
+ * yield* authCache.set("upload-abc", authContext);
20
+ *
21
+ * // Retrieve cached auth later
22
+ * const cached = yield* authCache.get("upload-abc");
23
+ * console.log(cached?.userId); // "user-123"
24
+ *
25
+ * // Clear when done
26
+ * yield* authCache.delete("upload-abc");
27
+ * });
28
+ * ```
29
+ */
30
+ export class AuthCacheService extends Context.Tag("AuthCacheService")() {
31
+ }
32
+ /**
33
+ * Creates an AuthCacheService Layer with in-memory storage.
34
+ *
35
+ * @param config - Optional configuration for cache behavior
36
+ * @returns Effect Layer providing AuthCacheService
37
+ */
38
+ export const AuthCacheServiceLive = (config = {}) => {
39
+ const maxSize = config.maxSize ?? 10000;
40
+ const ttl = config.ttl ?? 3600000; // 1 hour default
41
+ // In-memory cache storage
42
+ const cache = new Map();
43
+ /**
44
+ * Evict expired entries based on TTL.
45
+ */
46
+ const evictExpired = () => {
47
+ const now = Date.now();
48
+ for (const [jobId, entry] of cache.entries()) {
49
+ if (now - entry.timestamp > ttl) {
50
+ cache.delete(jobId);
51
+ }
52
+ }
53
+ };
54
+ /**
55
+ * Enforce max size limit using LRU eviction.
56
+ * Removes oldest entry when cache exceeds max size.
57
+ */
58
+ const enforceSizeLimit = () => {
59
+ if (cache.size <= maxSize)
60
+ return;
61
+ // Find and remove oldest entry
62
+ let oldestKey = null;
63
+ let oldestTime = Number.POSITIVE_INFINITY;
64
+ for (const [jobId, entry] of cache.entries()) {
65
+ if (entry.timestamp < oldestTime) {
66
+ oldestTime = entry.timestamp;
67
+ oldestKey = jobId;
68
+ }
69
+ }
70
+ if (oldestKey) {
71
+ cache.delete(oldestKey);
72
+ }
73
+ };
74
+ return Layer.succeed(AuthCacheService, {
75
+ set: (jobId, authContext) => Effect.sync(() => {
76
+ // Evict expired entries periodically
77
+ if (cache.size % 100 === 0) {
78
+ evictExpired();
79
+ }
80
+ cache.set(jobId, {
81
+ authContext,
82
+ timestamp: Date.now(),
83
+ });
84
+ // Enforce size limit after adding
85
+ enforceSizeLimit();
86
+ }),
87
+ get: (jobId) => Effect.sync(() => {
88
+ const entry = cache.get(jobId);
89
+ if (!entry)
90
+ return null;
91
+ // Check if expired
92
+ const now = Date.now();
93
+ if (now - entry.timestamp > ttl) {
94
+ cache.delete(jobId);
95
+ return null;
96
+ }
97
+ return entry.authContext;
98
+ }),
99
+ delete: (jobId) => Effect.sync(() => {
100
+ cache.delete(jobId);
101
+ }),
102
+ clear: () => Effect.sync(() => {
103
+ cache.clear();
104
+ }),
105
+ size: () => Effect.sync(() => {
106
+ return cache.size;
107
+ }),
108
+ });
109
+ };
110
+ /**
111
+ * No-op implementation of AuthCacheService.
112
+ * Does not cache anything - all operations are no-ops.
113
+ * Used when caching is disabled or not needed.
114
+ */
115
+ export const NoAuthCacheServiceLive = Layer.succeed(AuthCacheService, {
116
+ set: () => Effect.void,
117
+ get: () => Effect.succeed(null),
118
+ delete: () => Effect.void,
119
+ clear: () => Effect.void,
120
+ size: () => Effect.succeed(0),
121
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cache.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.test.d.ts","sourceRoot":"","sources":["../../src/auth/cache.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,209 @@
1
+ import { Effect } from "effect";
2
+ import { describe, expect, it } from "vitest";
3
+ import { AuthCacheService, AuthCacheServiceLive, NoAuthCacheServiceLive, } from "./cache";
4
+ describe("AuthCacheService", () => {
5
+ describe("AuthCacheServiceLive", () => {
6
+ it("should set and get auth context", async () => {
7
+ const authContext = {
8
+ clientId: "user-123",
9
+ metadata: { role: "admin" },
10
+ };
11
+ const program = Effect.gen(function* () {
12
+ const cache = yield* AuthCacheService;
13
+ // Set auth context
14
+ yield* cache.set("job-1", authContext);
15
+ // Get auth context
16
+ const retrieved = yield* cache.get("job-1");
17
+ expect(retrieved).toEqual(authContext);
18
+ });
19
+ await Effect.runPromise(program.pipe(Effect.provide(AuthCacheServiceLive())));
20
+ });
21
+ it("should return null for non-existent job ID", async () => {
22
+ const program = Effect.gen(function* () {
23
+ const cache = yield* AuthCacheService;
24
+ const retrieved = yield* cache.get("non-existent");
25
+ expect(retrieved).toBeNull();
26
+ });
27
+ await Effect.runPromise(program.pipe(Effect.provide(AuthCacheServiceLive())));
28
+ });
29
+ it("should delete cached auth context", async () => {
30
+ const authContext = {
31
+ clientId: "user-123",
32
+ };
33
+ const program = Effect.gen(function* () {
34
+ const cache = yield* AuthCacheService;
35
+ // Set and verify
36
+ yield* cache.set("job-1", authContext);
37
+ const before = yield* cache.get("job-1");
38
+ expect(before).toEqual(authContext);
39
+ // Delete
40
+ yield* cache.delete("job-1");
41
+ // Verify deleted
42
+ const after = yield* cache.get("job-1");
43
+ expect(after).toBeNull();
44
+ });
45
+ await Effect.runPromise(program.pipe(Effect.provide(AuthCacheServiceLive())));
46
+ });
47
+ it("should clear all cached auth contexts", async () => {
48
+ const authContext1 = { clientId: "user-1" };
49
+ const authContext2 = { clientId: "user-2" };
50
+ const program = Effect.gen(function* () {
51
+ const cache = yield* AuthCacheService;
52
+ // Set multiple entries
53
+ yield* cache.set("job-1", authContext1);
54
+ yield* cache.set("job-2", authContext2);
55
+ const sizeBefore = yield* cache.size();
56
+ expect(sizeBefore).toBe(2);
57
+ // Clear all
58
+ yield* cache.clear();
59
+ const sizeAfter = yield* cache.size();
60
+ expect(sizeAfter).toBe(0);
61
+ // Verify both deleted
62
+ const job1 = yield* cache.get("job-1");
63
+ const job2 = yield* cache.get("job-2");
64
+ expect(job1).toBeNull();
65
+ expect(job2).toBeNull();
66
+ });
67
+ await Effect.runPromise(program.pipe(Effect.provide(AuthCacheServiceLive())));
68
+ });
69
+ it("should track cache size", async () => {
70
+ const program = Effect.gen(function* () {
71
+ const cache = yield* AuthCacheService;
72
+ let size = yield* cache.size();
73
+ expect(size).toBe(0);
74
+ yield* cache.set("job-1", { clientId: "user-1" });
75
+ size = yield* cache.size();
76
+ expect(size).toBe(1);
77
+ yield* cache.set("job-2", { clientId: "user-2" });
78
+ size = yield* cache.size();
79
+ expect(size).toBe(2);
80
+ yield* cache.delete("job-1");
81
+ size = yield* cache.size();
82
+ expect(size).toBe(1);
83
+ yield* cache.clear();
84
+ size = yield* cache.size();
85
+ expect(size).toBe(0);
86
+ });
87
+ await Effect.runPromise(program.pipe(Effect.provide(AuthCacheServiceLive())));
88
+ });
89
+ it("should evict expired entries", async () => {
90
+ // Set very short TTL for testing
91
+ const shortTtl = 50; // 50ms
92
+ const authContext = {
93
+ clientId: "user-123",
94
+ };
95
+ const program = Effect.gen(function* () {
96
+ const cache = yield* AuthCacheService;
97
+ // Set auth context
98
+ yield* cache.set("job-1", authContext);
99
+ // Verify it's there immediately
100
+ const immediate = yield* cache.get("job-1");
101
+ expect(immediate).toEqual(authContext);
102
+ // Wait for TTL to expire
103
+ yield* Effect.sleep(100); // Wait 100ms (longer than 50ms TTL)
104
+ // Should be evicted now
105
+ const afterExpiry = yield* cache.get("job-1");
106
+ expect(afterExpiry).toBeNull();
107
+ });
108
+ await Effect.runPromise(program.pipe(Effect.provide(AuthCacheServiceLive({ ttl: shortTtl }))));
109
+ });
110
+ it("should enforce max size limit with LRU eviction", async () => {
111
+ const maxSize = 3;
112
+ const program = Effect.gen(function* () {
113
+ const cache = yield* AuthCacheService;
114
+ // Add entries up to max size
115
+ yield* cache.set("job-1", { clientId: "user-1" });
116
+ yield* Effect.sleep(10); // Small delay to ensure ordering
117
+ yield* cache.set("job-2", { clientId: "user-2" });
118
+ yield* Effect.sleep(10);
119
+ yield* cache.set("job-3", { clientId: "user-3" });
120
+ let size = yield* cache.size();
121
+ expect(size).toBe(3);
122
+ // Add one more - should evict oldest (job-1)
123
+ yield* Effect.sleep(10);
124
+ yield* cache.set("job-4", { clientId: "user-4" });
125
+ size = yield* cache.size();
126
+ expect(size).toBe(3); // Still at max size
127
+ // job-1 should be evicted (oldest)
128
+ const job1 = yield* cache.get("job-1");
129
+ expect(job1).toBeNull();
130
+ // Others should still exist
131
+ const job2 = yield* cache.get("job-2");
132
+ const job3 = yield* cache.get("job-3");
133
+ const job4 = yield* cache.get("job-4");
134
+ expect(job2).toEqual({ clientId: "user-2" });
135
+ expect(job3).toEqual({ clientId: "user-3" });
136
+ expect(job4).toEqual({ clientId: "user-4" });
137
+ });
138
+ await Effect.runPromise(program.pipe(Effect.provide(AuthCacheServiceLive({ maxSize }))));
139
+ });
140
+ it("should handle multiple auth contexts independently", async () => {
141
+ const authContext1 = {
142
+ clientId: "user-1",
143
+ metadata: { role: "admin" },
144
+ };
145
+ const authContext2 = {
146
+ clientId: "user-2",
147
+ permissions: ["read", "write"],
148
+ };
149
+ const program = Effect.gen(function* () {
150
+ const cache = yield* AuthCacheService;
151
+ yield* cache.set("upload-123", authContext1);
152
+ yield* cache.set("flow-456", authContext2);
153
+ const upload = yield* cache.get("upload-123");
154
+ const flow = yield* cache.get("flow-456");
155
+ expect(upload).toEqual(authContext1);
156
+ expect(flow).toEqual(authContext2);
157
+ });
158
+ await Effect.runPromise(program.pipe(Effect.provide(AuthCacheServiceLive())));
159
+ });
160
+ it("should update existing entry when setting same job ID", async () => {
161
+ const authContext1 = { clientId: "user-1" };
162
+ const authContext2 = { clientId: "user-2" };
163
+ const program = Effect.gen(function* () {
164
+ const cache = yield* AuthCacheService;
165
+ yield* cache.set("job-1", authContext1);
166
+ const first = yield* cache.get("job-1");
167
+ expect(first).toEqual(authContext1);
168
+ // Update with new auth context
169
+ yield* cache.set("job-1", authContext2);
170
+ const second = yield* cache.get("job-1");
171
+ expect(second).toEqual(authContext2);
172
+ // Should still be only 1 entry
173
+ const size = yield* cache.size();
174
+ expect(size).toBe(1);
175
+ });
176
+ await Effect.runPromise(program.pipe(Effect.provide(AuthCacheServiceLive())));
177
+ });
178
+ });
179
+ describe("NoAuthCacheServiceLive", () => {
180
+ it("should not cache anything", async () => {
181
+ const authContext = {
182
+ clientId: "user-123",
183
+ };
184
+ const program = Effect.gen(function* () {
185
+ const cache = yield* AuthCacheService;
186
+ // Try to set
187
+ yield* cache.set("job-1", authContext);
188
+ // Should always return null
189
+ const retrieved = yield* cache.get("job-1");
190
+ expect(retrieved).toBeNull();
191
+ // Size should always be 0
192
+ const size = yield* cache.size();
193
+ expect(size).toBe(0);
194
+ });
195
+ await Effect.runPromise(program.pipe(Effect.provide(NoAuthCacheServiceLive)));
196
+ });
197
+ it("should handle delete and clear without errors", async () => {
198
+ const program = Effect.gen(function* () {
199
+ const cache = yield* AuthCacheService;
200
+ // These should not throw
201
+ yield* cache.delete("non-existent");
202
+ yield* cache.clear();
203
+ const size = yield* cache.size();
204
+ expect(size).toBe(0);
205
+ });
206
+ await Effect.runPromise(program.pipe(Effect.provide(NoAuthCacheServiceLive)));
207
+ });
208
+ });
209
+ });
@@ -0,0 +1,73 @@
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
+ isValid: true;
21
+ data: {
22
+ token: string;
23
+ expiresIn: number;
24
+ };
25
+ } | {
26
+ isValid: false;
27
+ error: string;
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 declare const getAuthCredentials: ({ uploadistaClientId, uploadistaApiKey, baseUrl, }: {
69
+ uploadistaClientId: string;
70
+ uploadistaApiKey: string;
71
+ baseUrl?: string;
72
+ }) => Promise<AuthCredentialsResponse>;
73
+ //# sourceMappingURL=get-auth-credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-auth-credentials.d.ts","sourceRoot":"","sources":["../../src/auth/get-auth-credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,uBAAuB,GAC/B;IACE,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C,GACD;IACE,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,kBAAkB,GAAU,oDAItC;IACD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,KAAG,OAAO,CAAC,uBAAuB,CAqBlC,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Retrieve JWT authentication credentials from the Uploadista server.
3
+ * This function exchanges client credentials (ID + API key) for a signed JWT token.
4
+ *
5
+ * The JWT token is then used in subsequent API requests via the Authorization header.
6
+ * Tokens are time-limited and should be refreshed before expiration.
7
+ *
8
+ * @param params - Credential exchange parameters
9
+ * @param params.uploadistaClientId - Your Uploadista client ID
10
+ * @param params.uploadistaApiKey - Your Uploadista API key (secret)
11
+ * @param params.baseUrl - Uploadista server base URL (default: https://api.uploadista.com)
12
+ * @returns Promise resolving to authentication response with token or error
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import { getAuthCredentials } from "@uploadista/server";
17
+ *
18
+ * // Get JWT token for API requests
19
+ * const response = await getAuthCredentials({
20
+ * uploadistaClientId: process.env.UPLOADISTA_CLIENT_ID,
21
+ * uploadistaApiKey: process.env.UPLOADISTA_API_KEY,
22
+ * });
23
+ *
24
+ * if (response.isValid) {
25
+ * // Use token in API requests
26
+ * const headers = {
27
+ * Authorization: `Bearer ${response.data.token}`,
28
+ * };
29
+ *
30
+ * // Token expires in response.data.expiresIn seconds
31
+ * setTimeout(
32
+ * () => {
33
+ * // Refresh token before expiration
34
+ * },
35
+ * response.data.expiresIn * 1000,
36
+ * );
37
+ * }
38
+ * ```
39
+ */
40
+ export const getAuthCredentials = async ({ uploadistaClientId, uploadistaApiKey, baseUrl = "https://api.uploadista.com", }) => {
41
+ const response = await fetch(`${baseUrl}/uploadista/auth/jwt?apiKey=${uploadistaApiKey}&clientId=${uploadistaClientId}`, {
42
+ method: "GET",
43
+ headers: {
44
+ "Content-Type": "application/json",
45
+ },
46
+ });
47
+ if (response.ok !== true) {
48
+ return { isValid: false, error: "Failed to get auth credentials" };
49
+ }
50
+ const data = (await response.json());
51
+ return {
52
+ isValid: true,
53
+ data,
54
+ };
55
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./get-auth-credentials";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1 @@
1
+ export * from "./get-auth-credentials";
@@ -0,0 +1,38 @@
1
+ /**
2
+ * JWT Utilities for Uploadista Authentication
3
+ *
4
+ * This module provides JWT token validation and AuthContext extraction utilities
5
+ * for implementing SaaS-mode authentication in uploadista adapters.
6
+ *
7
+ * @example Basic JWT validation
8
+ * ```typescript
9
+ * import { validateJwtToken } from '@uploadista/server/auth/jwt';
10
+ *
11
+ * const result = await validateJwtToken(token, {
12
+ * secret: process.env.JWT_SECRET,
13
+ * issuer: 'https://auth.myapp.com',
14
+ * audience: 'uploadista-api',
15
+ * });
16
+ *
17
+ * if (result.success) {
18
+ * console.log('Valid token for user:', result.userId);
19
+ * }
20
+ * ```
21
+ *
22
+ * @example Extract AuthContext
23
+ * ```typescript
24
+ * import { extractAuthContextFromJwt } from '@uploadista/server/auth/jwt';
25
+ *
26
+ * const authContext = await extractAuthContextFromJwt(token, {
27
+ * secret: process.env.JWT_SECRET,
28
+ * });
29
+ *
30
+ * if (authContext) {
31
+ * // Use auth context in your middleware
32
+ * return authContext;
33
+ * }
34
+ * ```
35
+ */
36
+ export type { JwtValidationConfig, JwtValidationError, JwtValidationResult, } from "./types";
37
+ export { extractAuthContextFromJwt, validateJwtToken } from "./validate";
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/jwt/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * JWT Utilities for Uploadista Authentication
3
+ *
4
+ * This module provides JWT token validation and AuthContext extraction utilities
5
+ * for implementing SaaS-mode authentication in uploadista adapters.
6
+ *
7
+ * @example Basic JWT validation
8
+ * ```typescript
9
+ * import { validateJwtToken } from '@uploadista/server/auth/jwt';
10
+ *
11
+ * const result = await validateJwtToken(token, {
12
+ * secret: process.env.JWT_SECRET,
13
+ * issuer: 'https://auth.myapp.com',
14
+ * audience: 'uploadista-api',
15
+ * });
16
+ *
17
+ * if (result.success) {
18
+ * console.log('Valid token for user:', result.userId);
19
+ * }
20
+ * ```
21
+ *
22
+ * @example Extract AuthContext
23
+ * ```typescript
24
+ * import { extractAuthContextFromJwt } from '@uploadista/server/auth/jwt';
25
+ *
26
+ * const authContext = await extractAuthContextFromJwt(token, {
27
+ * secret: process.env.JWT_SECRET,
28
+ * });
29
+ *
30
+ * if (authContext) {
31
+ * // Use auth context in your middleware
32
+ * return authContext;
33
+ * }
34
+ * ```
35
+ */
36
+ export { extractAuthContextFromJwt, validateJwtToken } from "./validate";
@@ -0,0 +1,77 @@
1
+ /**
2
+ * JWT validation configuration options
3
+ */
4
+ export type JwtValidationConfig = {
5
+ /**
6
+ * The secret key or public key used to verify the JWT signature.
7
+ * - For HS256: Use a string secret
8
+ * - For RS256/ES256: Use a public key (string in PEM format or KeyLike)
9
+ */
10
+ secret: string | Uint8Array;
11
+ /**
12
+ * Expected issuer (iss claim) of the JWT.
13
+ * If provided, validation will fail if the token's issuer doesn't match.
14
+ */
15
+ issuer?: string;
16
+ /**
17
+ * Expected audience (aud claim) of the JWT.
18
+ * If provided, validation will fail if the token's audience doesn't match.
19
+ */
20
+ audience?: string;
21
+ /**
22
+ * Clock tolerance in seconds for expiry validation.
23
+ * Allows tokens to be considered valid even if they're slightly expired
24
+ * to account for clock skew between servers.
25
+ * @default 60 (1 minute)
26
+ */
27
+ clockTolerance?: number;
28
+ /**
29
+ * Allowed signing algorithms.
30
+ * If not specified, all standard algorithms are allowed (HS256, RS256, ES256).
31
+ * It's recommended to explicitly specify expected algorithms for security.
32
+ */
33
+ algorithms?: string[];
34
+ };
35
+ /**
36
+ * JWT validation result - either success with claims or failure with error
37
+ */
38
+ export type JwtValidationResult = {
39
+ success: true;
40
+ claims: Record<string, unknown>;
41
+ userId: string;
42
+ } | {
43
+ success: false;
44
+ error: JwtValidationError;
45
+ };
46
+ /**
47
+ * JWT validation error types
48
+ */
49
+ export type JwtValidationError = {
50
+ type: "INVALID_TOKEN";
51
+ message: string;
52
+ } | {
53
+ type: "EXPIRED";
54
+ message: string;
55
+ } | {
56
+ type: "INVALID_SIGNATURE";
57
+ message: string;
58
+ } | {
59
+ type: "INVALID_ISSUER";
60
+ message: string;
61
+ expected: string;
62
+ actual: string;
63
+ } | {
64
+ type: "INVALID_AUDIENCE";
65
+ message: string;
66
+ expected: string;
67
+ actual: string;
68
+ } | {
69
+ type: "MISSING_SUBJECT";
70
+ message: string;
71
+ } | {
72
+ type: "INVALID_ALGORITHM";
73
+ message: string;
74
+ expected: string[];
75
+ actual: string;
76
+ };
77
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/auth/jwt/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;OAIG;IACH,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC;IAE5B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IACE,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,kBAAkB,CAAC;CAC3B,CAAC;AAEN;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC/E;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC"}
@@ -0,0 +1 @@
1
+ export {};