@inneropen/marvin-sdk 1.0.3 → 1.3.1

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.
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Authentication strategy interface
3
+ *
4
+ * Different API surfaces use different auth methods:
5
+ * - Publishing API: Bearer token (site client token)
6
+ * - Platform API: Session token or user token
7
+ * - Admin API: Admin session token
8
+ */
9
+ interface AuthStrategy {
10
+ /**
11
+ * Inject authentication headers into the request
12
+ */
13
+ injectAuth(headers: Headers): void;
14
+ /**
15
+ * Handle unauthorized responses (401)
16
+ * Optional - can be used for token refresh, redirect to login, etc.
17
+ */
18
+ handleUnauthorized?(): Promise<void>;
19
+ /**
20
+ * Get a description of the auth strategy (for debugging)
21
+ */
22
+ getDescription(): string;
23
+ }
24
+ /**
25
+ * Bearer token authentication (Publishing API, User tokens)
26
+ */
27
+ declare class BearerTokenAuth implements AuthStrategy {
28
+ private token;
29
+ constructor(token: string);
30
+ injectAuth(headers: Headers): void;
31
+ getDescription(): string;
32
+ }
33
+ /**
34
+ * Session-based authentication (Platform/Admin APIs in browser)
35
+ * Relies on HTTP-only cookies set by the server
36
+ */
37
+ declare class SessionAuth implements AuthStrategy {
38
+ private sessionToken?;
39
+ private onUnauthorized?;
40
+ constructor(sessionToken?: string | undefined, onUnauthorized?: (() => Promise<void>) | undefined);
41
+ injectAuth(headers: Headers): void;
42
+ handleUnauthorized(): Promise<void>;
43
+ getDescription(): string;
44
+ }
45
+ /**
46
+ * No authentication (for public endpoints)
47
+ */
48
+ declare class NoAuth implements AuthStrategy {
49
+ injectAuth(_headers: Headers): void;
50
+ getDescription(): string;
51
+ }
52
+
53
+ /**
54
+ * Base HTTP client for Marvin APIs
55
+ */
56
+
57
+ interface HttpClientConfig {
58
+ baseUrl: string;
59
+ auth: AuthStrategy;
60
+ defaultHeaders?: Record<string, string>;
61
+ credentials?: RequestCredentials;
62
+ timeout?: number;
63
+ }
64
+ declare class HttpClient {
65
+ private baseUrl;
66
+ private auth;
67
+ private defaultHeaders;
68
+ private credentials;
69
+ private timeout;
70
+ constructor(config: HttpClientConfig);
71
+ /**
72
+ * Build full URL from endpoint
73
+ */
74
+ private buildUrl;
75
+ /**
76
+ * Build headers for request
77
+ */
78
+ private buildHeaders;
79
+ /**
80
+ * Build query string from params
81
+ */
82
+ buildQueryString(params: Record<string, string | number | boolean | undefined>): string;
83
+ /**
84
+ * Perform HTTP request
85
+ */
86
+ request<T>(method: string, endpoint: string, options?: {
87
+ body?: unknown;
88
+ headers?: Record<string, string>;
89
+ params?: Record<string, string | number | boolean | undefined>;
90
+ }): Promise<T>;
91
+ /**
92
+ * GET request
93
+ */
94
+ get<T>(endpoint: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
95
+ /**
96
+ * POST request
97
+ */
98
+ post<T>(endpoint: string, body?: unknown): Promise<T>;
99
+ /**
100
+ * PUT request
101
+ */
102
+ put<T>(endpoint: string, body?: unknown): Promise<T>;
103
+ /**
104
+ * PATCH request
105
+ */
106
+ patch<T>(endpoint: string, body?: unknown): Promise<T>;
107
+ /**
108
+ * DELETE request
109
+ */
110
+ delete<T>(endpoint: string): Promise<T>;
111
+ }
112
+
113
+ export { type AuthStrategy as A, BearerTokenAuth as B, HttpClient as H, NoAuth as N, SessionAuth as S, type HttpClientConfig as a };
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Authentication strategy interface
3
+ *
4
+ * Different API surfaces use different auth methods:
5
+ * - Publishing API: Bearer token (site client token)
6
+ * - Platform API: Session token or user token
7
+ * - Admin API: Admin session token
8
+ */
9
+ interface AuthStrategy {
10
+ /**
11
+ * Inject authentication headers into the request
12
+ */
13
+ injectAuth(headers: Headers): void;
14
+ /**
15
+ * Handle unauthorized responses (401)
16
+ * Optional - can be used for token refresh, redirect to login, etc.
17
+ */
18
+ handleUnauthorized?(): Promise<void>;
19
+ /**
20
+ * Get a description of the auth strategy (for debugging)
21
+ */
22
+ getDescription(): string;
23
+ }
24
+ /**
25
+ * Bearer token authentication (Publishing API, User tokens)
26
+ */
27
+ declare class BearerTokenAuth implements AuthStrategy {
28
+ private token;
29
+ constructor(token: string);
30
+ injectAuth(headers: Headers): void;
31
+ getDescription(): string;
32
+ }
33
+ /**
34
+ * Session-based authentication (Platform/Admin APIs in browser)
35
+ * Relies on HTTP-only cookies set by the server
36
+ */
37
+ declare class SessionAuth implements AuthStrategy {
38
+ private sessionToken?;
39
+ private onUnauthorized?;
40
+ constructor(sessionToken?: string | undefined, onUnauthorized?: (() => Promise<void>) | undefined);
41
+ injectAuth(headers: Headers): void;
42
+ handleUnauthorized(): Promise<void>;
43
+ getDescription(): string;
44
+ }
45
+ /**
46
+ * No authentication (for public endpoints)
47
+ */
48
+ declare class NoAuth implements AuthStrategy {
49
+ injectAuth(_headers: Headers): void;
50
+ getDescription(): string;
51
+ }
52
+
53
+ /**
54
+ * Base HTTP client for Marvin APIs
55
+ */
56
+
57
+ interface HttpClientConfig {
58
+ baseUrl: string;
59
+ auth: AuthStrategy;
60
+ defaultHeaders?: Record<string, string>;
61
+ credentials?: RequestCredentials;
62
+ timeout?: number;
63
+ }
64
+ declare class HttpClient {
65
+ private baseUrl;
66
+ private auth;
67
+ private defaultHeaders;
68
+ private credentials;
69
+ private timeout;
70
+ constructor(config: HttpClientConfig);
71
+ /**
72
+ * Build full URL from endpoint
73
+ */
74
+ private buildUrl;
75
+ /**
76
+ * Build headers for request
77
+ */
78
+ private buildHeaders;
79
+ /**
80
+ * Build query string from params
81
+ */
82
+ buildQueryString(params: Record<string, string | number | boolean | undefined>): string;
83
+ /**
84
+ * Perform HTTP request
85
+ */
86
+ request<T>(method: string, endpoint: string, options?: {
87
+ body?: unknown;
88
+ headers?: Record<string, string>;
89
+ params?: Record<string, string | number | boolean | undefined>;
90
+ }): Promise<T>;
91
+ /**
92
+ * GET request
93
+ */
94
+ get<T>(endpoint: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
95
+ /**
96
+ * POST request
97
+ */
98
+ post<T>(endpoint: string, body?: unknown): Promise<T>;
99
+ /**
100
+ * PUT request
101
+ */
102
+ put<T>(endpoint: string, body?: unknown): Promise<T>;
103
+ /**
104
+ * PATCH request
105
+ */
106
+ patch<T>(endpoint: string, body?: unknown): Promise<T>;
107
+ /**
108
+ * DELETE request
109
+ */
110
+ delete<T>(endpoint: string): Promise<T>;
111
+ }
112
+
113
+ export { type AuthStrategy as A, BearerTokenAuth as B, HttpClient as H, NoAuth as N, SessionAuth as S, type HttpClientConfig as a };
@@ -0,0 +1,391 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __esm = (fn, res) => function __init() {
6
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
+ };
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/core/errors/MarvinError.ts
23
+ var MarvinError, MarvinApiError, MarvinAuthError, MarvinConfigError, MarvinValidationError;
24
+ var init_MarvinError = __esm({
25
+ "src/core/errors/MarvinError.ts"() {
26
+ "use strict";
27
+ MarvinError = class _MarvinError extends Error {
28
+ constructor(message, code, statusCode) {
29
+ super(message);
30
+ this.code = code;
31
+ this.statusCode = statusCode;
32
+ this.name = "MarvinError";
33
+ Object.setPrototypeOf(this, _MarvinError.prototype);
34
+ }
35
+ code;
36
+ statusCode;
37
+ };
38
+ MarvinApiError = class _MarvinApiError extends MarvinError {
39
+ constructor(message, statusCode, endpoint, responseBody) {
40
+ super(message, "API_ERROR", statusCode);
41
+ this.statusCode = statusCode;
42
+ this.endpoint = endpoint;
43
+ this.responseBody = responseBody;
44
+ this.name = "MarvinApiError";
45
+ Object.setPrototypeOf(this, _MarvinApiError.prototype);
46
+ }
47
+ statusCode;
48
+ endpoint;
49
+ responseBody;
50
+ static fromResponse(status, statusText, endpoint, body) {
51
+ const message = `Marvin API error: ${status} ${statusText} at ${endpoint}${body ? `
52
+ ${body}` : ""}`;
53
+ return new _MarvinApiError(message, status, endpoint, body);
54
+ }
55
+ };
56
+ MarvinAuthError = class _MarvinAuthError extends MarvinError {
57
+ constructor(message, statusCode) {
58
+ super(message, "AUTH_ERROR", statusCode);
59
+ this.name = "MarvinAuthError";
60
+ Object.setPrototypeOf(this, _MarvinAuthError.prototype);
61
+ }
62
+ };
63
+ MarvinConfigError = class _MarvinConfigError extends MarvinError {
64
+ constructor(message) {
65
+ super(message, "CONFIG_ERROR");
66
+ this.name = "MarvinConfigError";
67
+ Object.setPrototypeOf(this, _MarvinConfigError.prototype);
68
+ }
69
+ };
70
+ MarvinValidationError = class _MarvinValidationError extends MarvinError {
71
+ constructor(message, field) {
72
+ super(message, "VALIDATION_ERROR");
73
+ this.field = field;
74
+ this.name = "MarvinValidationError";
75
+ Object.setPrototypeOf(this, _MarvinValidationError.prototype);
76
+ }
77
+ field;
78
+ };
79
+ }
80
+ });
81
+
82
+ // src/core/errors/index.ts
83
+ var init_errors = __esm({
84
+ "src/core/errors/index.ts"() {
85
+ "use strict";
86
+ init_MarvinError();
87
+ }
88
+ });
89
+
90
+ // src/core/http/HttpClient.ts
91
+ var HttpClient;
92
+ var init_HttpClient = __esm({
93
+ "src/core/http/HttpClient.ts"() {
94
+ "use strict";
95
+ init_errors();
96
+ HttpClient = class {
97
+ baseUrl;
98
+ auth;
99
+ defaultHeaders;
100
+ credentials;
101
+ timeout;
102
+ constructor(config) {
103
+ this.baseUrl = config.baseUrl;
104
+ this.auth = config.auth;
105
+ this.defaultHeaders = config.defaultHeaders || {};
106
+ this.credentials = config.credentials || "same-origin";
107
+ this.timeout = config.timeout || 3e4;
108
+ }
109
+ /**
110
+ * Build full URL from endpoint
111
+ */
112
+ buildUrl(endpoint) {
113
+ const base = this.baseUrl.replace(/\/$/, "");
114
+ const path = endpoint.replace(/^\//, "");
115
+ return `${base}/${path}`;
116
+ }
117
+ /**
118
+ * Build headers for request
119
+ */
120
+ buildHeaders(additionalHeaders) {
121
+ const headers = new Headers({
122
+ "Content-Type": "application/json",
123
+ ...this.defaultHeaders,
124
+ ...additionalHeaders
125
+ });
126
+ this.auth.injectAuth(headers);
127
+ return headers;
128
+ }
129
+ /**
130
+ * Build query string from params
131
+ */
132
+ buildQueryString(params) {
133
+ const filtered = Object.entries(params).filter(([_, value]) => value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
134
+ return filtered.length > 0 ? `?${filtered.join("&")}` : "";
135
+ }
136
+ /**
137
+ * Perform HTTP request
138
+ */
139
+ async request(method, endpoint, options) {
140
+ const url = this.buildUrl(endpoint) + (options?.params ? this.buildQueryString(options.params) : "");
141
+ const headers = this.buildHeaders(options?.headers);
142
+ const controller = new AbortController();
143
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
144
+ try {
145
+ const response = await fetch(url, {
146
+ method,
147
+ headers,
148
+ body: options?.body ? JSON.stringify(options.body) : void 0,
149
+ credentials: this.credentials,
150
+ signal: controller.signal
151
+ });
152
+ clearTimeout(timeoutId);
153
+ if (response.status === 401 && this.auth.handleUnauthorized) {
154
+ await this.auth.handleUnauthorized();
155
+ }
156
+ if (!response.ok) {
157
+ const errorText = await response.text().catch(() => "");
158
+ throw MarvinApiError.fromResponse(
159
+ response.status,
160
+ response.statusText,
161
+ endpoint,
162
+ errorText
163
+ );
164
+ }
165
+ const contentType = response.headers.get("content-type");
166
+ if (!contentType || !contentType.includes("application/json")) {
167
+ return void 0;
168
+ }
169
+ return await response.json();
170
+ } catch (error) {
171
+ clearTimeout(timeoutId);
172
+ if (error instanceof MarvinApiError) {
173
+ throw error;
174
+ }
175
+ if (error instanceof Error) {
176
+ if (error.name === "AbortError") {
177
+ throw new MarvinApiError(
178
+ `Request timeout after ${this.timeout}ms`,
179
+ 408,
180
+ endpoint
181
+ );
182
+ }
183
+ throw new MarvinApiError(error.message, 0, endpoint);
184
+ }
185
+ throw error;
186
+ }
187
+ }
188
+ /**
189
+ * GET request
190
+ */
191
+ async get(endpoint, params) {
192
+ return this.request("GET", endpoint, { params });
193
+ }
194
+ /**
195
+ * POST request
196
+ */
197
+ async post(endpoint, body) {
198
+ return this.request("POST", endpoint, { body });
199
+ }
200
+ /**
201
+ * PUT request
202
+ */
203
+ async put(endpoint, body) {
204
+ return this.request("PUT", endpoint, { body });
205
+ }
206
+ /**
207
+ * PATCH request
208
+ */
209
+ async patch(endpoint, body) {
210
+ return this.request("PATCH", endpoint, { body });
211
+ }
212
+ /**
213
+ * DELETE request
214
+ */
215
+ async delete(endpoint) {
216
+ return this.request("DELETE", endpoint);
217
+ }
218
+ };
219
+ }
220
+ });
221
+
222
+ // src/core/http/index.ts
223
+ var init_http = __esm({
224
+ "src/core/http/index.ts"() {
225
+ "use strict";
226
+ init_HttpClient();
227
+ }
228
+ });
229
+
230
+ // src/core/auth/AuthStrategy.ts
231
+ var BearerTokenAuth, SessionAuth, NoAuth;
232
+ var init_AuthStrategy = __esm({
233
+ "src/core/auth/AuthStrategy.ts"() {
234
+ "use strict";
235
+ BearerTokenAuth = class {
236
+ constructor(token) {
237
+ this.token = token;
238
+ }
239
+ token;
240
+ injectAuth(headers) {
241
+ headers.set("Authorization", `Bearer ${this.token}`);
242
+ }
243
+ getDescription() {
244
+ return "Bearer token authentication";
245
+ }
246
+ };
247
+ SessionAuth = class {
248
+ constructor(sessionToken, onUnauthorized) {
249
+ this.sessionToken = sessionToken;
250
+ this.onUnauthorized = onUnauthorized;
251
+ }
252
+ sessionToken;
253
+ onUnauthorized;
254
+ injectAuth(headers) {
255
+ if (this.sessionToken) {
256
+ headers.set("Authorization", `Bearer ${this.sessionToken}`);
257
+ }
258
+ }
259
+ async handleUnauthorized() {
260
+ if (this.onUnauthorized) {
261
+ await this.onUnauthorized();
262
+ }
263
+ }
264
+ getDescription() {
265
+ return this.sessionToken ? "Session authentication (explicit token)" : "Session authentication (cookies)";
266
+ }
267
+ };
268
+ NoAuth = class {
269
+ injectAuth(_headers) {
270
+ }
271
+ getDescription() {
272
+ return "No authentication";
273
+ }
274
+ };
275
+ }
276
+ });
277
+
278
+ // src/core/auth/index.ts
279
+ var init_auth = __esm({
280
+ "src/core/auth/index.ts"() {
281
+ "use strict";
282
+ init_AuthStrategy();
283
+ }
284
+ });
285
+
286
+ // src/core/pagination/PaginatedResponse.ts
287
+ function createPaginatedResponse(data, meta) {
288
+ return { data, meta };
289
+ }
290
+ function extractData(response) {
291
+ if (Array.isArray(response)) {
292
+ return response;
293
+ }
294
+ return response.data;
295
+ }
296
+ function isPaginatedResponse(response) {
297
+ return !Array.isArray(response) && "data" in response;
298
+ }
299
+ function pageToOffset(page, limit) {
300
+ return (page - 1) * limit;
301
+ }
302
+ function offsetToPage(offset, limit) {
303
+ return Math.floor(offset / limit) + 1;
304
+ }
305
+ var init_PaginatedResponse = __esm({
306
+ "src/core/pagination/PaginatedResponse.ts"() {
307
+ "use strict";
308
+ }
309
+ });
310
+
311
+ // src/core/pagination/index.ts
312
+ var init_pagination = __esm({
313
+ "src/core/pagination/index.ts"() {
314
+ "use strict";
315
+ init_PaginatedResponse();
316
+ }
317
+ });
318
+
319
+ // src/core/cache.ts
320
+ var MarvinCache;
321
+ var init_cache = __esm({
322
+ "src/core/cache.ts"() {
323
+ "use strict";
324
+ MarvinCache = class {
325
+ constructor(duration = 5 * 60 * 1e3) {
326
+ this.duration = duration;
327
+ }
328
+ duration;
329
+ cache = /* @__PURE__ */ new Map();
330
+ get(key) {
331
+ const entry = this.cache.get(key);
332
+ if (!entry) return void 0;
333
+ const age = Date.now() - entry.timestamp;
334
+ if (age > this.duration) {
335
+ this.cache.delete(key);
336
+ return void 0;
337
+ }
338
+ return entry.data;
339
+ }
340
+ set(key, data) {
341
+ this.cache.set(key, {
342
+ data,
343
+ timestamp: Date.now()
344
+ });
345
+ }
346
+ has(key) {
347
+ return this.get(key) !== void 0;
348
+ }
349
+ clear() {
350
+ this.cache.clear();
351
+ }
352
+ delete(key) {
353
+ this.cache.delete(key);
354
+ }
355
+ };
356
+ }
357
+ });
358
+
359
+ // src/core/index.ts
360
+ var init_core = __esm({
361
+ "src/core/index.ts"() {
362
+ "use strict";
363
+ init_http();
364
+ init_auth();
365
+ init_errors();
366
+ init_pagination();
367
+ init_cache();
368
+ }
369
+ });
370
+
371
+ export {
372
+ __esm,
373
+ __export,
374
+ __toCommonJS,
375
+ MarvinError,
376
+ MarvinApiError,
377
+ MarvinAuthError,
378
+ MarvinConfigError,
379
+ MarvinValidationError,
380
+ HttpClient,
381
+ BearerTokenAuth,
382
+ SessionAuth,
383
+ NoAuth,
384
+ createPaginatedResponse,
385
+ extractData,
386
+ isPaginatedResponse,
387
+ pageToOffset,
388
+ offsetToPage,
389
+ MarvinCache,
390
+ init_core
391
+ };