@inneropen/marvin-sdk 2.0.0-next.11 → 2.0.0-next.13
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/{HttpClient-CLtgQGXH.d.cts → HttpClient-BX5Gqd0w.d.cts} +8 -0
- package/dist/{HttpClient-CLtgQGXH.d.ts → HttpClient-BX5Gqd0w.d.ts} +8 -0
- package/dist/{chunk-25F3IF6S.js → chunk-DYC2BEA4.js} +84 -7
- package/dist/index.cjs +185 -18
- package/dist/index.d.cts +75 -9
- package/dist/index.d.ts +75 -9
- package/dist/index.js +107 -12
- package/dist/platform.cjs +86 -6
- package/dist/platform.d.cts +1 -1
- package/dist/platform.d.ts +1 -1
- package/dist/platform.js +1 -1
- package/package.json +1 -1
|
@@ -60,6 +60,12 @@ interface HttpClientConfig {
|
|
|
60
60
|
defaultHeaders?: Record<string, string>;
|
|
61
61
|
credentials?: RequestCredentials;
|
|
62
62
|
timeout?: number;
|
|
63
|
+
debug?: boolean;
|
|
64
|
+
logger?: {
|
|
65
|
+
log: (message: string, ...args: unknown[]) => void;
|
|
66
|
+
warn: (message: string, ...args: unknown[]) => void;
|
|
67
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
68
|
+
};
|
|
63
69
|
}
|
|
64
70
|
declare class HttpClient {
|
|
65
71
|
private baseUrl;
|
|
@@ -67,6 +73,8 @@ declare class HttpClient {
|
|
|
67
73
|
private defaultHeaders;
|
|
68
74
|
private credentials;
|
|
69
75
|
private timeout;
|
|
76
|
+
private debug;
|
|
77
|
+
private logger;
|
|
70
78
|
constructor(config: HttpClientConfig);
|
|
71
79
|
/**
|
|
72
80
|
* Build full URL from endpoint
|
|
@@ -60,6 +60,12 @@ interface HttpClientConfig {
|
|
|
60
60
|
defaultHeaders?: Record<string, string>;
|
|
61
61
|
credentials?: RequestCredentials;
|
|
62
62
|
timeout?: number;
|
|
63
|
+
debug?: boolean;
|
|
64
|
+
logger?: {
|
|
65
|
+
log: (message: string, ...args: unknown[]) => void;
|
|
66
|
+
warn: (message: string, ...args: unknown[]) => void;
|
|
67
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
68
|
+
};
|
|
63
69
|
}
|
|
64
70
|
declare class HttpClient {
|
|
65
71
|
private baseUrl;
|
|
@@ -67,6 +73,8 @@ declare class HttpClient {
|
|
|
67
73
|
private defaultHeaders;
|
|
68
74
|
private credentials;
|
|
69
75
|
private timeout;
|
|
76
|
+
private debug;
|
|
77
|
+
private logger;
|
|
70
78
|
constructor(config: HttpClientConfig);
|
|
71
79
|
/**
|
|
72
80
|
* Build full URL from endpoint
|
|
@@ -20,7 +20,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
20
20
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
21
|
|
|
22
22
|
// src/core/errors/MarvinError.ts
|
|
23
|
-
var MarvinError, MarvinApiError, MarvinAuthError, MarvinConfigError, MarvinValidationError;
|
|
23
|
+
var MarvinError, MarvinApiError, MarvinAuthError, MarvinConfigError, MarvinValidationError, MarvinNotFoundError, MarvinNetworkError, MarvinServerError;
|
|
24
24
|
var init_MarvinError = __esm({
|
|
25
25
|
"src/core/errors/MarvinError.ts"() {
|
|
26
26
|
"use strict";
|
|
@@ -76,6 +76,33 @@ ${body}` : ""}`;
|
|
|
76
76
|
}
|
|
77
77
|
field;
|
|
78
78
|
};
|
|
79
|
+
MarvinNotFoundError = class _MarvinNotFoundError extends MarvinError {
|
|
80
|
+
constructor(message, endpoint) {
|
|
81
|
+
super(message, "NOT_FOUND", 404);
|
|
82
|
+
this.endpoint = endpoint;
|
|
83
|
+
this.name = "MarvinNotFoundError";
|
|
84
|
+
Object.setPrototypeOf(this, _MarvinNotFoundError.prototype);
|
|
85
|
+
}
|
|
86
|
+
endpoint;
|
|
87
|
+
};
|
|
88
|
+
MarvinNetworkError = class _MarvinNetworkError extends MarvinError {
|
|
89
|
+
constructor(message, originalError) {
|
|
90
|
+
super(message, "NETWORK_ERROR");
|
|
91
|
+
this.originalError = originalError;
|
|
92
|
+
this.name = "MarvinNetworkError";
|
|
93
|
+
Object.setPrototypeOf(this, _MarvinNetworkError.prototype);
|
|
94
|
+
}
|
|
95
|
+
originalError;
|
|
96
|
+
};
|
|
97
|
+
MarvinServerError = class _MarvinServerError extends MarvinError {
|
|
98
|
+
constructor(message, statusCode, endpoint) {
|
|
99
|
+
super(message, "SERVER_ERROR", statusCode);
|
|
100
|
+
this.endpoint = endpoint;
|
|
101
|
+
this.name = "MarvinServerError";
|
|
102
|
+
Object.setPrototypeOf(this, _MarvinServerError.prototype);
|
|
103
|
+
}
|
|
104
|
+
endpoint;
|
|
105
|
+
};
|
|
79
106
|
}
|
|
80
107
|
});
|
|
81
108
|
|
|
@@ -99,12 +126,16 @@ var init_HttpClient = __esm({
|
|
|
99
126
|
defaultHeaders;
|
|
100
127
|
credentials;
|
|
101
128
|
timeout;
|
|
129
|
+
debug;
|
|
130
|
+
logger;
|
|
102
131
|
constructor(config) {
|
|
103
132
|
this.baseUrl = config.baseUrl;
|
|
104
133
|
this.auth = config.auth;
|
|
105
134
|
this.defaultHeaders = config.defaultHeaders || {};
|
|
106
135
|
this.credentials = config.credentials || "same-origin";
|
|
107
136
|
this.timeout = config.timeout || 3e4;
|
|
137
|
+
this.debug = config.debug ?? false;
|
|
138
|
+
this.logger = config.logger ?? console;
|
|
108
139
|
}
|
|
109
140
|
/**
|
|
110
141
|
* Build full URL from endpoint
|
|
@@ -146,6 +177,10 @@ var init_HttpClient = __esm({
|
|
|
146
177
|
const headers = this.buildHeaders(options?.headers, isFormData);
|
|
147
178
|
const controller = new AbortController();
|
|
148
179
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
180
|
+
const startTime = Date.now();
|
|
181
|
+
if (this.debug) {
|
|
182
|
+
this.logger.log(`[Marvin] ${method} ${url}`);
|
|
183
|
+
}
|
|
149
184
|
try {
|
|
150
185
|
const response = await fetch(url, {
|
|
151
186
|
method,
|
|
@@ -155,11 +190,42 @@ var init_HttpClient = __esm({
|
|
|
155
190
|
signal: controller.signal
|
|
156
191
|
});
|
|
157
192
|
clearTimeout(timeoutId);
|
|
193
|
+
const duration = Date.now() - startTime;
|
|
194
|
+
if (this.debug) {
|
|
195
|
+
this.logger.log(
|
|
196
|
+
`[Marvin] ${response.status} ${response.statusText} (${duration}ms)`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
158
199
|
if (response.status === 401 && this.auth.handleUnauthorized) {
|
|
159
200
|
await this.auth.handleUnauthorized();
|
|
160
201
|
}
|
|
161
202
|
if (!response.ok) {
|
|
162
203
|
const errorText = await response.text().catch(() => "");
|
|
204
|
+
if (this.debug) {
|
|
205
|
+
this.logger.error(
|
|
206
|
+
`[Marvin] Error response: ${response.status} ${response.statusText}`,
|
|
207
|
+
errorText ? `Body: ${errorText}` : ""
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
if (response.status === 404) {
|
|
211
|
+
throw new MarvinNotFoundError(
|
|
212
|
+
`Resource not found: ${endpoint}`,
|
|
213
|
+
endpoint
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
if (response.status === 401 || response.status === 403) {
|
|
217
|
+
throw new MarvinAuthError(
|
|
218
|
+
`Authentication failed: ${response.statusText}`,
|
|
219
|
+
response.status
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
if (response.status >= 500) {
|
|
223
|
+
throw new MarvinServerError(
|
|
224
|
+
`Server error: ${response.status} ${response.statusText}`,
|
|
225
|
+
response.status,
|
|
226
|
+
endpoint
|
|
227
|
+
);
|
|
228
|
+
}
|
|
163
229
|
throw MarvinApiError.fromResponse(
|
|
164
230
|
response.status,
|
|
165
231
|
response.statusText,
|
|
@@ -171,21 +237,28 @@ var init_HttpClient = __esm({
|
|
|
171
237
|
if (!contentType || !contentType.includes("application/json")) {
|
|
172
238
|
return void 0;
|
|
173
239
|
}
|
|
174
|
-
|
|
240
|
+
const data = await response.json();
|
|
241
|
+
if (this.debug) {
|
|
242
|
+
const preview = typeof data === "object" && data !== null ? Array.isArray(data) ? `Array(${data.length})` : `Object with keys: ${Object.keys(data).join(", ")}` : String(data);
|
|
243
|
+
this.logger.log(`[Marvin] Response: ${preview}`);
|
|
244
|
+
}
|
|
245
|
+
return data;
|
|
175
246
|
} catch (error) {
|
|
176
247
|
clearTimeout(timeoutId);
|
|
177
|
-
if (error instanceof MarvinApiError) {
|
|
248
|
+
if (error instanceof MarvinApiError || error instanceof MarvinNotFoundError || error instanceof MarvinAuthError || error instanceof MarvinServerError) {
|
|
178
249
|
throw error;
|
|
179
250
|
}
|
|
180
251
|
if (error instanceof Error) {
|
|
181
252
|
if (error.name === "AbortError") {
|
|
182
|
-
throw new
|
|
253
|
+
throw new MarvinNetworkError(
|
|
183
254
|
`Request timeout after ${this.timeout}ms`,
|
|
184
|
-
|
|
185
|
-
endpoint
|
|
255
|
+
error
|
|
186
256
|
);
|
|
187
257
|
}
|
|
188
|
-
throw new
|
|
258
|
+
throw new MarvinNetworkError(
|
|
259
|
+
`Network error: ${error.message}`,
|
|
260
|
+
error
|
|
261
|
+
);
|
|
189
262
|
}
|
|
190
263
|
throw error;
|
|
191
264
|
}
|
|
@@ -382,6 +455,10 @@ export {
|
|
|
382
455
|
MarvinAuthError,
|
|
383
456
|
MarvinConfigError,
|
|
384
457
|
MarvinValidationError,
|
|
458
|
+
MarvinNotFoundError,
|
|
459
|
+
MarvinNetworkError,
|
|
460
|
+
MarvinServerError,
|
|
461
|
+
init_errors,
|
|
385
462
|
HttpClient,
|
|
386
463
|
BearerTokenAuth,
|
|
387
464
|
SessionAuth,
|
package/dist/index.cjs
CHANGED
|
@@ -27,14 +27,21 @@ __export(config_exports, {
|
|
|
27
27
|
validateConfig: () => validateConfig
|
|
28
28
|
});
|
|
29
29
|
function validateConfig(config) {
|
|
30
|
+
const receivedKeys = Object.keys(config).join(", ");
|
|
30
31
|
if (!config.apiUrl) {
|
|
31
|
-
throw new Error(
|
|
32
|
+
throw new Error(
|
|
33
|
+
`Missing required config parameter 'apiUrl'. Received config keys: ${receivedKeys || "(none)"}. Set this to your MARVIN_API_URL environment variable value.`
|
|
34
|
+
);
|
|
32
35
|
}
|
|
33
36
|
if (!config.siteClientToken) {
|
|
34
|
-
throw new Error(
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Missing required config parameter 'siteClientToken'. Received config keys: ${receivedKeys}. Set this to your MARVIN_SITE_CLIENT_TOKEN environment variable value.`
|
|
39
|
+
);
|
|
35
40
|
}
|
|
36
41
|
if (!config.workspaceSlug) {
|
|
37
|
-
throw new Error(
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Missing required config parameter 'workspaceSlug'. Received config keys: ${receivedKeys}. Set this to your MARVIN_WORKSPACE_SLUG environment variable value.`
|
|
44
|
+
);
|
|
38
45
|
}
|
|
39
46
|
}
|
|
40
47
|
function createConfigFromEnv(overrides) {
|
|
@@ -43,8 +50,10 @@ function createConfigFromEnv(overrides) {
|
|
|
43
50
|
siteClientToken: overrides?.siteClientToken || process.env.MARVIN_SITE_CLIENT_TOKEN || "",
|
|
44
51
|
workspaceSlug: overrides?.workspaceSlug || process.env.MARVIN_WORKSPACE_SLUG || "",
|
|
45
52
|
autoInitialize: overrides?.autoInitialize ?? false,
|
|
46
|
-
cacheDuration: overrides?.cacheDuration ?? 5 * 60 * 1e3
|
|
53
|
+
cacheDuration: overrides?.cacheDuration ?? 5 * 60 * 1e3,
|
|
47
54
|
// 5 minutes
|
|
55
|
+
debug: overrides?.debug ?? process.env.MARVIN_DEBUG === "true",
|
|
56
|
+
logger: overrides?.logger ?? console
|
|
48
57
|
};
|
|
49
58
|
}
|
|
50
59
|
var init_config = __esm({
|
|
@@ -54,7 +63,7 @@ var init_config = __esm({
|
|
|
54
63
|
});
|
|
55
64
|
|
|
56
65
|
// src/core/errors/MarvinError.ts
|
|
57
|
-
var MarvinError, MarvinApiError, MarvinAuthError, MarvinConfigError, MarvinValidationError;
|
|
66
|
+
var MarvinError, MarvinApiError, MarvinAuthError, MarvinConfigError, MarvinValidationError, MarvinNotFoundError, MarvinNetworkError, MarvinServerError;
|
|
58
67
|
var init_MarvinError = __esm({
|
|
59
68
|
"src/core/errors/MarvinError.ts"() {
|
|
60
69
|
"use strict";
|
|
@@ -110,6 +119,33 @@ ${body}` : ""}`;
|
|
|
110
119
|
}
|
|
111
120
|
field;
|
|
112
121
|
};
|
|
122
|
+
MarvinNotFoundError = class _MarvinNotFoundError extends MarvinError {
|
|
123
|
+
constructor(message, endpoint) {
|
|
124
|
+
super(message, "NOT_FOUND", 404);
|
|
125
|
+
this.endpoint = endpoint;
|
|
126
|
+
this.name = "MarvinNotFoundError";
|
|
127
|
+
Object.setPrototypeOf(this, _MarvinNotFoundError.prototype);
|
|
128
|
+
}
|
|
129
|
+
endpoint;
|
|
130
|
+
};
|
|
131
|
+
MarvinNetworkError = class _MarvinNetworkError extends MarvinError {
|
|
132
|
+
constructor(message, originalError) {
|
|
133
|
+
super(message, "NETWORK_ERROR");
|
|
134
|
+
this.originalError = originalError;
|
|
135
|
+
this.name = "MarvinNetworkError";
|
|
136
|
+
Object.setPrototypeOf(this, _MarvinNetworkError.prototype);
|
|
137
|
+
}
|
|
138
|
+
originalError;
|
|
139
|
+
};
|
|
140
|
+
MarvinServerError = class _MarvinServerError extends MarvinError {
|
|
141
|
+
constructor(message, statusCode, endpoint) {
|
|
142
|
+
super(message, "SERVER_ERROR", statusCode);
|
|
143
|
+
this.endpoint = endpoint;
|
|
144
|
+
this.name = "MarvinServerError";
|
|
145
|
+
Object.setPrototypeOf(this, _MarvinServerError.prototype);
|
|
146
|
+
}
|
|
147
|
+
endpoint;
|
|
148
|
+
};
|
|
113
149
|
}
|
|
114
150
|
});
|
|
115
151
|
|
|
@@ -133,12 +169,16 @@ var init_HttpClient = __esm({
|
|
|
133
169
|
defaultHeaders;
|
|
134
170
|
credentials;
|
|
135
171
|
timeout;
|
|
172
|
+
debug;
|
|
173
|
+
logger;
|
|
136
174
|
constructor(config) {
|
|
137
175
|
this.baseUrl = config.baseUrl;
|
|
138
176
|
this.auth = config.auth;
|
|
139
177
|
this.defaultHeaders = config.defaultHeaders || {};
|
|
140
178
|
this.credentials = config.credentials || "same-origin";
|
|
141
179
|
this.timeout = config.timeout || 3e4;
|
|
180
|
+
this.debug = config.debug ?? false;
|
|
181
|
+
this.logger = config.logger ?? console;
|
|
142
182
|
}
|
|
143
183
|
/**
|
|
144
184
|
* Build full URL from endpoint
|
|
@@ -180,6 +220,10 @@ var init_HttpClient = __esm({
|
|
|
180
220
|
const headers = this.buildHeaders(options?.headers, isFormData);
|
|
181
221
|
const controller = new AbortController();
|
|
182
222
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
223
|
+
const startTime = Date.now();
|
|
224
|
+
if (this.debug) {
|
|
225
|
+
this.logger.log(`[Marvin] ${method} ${url}`);
|
|
226
|
+
}
|
|
183
227
|
try {
|
|
184
228
|
const response = await fetch(url, {
|
|
185
229
|
method,
|
|
@@ -189,11 +233,42 @@ var init_HttpClient = __esm({
|
|
|
189
233
|
signal: controller.signal
|
|
190
234
|
});
|
|
191
235
|
clearTimeout(timeoutId);
|
|
236
|
+
const duration = Date.now() - startTime;
|
|
237
|
+
if (this.debug) {
|
|
238
|
+
this.logger.log(
|
|
239
|
+
`[Marvin] ${response.status} ${response.statusText} (${duration}ms)`
|
|
240
|
+
);
|
|
241
|
+
}
|
|
192
242
|
if (response.status === 401 && this.auth.handleUnauthorized) {
|
|
193
243
|
await this.auth.handleUnauthorized();
|
|
194
244
|
}
|
|
195
245
|
if (!response.ok) {
|
|
196
246
|
const errorText = await response.text().catch(() => "");
|
|
247
|
+
if (this.debug) {
|
|
248
|
+
this.logger.error(
|
|
249
|
+
`[Marvin] Error response: ${response.status} ${response.statusText}`,
|
|
250
|
+
errorText ? `Body: ${errorText}` : ""
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
if (response.status === 404) {
|
|
254
|
+
throw new MarvinNotFoundError(
|
|
255
|
+
`Resource not found: ${endpoint}`,
|
|
256
|
+
endpoint
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
if (response.status === 401 || response.status === 403) {
|
|
260
|
+
throw new MarvinAuthError(
|
|
261
|
+
`Authentication failed: ${response.statusText}`,
|
|
262
|
+
response.status
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
if (response.status >= 500) {
|
|
266
|
+
throw new MarvinServerError(
|
|
267
|
+
`Server error: ${response.status} ${response.statusText}`,
|
|
268
|
+
response.status,
|
|
269
|
+
endpoint
|
|
270
|
+
);
|
|
271
|
+
}
|
|
197
272
|
throw MarvinApiError.fromResponse(
|
|
198
273
|
response.status,
|
|
199
274
|
response.statusText,
|
|
@@ -205,21 +280,28 @@ var init_HttpClient = __esm({
|
|
|
205
280
|
if (!contentType || !contentType.includes("application/json")) {
|
|
206
281
|
return void 0;
|
|
207
282
|
}
|
|
208
|
-
|
|
283
|
+
const data = await response.json();
|
|
284
|
+
if (this.debug) {
|
|
285
|
+
const preview = typeof data === "object" && data !== null ? Array.isArray(data) ? `Array(${data.length})` : `Object with keys: ${Object.keys(data).join(", ")}` : String(data);
|
|
286
|
+
this.logger.log(`[Marvin] Response: ${preview}`);
|
|
287
|
+
}
|
|
288
|
+
return data;
|
|
209
289
|
} catch (error) {
|
|
210
290
|
clearTimeout(timeoutId);
|
|
211
|
-
if (error instanceof MarvinApiError) {
|
|
291
|
+
if (error instanceof MarvinApiError || error instanceof MarvinNotFoundError || error instanceof MarvinAuthError || error instanceof MarvinServerError) {
|
|
212
292
|
throw error;
|
|
213
293
|
}
|
|
214
294
|
if (error instanceof Error) {
|
|
215
295
|
if (error.name === "AbortError") {
|
|
216
|
-
throw new
|
|
296
|
+
throw new MarvinNetworkError(
|
|
217
297
|
`Request timeout after ${this.timeout}ms`,
|
|
218
|
-
|
|
219
|
-
endpoint
|
|
298
|
+
error
|
|
220
299
|
);
|
|
221
300
|
}
|
|
222
|
-
throw new
|
|
301
|
+
throw new MarvinNetworkError(
|
|
302
|
+
`Network error: ${error.message}`,
|
|
303
|
+
error
|
|
304
|
+
);
|
|
223
305
|
}
|
|
224
306
|
throw error;
|
|
225
307
|
}
|
|
@@ -418,7 +500,9 @@ var init_http2 = __esm({
|
|
|
418
500
|
super({
|
|
419
501
|
baseUrl: config.apiUrl,
|
|
420
502
|
auth: new BearerTokenAuth(config.siteClientToken),
|
|
421
|
-
credentials: "same-origin"
|
|
503
|
+
credentials: "same-origin",
|
|
504
|
+
debug: config.debug,
|
|
505
|
+
logger: config.logger
|
|
422
506
|
});
|
|
423
507
|
}
|
|
424
508
|
/**
|
|
@@ -555,6 +639,7 @@ var init_entries = __esm({
|
|
|
555
639
|
"src/entries/entries.ts"() {
|
|
556
640
|
"use strict";
|
|
557
641
|
init_entry();
|
|
642
|
+
init_errors();
|
|
558
643
|
EntriesModule = class {
|
|
559
644
|
constructor(http, workspaceSlug) {
|
|
560
645
|
this.http = http;
|
|
@@ -579,11 +664,19 @@ var init_entries = __esm({
|
|
|
579
664
|
}
|
|
580
665
|
/**
|
|
581
666
|
* Get a single entry by slug
|
|
667
|
+
* Returns null if entry is not found (404)
|
|
582
668
|
*/
|
|
583
669
|
async get(slug) {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
670
|
+
try {
|
|
671
|
+
const endpoint = `/api/publish/${this.workspaceSlug}/entries/${slug}`;
|
|
672
|
+
const data = await this.http.fetch(endpoint);
|
|
673
|
+
return new Entry(data, this.http, this.workspaceSlug);
|
|
674
|
+
} catch (error) {
|
|
675
|
+
if (error instanceof MarvinNotFoundError) {
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
throw error;
|
|
679
|
+
}
|
|
587
680
|
}
|
|
588
681
|
/**
|
|
589
682
|
* Convenience: Get all pages
|
|
@@ -689,6 +782,7 @@ var init_collections = __esm({
|
|
|
689
782
|
"src/collections/collections.ts"() {
|
|
690
783
|
"use strict";
|
|
691
784
|
init_collection();
|
|
785
|
+
init_errors();
|
|
692
786
|
CollectionsModule = class {
|
|
693
787
|
constructor(http, workspaceSlug) {
|
|
694
788
|
this.http = http;
|
|
@@ -706,19 +800,63 @@ var init_collections = __esm({
|
|
|
706
800
|
}
|
|
707
801
|
/**
|
|
708
802
|
* Get a single collection by slug
|
|
803
|
+
* Returns null if collection is not found (404)
|
|
709
804
|
*/
|
|
710
805
|
async get(slug) {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
806
|
+
try {
|
|
807
|
+
const endpoint = `/api/publish/${this.workspaceSlug}/collections/${slug}`;
|
|
808
|
+
const data = await this.http.fetch(endpoint);
|
|
809
|
+
return new Collection(data, this.http, this.workspaceSlug);
|
|
810
|
+
} catch (error) {
|
|
811
|
+
if (error instanceof MarvinNotFoundError) {
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
throw error;
|
|
815
|
+
}
|
|
714
816
|
}
|
|
715
817
|
/**
|
|
716
818
|
* Get entries in a collection
|
|
819
|
+
* Returns empty array if collection is not found
|
|
717
820
|
*/
|
|
718
821
|
async entries(slug) {
|
|
719
822
|
const collection = await this.get(slug);
|
|
823
|
+
if (!collection) {
|
|
824
|
+
return [];
|
|
825
|
+
}
|
|
720
826
|
return collection.entries();
|
|
721
827
|
}
|
|
828
|
+
/**
|
|
829
|
+
* Try multiple collection slugs in fallback order
|
|
830
|
+
* Returns the first collection that exists and has entries
|
|
831
|
+
*
|
|
832
|
+
* @param slugs - Collection slugs to try in order
|
|
833
|
+
* @param options - Options for fallback behavior
|
|
834
|
+
* @returns Entries from the first matching collection, or empty array
|
|
835
|
+
*
|
|
836
|
+
* @example
|
|
837
|
+
* ```ts
|
|
838
|
+
* // Try bench-notes, then journal, then blog
|
|
839
|
+
* const entries = await collections.fallback(['bench-notes', 'journal', 'blog']);
|
|
840
|
+
* ```
|
|
841
|
+
*/
|
|
842
|
+
async fallback(slugs, options = {}) {
|
|
843
|
+
const { requireEntries = true } = options;
|
|
844
|
+
for (const slug of slugs) {
|
|
845
|
+
try {
|
|
846
|
+
const collection = await this.get(slug);
|
|
847
|
+
if (!collection) {
|
|
848
|
+
continue;
|
|
849
|
+
}
|
|
850
|
+
const entries = await collection.entries();
|
|
851
|
+
if (!requireEntries || entries.length > 0) {
|
|
852
|
+
return entries;
|
|
853
|
+
}
|
|
854
|
+
} catch (error) {
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return [];
|
|
859
|
+
}
|
|
722
860
|
};
|
|
723
861
|
}
|
|
724
862
|
});
|
|
@@ -1081,6 +1219,23 @@ var init_marvin = __esm({
|
|
|
1081
1219
|
async resource(slug) {
|
|
1082
1220
|
return this.workspace.resources.get(slug);
|
|
1083
1221
|
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Try multiple collection slugs in fallback order
|
|
1224
|
+
* Returns entries from the first collection that exists and has content
|
|
1225
|
+
*
|
|
1226
|
+
* @param slugs - Collection slugs to try in order
|
|
1227
|
+
* @param options - Options for fallback behavior
|
|
1228
|
+
* @returns Entries from the first matching collection, or empty array
|
|
1229
|
+
*
|
|
1230
|
+
* @example
|
|
1231
|
+
* ```ts
|
|
1232
|
+
* // Try bench-notes, then journal, then blog
|
|
1233
|
+
* const entries = await client.collectionFallback(['bench-notes', 'journal', 'blog']);
|
|
1234
|
+
* ```
|
|
1235
|
+
*/
|
|
1236
|
+
async collectionFallback(slugs, options) {
|
|
1237
|
+
return this.workspace.collections.fallback(slugs, options);
|
|
1238
|
+
}
|
|
1084
1239
|
// ======================
|
|
1085
1240
|
// Backwards-Compatible Publishing API
|
|
1086
1241
|
// ======================
|
|
@@ -1104,6 +1259,9 @@ var init_marvin = __esm({
|
|
|
1104
1259
|
*/
|
|
1105
1260
|
async getEntry(slug) {
|
|
1106
1261
|
const entry = await this.workspace.entries.get(slug);
|
|
1262
|
+
if (!entry) {
|
|
1263
|
+
return null;
|
|
1264
|
+
}
|
|
1107
1265
|
return entry.toJSON();
|
|
1108
1266
|
}
|
|
1109
1267
|
/**
|
|
@@ -1119,6 +1277,9 @@ var init_marvin = __esm({
|
|
|
1119
1277
|
*/
|
|
1120
1278
|
async getCollection(slug) {
|
|
1121
1279
|
const collection = await this.workspace.collections.get(slug);
|
|
1280
|
+
if (!collection) {
|
|
1281
|
+
return null;
|
|
1282
|
+
}
|
|
1122
1283
|
return collection.toJSON();
|
|
1123
1284
|
}
|
|
1124
1285
|
/**
|
|
@@ -1175,6 +1336,9 @@ __export(index_exports, {
|
|
|
1175
1336
|
MarvinClient: () => MarvinClient,
|
|
1176
1337
|
MarvinConfigError: () => MarvinConfigError,
|
|
1177
1338
|
MarvinError: () => MarvinError,
|
|
1339
|
+
MarvinNetworkError: () => MarvinNetworkError,
|
|
1340
|
+
MarvinNotFoundError: () => MarvinNotFoundError,
|
|
1341
|
+
MarvinServerError: () => MarvinServerError,
|
|
1178
1342
|
MarvinValidationError: () => MarvinValidationError,
|
|
1179
1343
|
NoAuth: () => NoAuth,
|
|
1180
1344
|
Resource: () => Resource,
|
|
@@ -1271,6 +1435,9 @@ function createMarvinClient(config) {
|
|
|
1271
1435
|
MarvinClient,
|
|
1272
1436
|
MarvinConfigError,
|
|
1273
1437
|
MarvinError,
|
|
1438
|
+
MarvinNetworkError,
|
|
1439
|
+
MarvinNotFoundError,
|
|
1440
|
+
MarvinServerError,
|
|
1274
1441
|
MarvinValidationError,
|
|
1275
1442
|
NoAuth,
|
|
1276
1443
|
Resource,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MarvinResource, MarvinEntry, MarvinAsset, MarvinCollection, MarvinEntryType, MarvinSite, GetResourcesOptions as GetResourcesOptions$1 } from './types/index.cjs';
|
|
2
2
|
export { GetAssetsOptions, GetEntriesOptions, MarvinPublishResponse } from './types/index.cjs';
|
|
3
|
-
import { H as HttpClient } from './HttpClient-
|
|
4
|
-
export { A as AuthStrategy, B as BearerTokenAuth, a as HttpClientConfig, N as NoAuth, S as SessionAuth } from './HttpClient-
|
|
3
|
+
import { H as HttpClient } from './HttpClient-BX5Gqd0w.cjs';
|
|
4
|
+
export { A as AuthStrategy, B as BearerTokenAuth, a as HttpClientConfig, N as NoAuth, S as SessionAuth } from './HttpClient-BX5Gqd0w.cjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Marvin SDK Configuration
|
|
@@ -14,6 +14,14 @@ interface MarvinConfig {
|
|
|
14
14
|
autoInitialize?: boolean;
|
|
15
15
|
/** Cache duration in milliseconds (default: 5 minutes) */
|
|
16
16
|
cacheDuration?: number;
|
|
17
|
+
/** Enable debug logging for HTTP requests and responses */
|
|
18
|
+
debug?: boolean;
|
|
19
|
+
/** Custom logger function (defaults to console) */
|
|
20
|
+
logger?: {
|
|
21
|
+
log: (message: string, ...args: unknown[]) => void;
|
|
22
|
+
warn: (message: string, ...args: unknown[]) => void;
|
|
23
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
24
|
+
};
|
|
17
25
|
}
|
|
18
26
|
declare function createConfigFromEnv(overrides?: Partial<MarvinConfig>): MarvinConfig;
|
|
19
27
|
|
|
@@ -54,6 +62,27 @@ declare class MarvinValidationError extends MarvinError {
|
|
|
54
62
|
readonly field?: string | undefined;
|
|
55
63
|
constructor(message: string, field?: string | undefined);
|
|
56
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Resource not found errors (404)
|
|
67
|
+
*/
|
|
68
|
+
declare class MarvinNotFoundError extends MarvinError {
|
|
69
|
+
readonly endpoint: string;
|
|
70
|
+
constructor(message: string, endpoint: string);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Network/connectivity errors
|
|
74
|
+
*/
|
|
75
|
+
declare class MarvinNetworkError extends MarvinError {
|
|
76
|
+
readonly originalError?: Error | undefined;
|
|
77
|
+
constructor(message: string, originalError?: Error | undefined);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Server errors (5xx)
|
|
81
|
+
*/
|
|
82
|
+
declare class MarvinServerError extends MarvinError {
|
|
83
|
+
readonly endpoint: string;
|
|
84
|
+
constructor(message: string, statusCode: number, endpoint: string);
|
|
85
|
+
}
|
|
57
86
|
|
|
58
87
|
/**
|
|
59
88
|
* Pagination response types and helpers
|
|
@@ -270,12 +299,31 @@ declare class CollectionsModule {
|
|
|
270
299
|
list(): Promise<MarvinCollection[]>;
|
|
271
300
|
/**
|
|
272
301
|
* Get a single collection by slug
|
|
302
|
+
* Returns null if collection is not found (404)
|
|
273
303
|
*/
|
|
274
|
-
get(slug: string): Promise<Collection>;
|
|
304
|
+
get(slug: string): Promise<Collection | null>;
|
|
275
305
|
/**
|
|
276
306
|
* Get entries in a collection
|
|
307
|
+
* Returns empty array if collection is not found
|
|
277
308
|
*/
|
|
278
309
|
entries(slug: string): Promise<MarvinEntry[]>;
|
|
310
|
+
/**
|
|
311
|
+
* Try multiple collection slugs in fallback order
|
|
312
|
+
* Returns the first collection that exists and has entries
|
|
313
|
+
*
|
|
314
|
+
* @param slugs - Collection slugs to try in order
|
|
315
|
+
* @param options - Options for fallback behavior
|
|
316
|
+
* @returns Entries from the first matching collection, or empty array
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* ```ts
|
|
320
|
+
* // Try bench-notes, then journal, then blog
|
|
321
|
+
* const entries = await collections.fallback(['bench-notes', 'journal', 'blog']);
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
fallback(slugs: string[], options?: {
|
|
325
|
+
requireEntries?: boolean;
|
|
326
|
+
}): Promise<MarvinEntry[]>;
|
|
279
327
|
}
|
|
280
328
|
|
|
281
329
|
declare class Entry {
|
|
@@ -365,8 +413,9 @@ declare class EntriesModule {
|
|
|
365
413
|
list(options?: GetEntriesOptions): Promise<MarvinEntry[]>;
|
|
366
414
|
/**
|
|
367
415
|
* Get a single entry by slug
|
|
416
|
+
* Returns null if entry is not found (404)
|
|
368
417
|
*/
|
|
369
|
-
get(slug: string): Promise<Entry>;
|
|
418
|
+
get(slug: string): Promise<Entry | null>;
|
|
370
419
|
/**
|
|
371
420
|
* Convenience: Get all pages
|
|
372
421
|
*/
|
|
@@ -465,11 +514,11 @@ declare class MarvinClient {
|
|
|
465
514
|
/**
|
|
466
515
|
* Get a single entry by slug
|
|
467
516
|
*/
|
|
468
|
-
entry(slug: string): Promise<Entry>;
|
|
517
|
+
entry(slug: string): Promise<Entry | null>;
|
|
469
518
|
/**
|
|
470
519
|
* Get a single collection by slug
|
|
471
520
|
*/
|
|
472
|
-
collection(slug: string): Promise<Collection>;
|
|
521
|
+
collection(slug: string): Promise<Collection | null>;
|
|
473
522
|
/**
|
|
474
523
|
* Get all pages
|
|
475
524
|
*/
|
|
@@ -486,6 +535,23 @@ declare class MarvinClient {
|
|
|
486
535
|
* Get a single resource by slug
|
|
487
536
|
*/
|
|
488
537
|
resource(slug: string): Promise<Resource>;
|
|
538
|
+
/**
|
|
539
|
+
* Try multiple collection slugs in fallback order
|
|
540
|
+
* Returns entries from the first collection that exists and has content
|
|
541
|
+
*
|
|
542
|
+
* @param slugs - Collection slugs to try in order
|
|
543
|
+
* @param options - Options for fallback behavior
|
|
544
|
+
* @returns Entries from the first matching collection, or empty array
|
|
545
|
+
*
|
|
546
|
+
* @example
|
|
547
|
+
* ```ts
|
|
548
|
+
* // Try bench-notes, then journal, then blog
|
|
549
|
+
* const entries = await client.collectionFallback(['bench-notes', 'journal', 'blog']);
|
|
550
|
+
* ```
|
|
551
|
+
*/
|
|
552
|
+
collectionFallback(slugs: string[], options?: {
|
|
553
|
+
requireEntries?: boolean;
|
|
554
|
+
}): Promise<MarvinEntry[]>;
|
|
489
555
|
/**
|
|
490
556
|
* @deprecated Use workspace.site or marvin.site instead
|
|
491
557
|
* Get site configuration
|
|
@@ -500,7 +566,7 @@ declare class MarvinClient {
|
|
|
500
566
|
* @deprecated Use workspace.entries.get() instead
|
|
501
567
|
* Get a single published entry by slug
|
|
502
568
|
*/
|
|
503
|
-
getEntry(slug: string): Promise<MarvinEntry>;
|
|
569
|
+
getEntry(slug: string): Promise<MarvinEntry | null>;
|
|
504
570
|
/**
|
|
505
571
|
* @deprecated Use workspace.collections.list() instead
|
|
506
572
|
* Get all collections
|
|
@@ -510,7 +576,7 @@ declare class MarvinClient {
|
|
|
510
576
|
* @deprecated Use workspace.collections.get() instead
|
|
511
577
|
* Get a single collection by slug
|
|
512
578
|
*/
|
|
513
|
-
getCollection(slug: string): Promise<MarvinCollection>;
|
|
579
|
+
getCollection(slug: string): Promise<MarvinCollection | null>;
|
|
514
580
|
/**
|
|
515
581
|
* @deprecated Use workspace.collections.entries() instead
|
|
516
582
|
* Get all entries in a collection
|
|
@@ -621,4 +687,4 @@ declare function createAuthClient(apiUrl: string): AuthClient;
|
|
|
621
687
|
*/
|
|
622
688
|
declare function createMarvinClient(config?: Partial<MarvinConfig>): MarvinClient;
|
|
623
689
|
|
|
624
|
-
export { AuthClient, type AuthToken, Collection, Entry, type ForgotPasswordRequest, GetResourcesOptions$1 as GetResourcesOptions, HttpClient, type LoginRequest, MarvinApiError, MarvinAsset, MarvinAuthError, MarvinCache, MarvinClient, MarvinCollection, type MarvinConfig, MarvinConfigError, MarvinEntry, MarvinEntryType, MarvinError, MarvinResource, MarvinSite, MarvinValidationError, type PaginatedResponse, type PaginationMeta, type PaginationParams, type ResetPasswordRequest, Resource, type UserRegistration, Workspace, createAuthClient, createConfigFromEnv, createMarvinClient, createPaginatedResponse, extractData, isPaginatedResponse, offsetToPage, pageToOffset };
|
|
690
|
+
export { AuthClient, type AuthToken, Collection, Entry, type ForgotPasswordRequest, GetResourcesOptions$1 as GetResourcesOptions, HttpClient, type LoginRequest, MarvinApiError, MarvinAsset, MarvinAuthError, MarvinCache, MarvinClient, MarvinCollection, type MarvinConfig, MarvinConfigError, MarvinEntry, MarvinEntryType, MarvinError, MarvinNetworkError, MarvinNotFoundError, MarvinResource, MarvinServerError, MarvinSite, MarvinValidationError, type PaginatedResponse, type PaginationMeta, type PaginationParams, type ResetPasswordRequest, Resource, type UserRegistration, Workspace, createAuthClient, createConfigFromEnv, createMarvinClient, createPaginatedResponse, extractData, isPaginatedResponse, offsetToPage, pageToOffset };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MarvinResource, MarvinEntry, MarvinAsset, MarvinCollection, MarvinEntryType, MarvinSite, GetResourcesOptions as GetResourcesOptions$1 } from './types/index.js';
|
|
2
2
|
export { GetAssetsOptions, GetEntriesOptions, MarvinPublishResponse } from './types/index.js';
|
|
3
|
-
import { H as HttpClient } from './HttpClient-
|
|
4
|
-
export { A as AuthStrategy, B as BearerTokenAuth, a as HttpClientConfig, N as NoAuth, S as SessionAuth } from './HttpClient-
|
|
3
|
+
import { H as HttpClient } from './HttpClient-BX5Gqd0w.js';
|
|
4
|
+
export { A as AuthStrategy, B as BearerTokenAuth, a as HttpClientConfig, N as NoAuth, S as SessionAuth } from './HttpClient-BX5Gqd0w.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Marvin SDK Configuration
|
|
@@ -14,6 +14,14 @@ interface MarvinConfig {
|
|
|
14
14
|
autoInitialize?: boolean;
|
|
15
15
|
/** Cache duration in milliseconds (default: 5 minutes) */
|
|
16
16
|
cacheDuration?: number;
|
|
17
|
+
/** Enable debug logging for HTTP requests and responses */
|
|
18
|
+
debug?: boolean;
|
|
19
|
+
/** Custom logger function (defaults to console) */
|
|
20
|
+
logger?: {
|
|
21
|
+
log: (message: string, ...args: unknown[]) => void;
|
|
22
|
+
warn: (message: string, ...args: unknown[]) => void;
|
|
23
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
24
|
+
};
|
|
17
25
|
}
|
|
18
26
|
declare function createConfigFromEnv(overrides?: Partial<MarvinConfig>): MarvinConfig;
|
|
19
27
|
|
|
@@ -54,6 +62,27 @@ declare class MarvinValidationError extends MarvinError {
|
|
|
54
62
|
readonly field?: string | undefined;
|
|
55
63
|
constructor(message: string, field?: string | undefined);
|
|
56
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Resource not found errors (404)
|
|
67
|
+
*/
|
|
68
|
+
declare class MarvinNotFoundError extends MarvinError {
|
|
69
|
+
readonly endpoint: string;
|
|
70
|
+
constructor(message: string, endpoint: string);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Network/connectivity errors
|
|
74
|
+
*/
|
|
75
|
+
declare class MarvinNetworkError extends MarvinError {
|
|
76
|
+
readonly originalError?: Error | undefined;
|
|
77
|
+
constructor(message: string, originalError?: Error | undefined);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Server errors (5xx)
|
|
81
|
+
*/
|
|
82
|
+
declare class MarvinServerError extends MarvinError {
|
|
83
|
+
readonly endpoint: string;
|
|
84
|
+
constructor(message: string, statusCode: number, endpoint: string);
|
|
85
|
+
}
|
|
57
86
|
|
|
58
87
|
/**
|
|
59
88
|
* Pagination response types and helpers
|
|
@@ -270,12 +299,31 @@ declare class CollectionsModule {
|
|
|
270
299
|
list(): Promise<MarvinCollection[]>;
|
|
271
300
|
/**
|
|
272
301
|
* Get a single collection by slug
|
|
302
|
+
* Returns null if collection is not found (404)
|
|
273
303
|
*/
|
|
274
|
-
get(slug: string): Promise<Collection>;
|
|
304
|
+
get(slug: string): Promise<Collection | null>;
|
|
275
305
|
/**
|
|
276
306
|
* Get entries in a collection
|
|
307
|
+
* Returns empty array if collection is not found
|
|
277
308
|
*/
|
|
278
309
|
entries(slug: string): Promise<MarvinEntry[]>;
|
|
310
|
+
/**
|
|
311
|
+
* Try multiple collection slugs in fallback order
|
|
312
|
+
* Returns the first collection that exists and has entries
|
|
313
|
+
*
|
|
314
|
+
* @param slugs - Collection slugs to try in order
|
|
315
|
+
* @param options - Options for fallback behavior
|
|
316
|
+
* @returns Entries from the first matching collection, or empty array
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* ```ts
|
|
320
|
+
* // Try bench-notes, then journal, then blog
|
|
321
|
+
* const entries = await collections.fallback(['bench-notes', 'journal', 'blog']);
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
fallback(slugs: string[], options?: {
|
|
325
|
+
requireEntries?: boolean;
|
|
326
|
+
}): Promise<MarvinEntry[]>;
|
|
279
327
|
}
|
|
280
328
|
|
|
281
329
|
declare class Entry {
|
|
@@ -365,8 +413,9 @@ declare class EntriesModule {
|
|
|
365
413
|
list(options?: GetEntriesOptions): Promise<MarvinEntry[]>;
|
|
366
414
|
/**
|
|
367
415
|
* Get a single entry by slug
|
|
416
|
+
* Returns null if entry is not found (404)
|
|
368
417
|
*/
|
|
369
|
-
get(slug: string): Promise<Entry>;
|
|
418
|
+
get(slug: string): Promise<Entry | null>;
|
|
370
419
|
/**
|
|
371
420
|
* Convenience: Get all pages
|
|
372
421
|
*/
|
|
@@ -465,11 +514,11 @@ declare class MarvinClient {
|
|
|
465
514
|
/**
|
|
466
515
|
* Get a single entry by slug
|
|
467
516
|
*/
|
|
468
|
-
entry(slug: string): Promise<Entry>;
|
|
517
|
+
entry(slug: string): Promise<Entry | null>;
|
|
469
518
|
/**
|
|
470
519
|
* Get a single collection by slug
|
|
471
520
|
*/
|
|
472
|
-
collection(slug: string): Promise<Collection>;
|
|
521
|
+
collection(slug: string): Promise<Collection | null>;
|
|
473
522
|
/**
|
|
474
523
|
* Get all pages
|
|
475
524
|
*/
|
|
@@ -486,6 +535,23 @@ declare class MarvinClient {
|
|
|
486
535
|
* Get a single resource by slug
|
|
487
536
|
*/
|
|
488
537
|
resource(slug: string): Promise<Resource>;
|
|
538
|
+
/**
|
|
539
|
+
* Try multiple collection slugs in fallback order
|
|
540
|
+
* Returns entries from the first collection that exists and has content
|
|
541
|
+
*
|
|
542
|
+
* @param slugs - Collection slugs to try in order
|
|
543
|
+
* @param options - Options for fallback behavior
|
|
544
|
+
* @returns Entries from the first matching collection, or empty array
|
|
545
|
+
*
|
|
546
|
+
* @example
|
|
547
|
+
* ```ts
|
|
548
|
+
* // Try bench-notes, then journal, then blog
|
|
549
|
+
* const entries = await client.collectionFallback(['bench-notes', 'journal', 'blog']);
|
|
550
|
+
* ```
|
|
551
|
+
*/
|
|
552
|
+
collectionFallback(slugs: string[], options?: {
|
|
553
|
+
requireEntries?: boolean;
|
|
554
|
+
}): Promise<MarvinEntry[]>;
|
|
489
555
|
/**
|
|
490
556
|
* @deprecated Use workspace.site or marvin.site instead
|
|
491
557
|
* Get site configuration
|
|
@@ -500,7 +566,7 @@ declare class MarvinClient {
|
|
|
500
566
|
* @deprecated Use workspace.entries.get() instead
|
|
501
567
|
* Get a single published entry by slug
|
|
502
568
|
*/
|
|
503
|
-
getEntry(slug: string): Promise<MarvinEntry>;
|
|
569
|
+
getEntry(slug: string): Promise<MarvinEntry | null>;
|
|
504
570
|
/**
|
|
505
571
|
* @deprecated Use workspace.collections.list() instead
|
|
506
572
|
* Get all collections
|
|
@@ -510,7 +576,7 @@ declare class MarvinClient {
|
|
|
510
576
|
* @deprecated Use workspace.collections.get() instead
|
|
511
577
|
* Get a single collection by slug
|
|
512
578
|
*/
|
|
513
|
-
getCollection(slug: string): Promise<MarvinCollection>;
|
|
579
|
+
getCollection(slug: string): Promise<MarvinCollection | null>;
|
|
514
580
|
/**
|
|
515
581
|
* @deprecated Use workspace.collections.entries() instead
|
|
516
582
|
* Get all entries in a collection
|
|
@@ -621,4 +687,4 @@ declare function createAuthClient(apiUrl: string): AuthClient;
|
|
|
621
687
|
*/
|
|
622
688
|
declare function createMarvinClient(config?: Partial<MarvinConfig>): MarvinClient;
|
|
623
689
|
|
|
624
|
-
export { AuthClient, type AuthToken, Collection, Entry, type ForgotPasswordRequest, GetResourcesOptions$1 as GetResourcesOptions, HttpClient, type LoginRequest, MarvinApiError, MarvinAsset, MarvinAuthError, MarvinCache, MarvinClient, MarvinCollection, type MarvinConfig, MarvinConfigError, MarvinEntry, MarvinEntryType, MarvinError, MarvinResource, MarvinSite, MarvinValidationError, type PaginatedResponse, type PaginationMeta, type PaginationParams, type ResetPasswordRequest, Resource, type UserRegistration, Workspace, createAuthClient, createConfigFromEnv, createMarvinClient, createPaginatedResponse, extractData, isPaginatedResponse, offsetToPage, pageToOffset };
|
|
690
|
+
export { AuthClient, type AuthToken, Collection, Entry, type ForgotPasswordRequest, GetResourcesOptions$1 as GetResourcesOptions, HttpClient, type LoginRequest, MarvinApiError, MarvinAsset, MarvinAuthError, MarvinCache, MarvinClient, MarvinCollection, type MarvinConfig, MarvinConfigError, MarvinEntry, MarvinEntryType, MarvinError, MarvinNetworkError, MarvinNotFoundError, MarvinResource, MarvinServerError, MarvinSite, MarvinValidationError, type PaginatedResponse, type PaginationMeta, type PaginationParams, type ResetPasswordRequest, Resource, type UserRegistration, Workspace, createAuthClient, createConfigFromEnv, createMarvinClient, createPaginatedResponse, extractData, isPaginatedResponse, offsetToPage, pageToOffset };
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,9 @@ import {
|
|
|
6
6
|
MarvinCache,
|
|
7
7
|
MarvinConfigError,
|
|
8
8
|
MarvinError,
|
|
9
|
+
MarvinNetworkError,
|
|
10
|
+
MarvinNotFoundError,
|
|
11
|
+
MarvinServerError,
|
|
9
12
|
MarvinValidationError,
|
|
10
13
|
NoAuth,
|
|
11
14
|
SessionAuth,
|
|
@@ -15,10 +18,11 @@ import {
|
|
|
15
18
|
createPaginatedResponse,
|
|
16
19
|
extractData,
|
|
17
20
|
init_core,
|
|
21
|
+
init_errors,
|
|
18
22
|
isPaginatedResponse,
|
|
19
23
|
offsetToPage,
|
|
20
24
|
pageToOffset
|
|
21
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-DYC2BEA4.js";
|
|
22
26
|
|
|
23
27
|
// src/client/config.ts
|
|
24
28
|
var config_exports = {};
|
|
@@ -27,14 +31,21 @@ __export(config_exports, {
|
|
|
27
31
|
validateConfig: () => validateConfig
|
|
28
32
|
});
|
|
29
33
|
function validateConfig(config) {
|
|
34
|
+
const receivedKeys = Object.keys(config).join(", ");
|
|
30
35
|
if (!config.apiUrl) {
|
|
31
|
-
throw new Error(
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Missing required config parameter 'apiUrl'. Received config keys: ${receivedKeys || "(none)"}. Set this to your MARVIN_API_URL environment variable value.`
|
|
38
|
+
);
|
|
32
39
|
}
|
|
33
40
|
if (!config.siteClientToken) {
|
|
34
|
-
throw new Error(
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Missing required config parameter 'siteClientToken'. Received config keys: ${receivedKeys}. Set this to your MARVIN_SITE_CLIENT_TOKEN environment variable value.`
|
|
43
|
+
);
|
|
35
44
|
}
|
|
36
45
|
if (!config.workspaceSlug) {
|
|
37
|
-
throw new Error(
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Missing required config parameter 'workspaceSlug'. Received config keys: ${receivedKeys}. Set this to your MARVIN_WORKSPACE_SLUG environment variable value.`
|
|
48
|
+
);
|
|
38
49
|
}
|
|
39
50
|
}
|
|
40
51
|
function createConfigFromEnv(overrides) {
|
|
@@ -43,8 +54,10 @@ function createConfigFromEnv(overrides) {
|
|
|
43
54
|
siteClientToken: overrides?.siteClientToken || process.env.MARVIN_SITE_CLIENT_TOKEN || "",
|
|
44
55
|
workspaceSlug: overrides?.workspaceSlug || process.env.MARVIN_WORKSPACE_SLUG || "",
|
|
45
56
|
autoInitialize: overrides?.autoInitialize ?? false,
|
|
46
|
-
cacheDuration: overrides?.cacheDuration ?? 5 * 60 * 1e3
|
|
57
|
+
cacheDuration: overrides?.cacheDuration ?? 5 * 60 * 1e3,
|
|
47
58
|
// 5 minutes
|
|
59
|
+
debug: overrides?.debug ?? process.env.MARVIN_DEBUG === "true",
|
|
60
|
+
logger: overrides?.logger ?? console
|
|
48
61
|
};
|
|
49
62
|
}
|
|
50
63
|
var init_config = __esm({
|
|
@@ -64,7 +77,9 @@ var init_http = __esm({
|
|
|
64
77
|
super({
|
|
65
78
|
baseUrl: config.apiUrl,
|
|
66
79
|
auth: new BearerTokenAuth(config.siteClientToken),
|
|
67
|
-
credentials: "same-origin"
|
|
80
|
+
credentials: "same-origin",
|
|
81
|
+
debug: config.debug,
|
|
82
|
+
logger: config.logger
|
|
68
83
|
});
|
|
69
84
|
}
|
|
70
85
|
/**
|
|
@@ -201,6 +216,7 @@ var init_entries = __esm({
|
|
|
201
216
|
"src/entries/entries.ts"() {
|
|
202
217
|
"use strict";
|
|
203
218
|
init_entry();
|
|
219
|
+
init_errors();
|
|
204
220
|
EntriesModule = class {
|
|
205
221
|
constructor(http, workspaceSlug) {
|
|
206
222
|
this.http = http;
|
|
@@ -225,11 +241,19 @@ var init_entries = __esm({
|
|
|
225
241
|
}
|
|
226
242
|
/**
|
|
227
243
|
* Get a single entry by slug
|
|
244
|
+
* Returns null if entry is not found (404)
|
|
228
245
|
*/
|
|
229
246
|
async get(slug) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
247
|
+
try {
|
|
248
|
+
const endpoint = `/api/publish/${this.workspaceSlug}/entries/${slug}`;
|
|
249
|
+
const data = await this.http.fetch(endpoint);
|
|
250
|
+
return new Entry(data, this.http, this.workspaceSlug);
|
|
251
|
+
} catch (error) {
|
|
252
|
+
if (error instanceof MarvinNotFoundError) {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
233
257
|
}
|
|
234
258
|
/**
|
|
235
259
|
* Convenience: Get all pages
|
|
@@ -335,6 +359,7 @@ var init_collections = __esm({
|
|
|
335
359
|
"src/collections/collections.ts"() {
|
|
336
360
|
"use strict";
|
|
337
361
|
init_collection();
|
|
362
|
+
init_errors();
|
|
338
363
|
CollectionsModule = class {
|
|
339
364
|
constructor(http, workspaceSlug) {
|
|
340
365
|
this.http = http;
|
|
@@ -352,19 +377,63 @@ var init_collections = __esm({
|
|
|
352
377
|
}
|
|
353
378
|
/**
|
|
354
379
|
* Get a single collection by slug
|
|
380
|
+
* Returns null if collection is not found (404)
|
|
355
381
|
*/
|
|
356
382
|
async get(slug) {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
383
|
+
try {
|
|
384
|
+
const endpoint = `/api/publish/${this.workspaceSlug}/collections/${slug}`;
|
|
385
|
+
const data = await this.http.fetch(endpoint);
|
|
386
|
+
return new Collection(data, this.http, this.workspaceSlug);
|
|
387
|
+
} catch (error) {
|
|
388
|
+
if (error instanceof MarvinNotFoundError) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
throw error;
|
|
392
|
+
}
|
|
360
393
|
}
|
|
361
394
|
/**
|
|
362
395
|
* Get entries in a collection
|
|
396
|
+
* Returns empty array if collection is not found
|
|
363
397
|
*/
|
|
364
398
|
async entries(slug) {
|
|
365
399
|
const collection = await this.get(slug);
|
|
400
|
+
if (!collection) {
|
|
401
|
+
return [];
|
|
402
|
+
}
|
|
366
403
|
return collection.entries();
|
|
367
404
|
}
|
|
405
|
+
/**
|
|
406
|
+
* Try multiple collection slugs in fallback order
|
|
407
|
+
* Returns the first collection that exists and has entries
|
|
408
|
+
*
|
|
409
|
+
* @param slugs - Collection slugs to try in order
|
|
410
|
+
* @param options - Options for fallback behavior
|
|
411
|
+
* @returns Entries from the first matching collection, or empty array
|
|
412
|
+
*
|
|
413
|
+
* @example
|
|
414
|
+
* ```ts
|
|
415
|
+
* // Try bench-notes, then journal, then blog
|
|
416
|
+
* const entries = await collections.fallback(['bench-notes', 'journal', 'blog']);
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
419
|
+
async fallback(slugs, options = {}) {
|
|
420
|
+
const { requireEntries = true } = options;
|
|
421
|
+
for (const slug of slugs) {
|
|
422
|
+
try {
|
|
423
|
+
const collection = await this.get(slug);
|
|
424
|
+
if (!collection) {
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
const entries = await collection.entries();
|
|
428
|
+
if (!requireEntries || entries.length > 0) {
|
|
429
|
+
return entries;
|
|
430
|
+
}
|
|
431
|
+
} catch (error) {
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return [];
|
|
436
|
+
}
|
|
368
437
|
};
|
|
369
438
|
}
|
|
370
439
|
});
|
|
@@ -727,6 +796,23 @@ var init_marvin = __esm({
|
|
|
727
796
|
async resource(slug) {
|
|
728
797
|
return this.workspace.resources.get(slug);
|
|
729
798
|
}
|
|
799
|
+
/**
|
|
800
|
+
* Try multiple collection slugs in fallback order
|
|
801
|
+
* Returns entries from the first collection that exists and has content
|
|
802
|
+
*
|
|
803
|
+
* @param slugs - Collection slugs to try in order
|
|
804
|
+
* @param options - Options for fallback behavior
|
|
805
|
+
* @returns Entries from the first matching collection, or empty array
|
|
806
|
+
*
|
|
807
|
+
* @example
|
|
808
|
+
* ```ts
|
|
809
|
+
* // Try bench-notes, then journal, then blog
|
|
810
|
+
* const entries = await client.collectionFallback(['bench-notes', 'journal', 'blog']);
|
|
811
|
+
* ```
|
|
812
|
+
*/
|
|
813
|
+
async collectionFallback(slugs, options) {
|
|
814
|
+
return this.workspace.collections.fallback(slugs, options);
|
|
815
|
+
}
|
|
730
816
|
// ======================
|
|
731
817
|
// Backwards-Compatible Publishing API
|
|
732
818
|
// ======================
|
|
@@ -750,6 +836,9 @@ var init_marvin = __esm({
|
|
|
750
836
|
*/
|
|
751
837
|
async getEntry(slug) {
|
|
752
838
|
const entry = await this.workspace.entries.get(slug);
|
|
839
|
+
if (!entry) {
|
|
840
|
+
return null;
|
|
841
|
+
}
|
|
753
842
|
return entry.toJSON();
|
|
754
843
|
}
|
|
755
844
|
/**
|
|
@@ -765,6 +854,9 @@ var init_marvin = __esm({
|
|
|
765
854
|
*/
|
|
766
855
|
async getCollection(slug) {
|
|
767
856
|
const collection = await this.workspace.collections.get(slug);
|
|
857
|
+
if (!collection) {
|
|
858
|
+
return null;
|
|
859
|
+
}
|
|
768
860
|
return collection.toJSON();
|
|
769
861
|
}
|
|
770
862
|
/**
|
|
@@ -888,6 +980,9 @@ export {
|
|
|
888
980
|
MarvinClient,
|
|
889
981
|
MarvinConfigError,
|
|
890
982
|
MarvinError,
|
|
983
|
+
MarvinNetworkError,
|
|
984
|
+
MarvinNotFoundError,
|
|
985
|
+
MarvinServerError,
|
|
891
986
|
MarvinValidationError,
|
|
892
987
|
NoAuth,
|
|
893
988
|
Resource,
|
package/dist/platform.cjs
CHANGED
|
@@ -77,6 +77,40 @@ ${body}` : ""}`;
|
|
|
77
77
|
return new _MarvinApiError(message, status, endpoint, body);
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
|
+
var MarvinAuthError = class _MarvinAuthError extends MarvinError {
|
|
81
|
+
constructor(message, statusCode) {
|
|
82
|
+
super(message, "AUTH_ERROR", statusCode);
|
|
83
|
+
this.name = "MarvinAuthError";
|
|
84
|
+
Object.setPrototypeOf(this, _MarvinAuthError.prototype);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var MarvinNotFoundError = class _MarvinNotFoundError extends MarvinError {
|
|
88
|
+
constructor(message, endpoint) {
|
|
89
|
+
super(message, "NOT_FOUND", 404);
|
|
90
|
+
this.endpoint = endpoint;
|
|
91
|
+
this.name = "MarvinNotFoundError";
|
|
92
|
+
Object.setPrototypeOf(this, _MarvinNotFoundError.prototype);
|
|
93
|
+
}
|
|
94
|
+
endpoint;
|
|
95
|
+
};
|
|
96
|
+
var MarvinNetworkError = class _MarvinNetworkError extends MarvinError {
|
|
97
|
+
constructor(message, originalError) {
|
|
98
|
+
super(message, "NETWORK_ERROR");
|
|
99
|
+
this.originalError = originalError;
|
|
100
|
+
this.name = "MarvinNetworkError";
|
|
101
|
+
Object.setPrototypeOf(this, _MarvinNetworkError.prototype);
|
|
102
|
+
}
|
|
103
|
+
originalError;
|
|
104
|
+
};
|
|
105
|
+
var MarvinServerError = class _MarvinServerError extends MarvinError {
|
|
106
|
+
constructor(message, statusCode, endpoint) {
|
|
107
|
+
super(message, "SERVER_ERROR", statusCode);
|
|
108
|
+
this.endpoint = endpoint;
|
|
109
|
+
this.name = "MarvinServerError";
|
|
110
|
+
Object.setPrototypeOf(this, _MarvinServerError.prototype);
|
|
111
|
+
}
|
|
112
|
+
endpoint;
|
|
113
|
+
};
|
|
80
114
|
|
|
81
115
|
// src/core/http/HttpClient.ts
|
|
82
116
|
var HttpClient = class {
|
|
@@ -85,12 +119,16 @@ var HttpClient = class {
|
|
|
85
119
|
defaultHeaders;
|
|
86
120
|
credentials;
|
|
87
121
|
timeout;
|
|
122
|
+
debug;
|
|
123
|
+
logger;
|
|
88
124
|
constructor(config) {
|
|
89
125
|
this.baseUrl = config.baseUrl;
|
|
90
126
|
this.auth = config.auth;
|
|
91
127
|
this.defaultHeaders = config.defaultHeaders || {};
|
|
92
128
|
this.credentials = config.credentials || "same-origin";
|
|
93
129
|
this.timeout = config.timeout || 3e4;
|
|
130
|
+
this.debug = config.debug ?? false;
|
|
131
|
+
this.logger = config.logger ?? console;
|
|
94
132
|
}
|
|
95
133
|
/**
|
|
96
134
|
* Build full URL from endpoint
|
|
@@ -132,6 +170,10 @@ var HttpClient = class {
|
|
|
132
170
|
const headers = this.buildHeaders(options?.headers, isFormData);
|
|
133
171
|
const controller = new AbortController();
|
|
134
172
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
173
|
+
const startTime = Date.now();
|
|
174
|
+
if (this.debug) {
|
|
175
|
+
this.logger.log(`[Marvin] ${method} ${url}`);
|
|
176
|
+
}
|
|
135
177
|
try {
|
|
136
178
|
const response = await fetch(url, {
|
|
137
179
|
method,
|
|
@@ -141,11 +183,42 @@ var HttpClient = class {
|
|
|
141
183
|
signal: controller.signal
|
|
142
184
|
});
|
|
143
185
|
clearTimeout(timeoutId);
|
|
186
|
+
const duration = Date.now() - startTime;
|
|
187
|
+
if (this.debug) {
|
|
188
|
+
this.logger.log(
|
|
189
|
+
`[Marvin] ${response.status} ${response.statusText} (${duration}ms)`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
144
192
|
if (response.status === 401 && this.auth.handleUnauthorized) {
|
|
145
193
|
await this.auth.handleUnauthorized();
|
|
146
194
|
}
|
|
147
195
|
if (!response.ok) {
|
|
148
196
|
const errorText = await response.text().catch(() => "");
|
|
197
|
+
if (this.debug) {
|
|
198
|
+
this.logger.error(
|
|
199
|
+
`[Marvin] Error response: ${response.status} ${response.statusText}`,
|
|
200
|
+
errorText ? `Body: ${errorText}` : ""
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (response.status === 404) {
|
|
204
|
+
throw new MarvinNotFoundError(
|
|
205
|
+
`Resource not found: ${endpoint}`,
|
|
206
|
+
endpoint
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
if (response.status === 401 || response.status === 403) {
|
|
210
|
+
throw new MarvinAuthError(
|
|
211
|
+
`Authentication failed: ${response.statusText}`,
|
|
212
|
+
response.status
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
if (response.status >= 500) {
|
|
216
|
+
throw new MarvinServerError(
|
|
217
|
+
`Server error: ${response.status} ${response.statusText}`,
|
|
218
|
+
response.status,
|
|
219
|
+
endpoint
|
|
220
|
+
);
|
|
221
|
+
}
|
|
149
222
|
throw MarvinApiError.fromResponse(
|
|
150
223
|
response.status,
|
|
151
224
|
response.statusText,
|
|
@@ -157,21 +230,28 @@ var HttpClient = class {
|
|
|
157
230
|
if (!contentType || !contentType.includes("application/json")) {
|
|
158
231
|
return void 0;
|
|
159
232
|
}
|
|
160
|
-
|
|
233
|
+
const data = await response.json();
|
|
234
|
+
if (this.debug) {
|
|
235
|
+
const preview = typeof data === "object" && data !== null ? Array.isArray(data) ? `Array(${data.length})` : `Object with keys: ${Object.keys(data).join(", ")}` : String(data);
|
|
236
|
+
this.logger.log(`[Marvin] Response: ${preview}`);
|
|
237
|
+
}
|
|
238
|
+
return data;
|
|
161
239
|
} catch (error) {
|
|
162
240
|
clearTimeout(timeoutId);
|
|
163
|
-
if (error instanceof MarvinApiError) {
|
|
241
|
+
if (error instanceof MarvinApiError || error instanceof MarvinNotFoundError || error instanceof MarvinAuthError || error instanceof MarvinServerError) {
|
|
164
242
|
throw error;
|
|
165
243
|
}
|
|
166
244
|
if (error instanceof Error) {
|
|
167
245
|
if (error.name === "AbortError") {
|
|
168
|
-
throw new
|
|
246
|
+
throw new MarvinNetworkError(
|
|
169
247
|
`Request timeout after ${this.timeout}ms`,
|
|
170
|
-
|
|
171
|
-
endpoint
|
|
248
|
+
error
|
|
172
249
|
);
|
|
173
250
|
}
|
|
174
|
-
throw new
|
|
251
|
+
throw new MarvinNetworkError(
|
|
252
|
+
`Network error: ${error.message}`,
|
|
253
|
+
error
|
|
254
|
+
);
|
|
175
255
|
}
|
|
176
256
|
throw error;
|
|
177
257
|
}
|
package/dist/platform.d.cts
CHANGED
package/dist/platform.d.ts
CHANGED
package/dist/platform.js
CHANGED