@headroom-cms/api 0.1.4 → 0.1.5
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/astro.js +156 -0
- package/dist/index.cjs +158 -0
- package/dist/index.d.cts +74 -1
- package/dist/index.d.ts +74 -1
- package/dist/index.js +157 -0
- package/dist/next.cjs +68 -0
- package/dist/next.d.cts +11 -0
- package/dist/next.d.ts +11 -0
- package/dist/next.js +42 -0
- package/package.json +15 -5
package/dist/astro.js
CHANGED
|
@@ -1,5 +1,73 @@
|
|
|
1
1
|
// src/client.ts
|
|
2
2
|
import { createHmac } from "crypto";
|
|
3
|
+
|
|
4
|
+
// src/auth.ts
|
|
5
|
+
var HeadroomAuth = class {
|
|
6
|
+
/** @internal */
|
|
7
|
+
constructor(client) {
|
|
8
|
+
this.client = client;
|
|
9
|
+
}
|
|
10
|
+
/** Request an OTP code be sent to the email address */
|
|
11
|
+
async requestOTP(email) {
|
|
12
|
+
await this.client._fetchPost("/auth/otp/request", { email });
|
|
13
|
+
}
|
|
14
|
+
/** Verify OTP code and receive a long-lived session token */
|
|
15
|
+
async verifyOTP(email, code) {
|
|
16
|
+
return this.client._fetchPost("/auth/otp/verify", {
|
|
17
|
+
email,
|
|
18
|
+
code
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validate a session token and return the user.
|
|
23
|
+
* Automatically refreshes the token if it's past 75% of its lifetime,
|
|
24
|
+
* so callers can update their cookie with the new token if wasRefreshed is true.
|
|
25
|
+
*/
|
|
26
|
+
async getSession(token) {
|
|
27
|
+
const res = await this.client._fetchWithAuth(
|
|
28
|
+
"/auth/session",
|
|
29
|
+
token
|
|
30
|
+
);
|
|
31
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
32
|
+
const remaining = res.expiresAt - now;
|
|
33
|
+
const lifetime = res.expiresAt - res.issuedAt;
|
|
34
|
+
if (remaining < lifetime * 0.25) {
|
|
35
|
+
try {
|
|
36
|
+
const refreshed = await this.refreshSession(token);
|
|
37
|
+
return { ...refreshed, wasRefreshed: true };
|
|
38
|
+
} catch {
|
|
39
|
+
return {
|
|
40
|
+
user: res.user,
|
|
41
|
+
expiresAt: res.expiresAt,
|
|
42
|
+
token,
|
|
43
|
+
wasRefreshed: false
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
user: res.user,
|
|
49
|
+
expiresAt: res.expiresAt,
|
|
50
|
+
token,
|
|
51
|
+
wasRefreshed: false
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Refresh a session token for a new expiry period */
|
|
55
|
+
async refreshSession(token) {
|
|
56
|
+
const res = await this.client._fetchPostWithAuth(
|
|
57
|
+
"/auth/session/refresh",
|
|
58
|
+
token,
|
|
59
|
+
{}
|
|
60
|
+
);
|
|
61
|
+
return {
|
|
62
|
+
user: res.user,
|
|
63
|
+
expiresAt: res.expiresAt,
|
|
64
|
+
token: res.token,
|
|
65
|
+
wasRefreshed: true
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// src/client.ts
|
|
3
71
|
var HeadroomError = class extends Error {
|
|
4
72
|
status;
|
|
5
73
|
code;
|
|
@@ -12,11 +80,14 @@ var HeadroomError = class extends Error {
|
|
|
12
80
|
};
|
|
13
81
|
var HeadroomClient = class {
|
|
14
82
|
config;
|
|
83
|
+
/** Site user authentication methods */
|
|
84
|
+
auth;
|
|
15
85
|
constructor(config) {
|
|
16
86
|
this.config = {
|
|
17
87
|
...config,
|
|
18
88
|
url: config.url.replace(/\/+$/, "")
|
|
19
89
|
};
|
|
90
|
+
this.auth = new HeadroomAuth(this);
|
|
20
91
|
}
|
|
21
92
|
/** Build the full URL for a public API path */
|
|
22
93
|
apiUrl(path) {
|
|
@@ -105,6 +176,57 @@ var HeadroomClient = class {
|
|
|
105
176
|
}
|
|
106
177
|
return res.json();
|
|
107
178
|
}
|
|
179
|
+
/** @internal Used by HeadroomAuth */
|
|
180
|
+
async _fetchPost(path, body) {
|
|
181
|
+
return this.fetchPost(path, body);
|
|
182
|
+
}
|
|
183
|
+
/** @internal Used by HeadroomAuth — GET with Bearer token */
|
|
184
|
+
async _fetchWithAuth(path, token) {
|
|
185
|
+
const url = this.apiUrl(path);
|
|
186
|
+
const res = await fetch(url, {
|
|
187
|
+
headers: {
|
|
188
|
+
"X-Headroom-Key": this.config.apiKey,
|
|
189
|
+
Authorization: `Bearer ${token}`
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
if (!res.ok) {
|
|
193
|
+
let code = "UNKNOWN";
|
|
194
|
+
let message = `HTTP ${res.status}`;
|
|
195
|
+
try {
|
|
196
|
+
const body = await res.json();
|
|
197
|
+
code = body.code || code;
|
|
198
|
+
message = body.error || message;
|
|
199
|
+
} catch {
|
|
200
|
+
}
|
|
201
|
+
throw new HeadroomError(res.status, code, `${message} (GET ${url})`);
|
|
202
|
+
}
|
|
203
|
+
return res.json();
|
|
204
|
+
}
|
|
205
|
+
/** @internal Used by HeadroomAuth — POST with Bearer token */
|
|
206
|
+
async _fetchPostWithAuth(path, token, body) {
|
|
207
|
+
const url = this.apiUrl(path);
|
|
208
|
+
const res = await fetch(url, {
|
|
209
|
+
method: "POST",
|
|
210
|
+
headers: {
|
|
211
|
+
"X-Headroom-Key": this.config.apiKey,
|
|
212
|
+
Authorization: `Bearer ${token}`,
|
|
213
|
+
"Content-Type": "application/json"
|
|
214
|
+
},
|
|
215
|
+
body: JSON.stringify(body)
|
|
216
|
+
});
|
|
217
|
+
if (!res.ok) {
|
|
218
|
+
let code = "UNKNOWN";
|
|
219
|
+
let message = `HTTP ${res.status}`;
|
|
220
|
+
try {
|
|
221
|
+
const errBody = await res.json();
|
|
222
|
+
code = errBody.code || code;
|
|
223
|
+
message = errBody.error || message;
|
|
224
|
+
} catch {
|
|
225
|
+
}
|
|
226
|
+
throw new HeadroomError(res.status, code, `${message} (POST ${url})`);
|
|
227
|
+
}
|
|
228
|
+
return res.json();
|
|
229
|
+
}
|
|
108
230
|
// --- Content ---
|
|
109
231
|
async listContent(collection, opts) {
|
|
110
232
|
const params = new URLSearchParams({ collection });
|
|
@@ -163,6 +285,40 @@ var HeadroomClient = class {
|
|
|
163
285
|
const result = await this.fetch("/version");
|
|
164
286
|
return result.contentVersion;
|
|
165
287
|
}
|
|
288
|
+
// --- Submissions ---
|
|
289
|
+
/**
|
|
290
|
+
* Submit content to a submission collection.
|
|
291
|
+
* Sends a POST to `/v1/{site}/submit/{collection}`.
|
|
292
|
+
* If a sessionToken is provided, it is sent as the `X-Headroom-Session` header
|
|
293
|
+
* to associate the submission with an authenticated site user.
|
|
294
|
+
*/
|
|
295
|
+
async submit(options) {
|
|
296
|
+
const url = this.apiUrl(`/submit/${encodeURIComponent(options.collection)}`);
|
|
297
|
+
const headers = {
|
|
298
|
+
"X-Headroom-Key": this.config.apiKey,
|
|
299
|
+
"Content-Type": "application/json"
|
|
300
|
+
};
|
|
301
|
+
if (options.sessionToken) {
|
|
302
|
+
headers["X-Headroom-Session"] = options.sessionToken;
|
|
303
|
+
}
|
|
304
|
+
const res = await fetch(url, {
|
|
305
|
+
method: "POST",
|
|
306
|
+
headers,
|
|
307
|
+
body: JSON.stringify({ fields: options.fields })
|
|
308
|
+
});
|
|
309
|
+
if (!res.ok) {
|
|
310
|
+
let code = "UNKNOWN";
|
|
311
|
+
let message = `HTTP ${res.status}`;
|
|
312
|
+
try {
|
|
313
|
+
const errBody = await res.json();
|
|
314
|
+
code = errBody.code || code;
|
|
315
|
+
message = errBody.error || message;
|
|
316
|
+
} catch {
|
|
317
|
+
}
|
|
318
|
+
throw new HeadroomError(res.status, code, `${message} (POST ${url})`);
|
|
319
|
+
}
|
|
320
|
+
return res.json();
|
|
321
|
+
}
|
|
166
322
|
};
|
|
167
323
|
|
|
168
324
|
// src/astro/env.ts
|
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
+
HeadroomAuth: () => HeadroomAuth,
|
|
23
24
|
HeadroomClient: () => HeadroomClient,
|
|
24
25
|
HeadroomError: () => HeadroomError
|
|
25
26
|
});
|
|
@@ -27,6 +28,74 @@ module.exports = __toCommonJS(src_exports);
|
|
|
27
28
|
|
|
28
29
|
// src/client.ts
|
|
29
30
|
var import_node_crypto = require("crypto");
|
|
31
|
+
|
|
32
|
+
// src/auth.ts
|
|
33
|
+
var HeadroomAuth = class {
|
|
34
|
+
/** @internal */
|
|
35
|
+
constructor(client) {
|
|
36
|
+
this.client = client;
|
|
37
|
+
}
|
|
38
|
+
/** Request an OTP code be sent to the email address */
|
|
39
|
+
async requestOTP(email) {
|
|
40
|
+
await this.client._fetchPost("/auth/otp/request", { email });
|
|
41
|
+
}
|
|
42
|
+
/** Verify OTP code and receive a long-lived session token */
|
|
43
|
+
async verifyOTP(email, code) {
|
|
44
|
+
return this.client._fetchPost("/auth/otp/verify", {
|
|
45
|
+
email,
|
|
46
|
+
code
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validate a session token and return the user.
|
|
51
|
+
* Automatically refreshes the token if it's past 75% of its lifetime,
|
|
52
|
+
* so callers can update their cookie with the new token if wasRefreshed is true.
|
|
53
|
+
*/
|
|
54
|
+
async getSession(token) {
|
|
55
|
+
const res = await this.client._fetchWithAuth(
|
|
56
|
+
"/auth/session",
|
|
57
|
+
token
|
|
58
|
+
);
|
|
59
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
60
|
+
const remaining = res.expiresAt - now;
|
|
61
|
+
const lifetime = res.expiresAt - res.issuedAt;
|
|
62
|
+
if (remaining < lifetime * 0.25) {
|
|
63
|
+
try {
|
|
64
|
+
const refreshed = await this.refreshSession(token);
|
|
65
|
+
return { ...refreshed, wasRefreshed: true };
|
|
66
|
+
} catch {
|
|
67
|
+
return {
|
|
68
|
+
user: res.user,
|
|
69
|
+
expiresAt: res.expiresAt,
|
|
70
|
+
token,
|
|
71
|
+
wasRefreshed: false
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
user: res.user,
|
|
77
|
+
expiresAt: res.expiresAt,
|
|
78
|
+
token,
|
|
79
|
+
wasRefreshed: false
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** Refresh a session token for a new expiry period */
|
|
83
|
+
async refreshSession(token) {
|
|
84
|
+
const res = await this.client._fetchPostWithAuth(
|
|
85
|
+
"/auth/session/refresh",
|
|
86
|
+
token,
|
|
87
|
+
{}
|
|
88
|
+
);
|
|
89
|
+
return {
|
|
90
|
+
user: res.user,
|
|
91
|
+
expiresAt: res.expiresAt,
|
|
92
|
+
token: res.token,
|
|
93
|
+
wasRefreshed: true
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// src/client.ts
|
|
30
99
|
var HeadroomError = class extends Error {
|
|
31
100
|
status;
|
|
32
101
|
code;
|
|
@@ -39,11 +108,14 @@ var HeadroomError = class extends Error {
|
|
|
39
108
|
};
|
|
40
109
|
var HeadroomClient = class {
|
|
41
110
|
config;
|
|
111
|
+
/** Site user authentication methods */
|
|
112
|
+
auth;
|
|
42
113
|
constructor(config) {
|
|
43
114
|
this.config = {
|
|
44
115
|
...config,
|
|
45
116
|
url: config.url.replace(/\/+$/, "")
|
|
46
117
|
};
|
|
118
|
+
this.auth = new HeadroomAuth(this);
|
|
47
119
|
}
|
|
48
120
|
/** Build the full URL for a public API path */
|
|
49
121
|
apiUrl(path) {
|
|
@@ -132,6 +204,57 @@ var HeadroomClient = class {
|
|
|
132
204
|
}
|
|
133
205
|
return res.json();
|
|
134
206
|
}
|
|
207
|
+
/** @internal Used by HeadroomAuth */
|
|
208
|
+
async _fetchPost(path, body) {
|
|
209
|
+
return this.fetchPost(path, body);
|
|
210
|
+
}
|
|
211
|
+
/** @internal Used by HeadroomAuth — GET with Bearer token */
|
|
212
|
+
async _fetchWithAuth(path, token) {
|
|
213
|
+
const url = this.apiUrl(path);
|
|
214
|
+
const res = await fetch(url, {
|
|
215
|
+
headers: {
|
|
216
|
+
"X-Headroom-Key": this.config.apiKey,
|
|
217
|
+
Authorization: `Bearer ${token}`
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
if (!res.ok) {
|
|
221
|
+
let code = "UNKNOWN";
|
|
222
|
+
let message = `HTTP ${res.status}`;
|
|
223
|
+
try {
|
|
224
|
+
const body = await res.json();
|
|
225
|
+
code = body.code || code;
|
|
226
|
+
message = body.error || message;
|
|
227
|
+
} catch {
|
|
228
|
+
}
|
|
229
|
+
throw new HeadroomError(res.status, code, `${message} (GET ${url})`);
|
|
230
|
+
}
|
|
231
|
+
return res.json();
|
|
232
|
+
}
|
|
233
|
+
/** @internal Used by HeadroomAuth — POST with Bearer token */
|
|
234
|
+
async _fetchPostWithAuth(path, token, body) {
|
|
235
|
+
const url = this.apiUrl(path);
|
|
236
|
+
const res = await fetch(url, {
|
|
237
|
+
method: "POST",
|
|
238
|
+
headers: {
|
|
239
|
+
"X-Headroom-Key": this.config.apiKey,
|
|
240
|
+
Authorization: `Bearer ${token}`,
|
|
241
|
+
"Content-Type": "application/json"
|
|
242
|
+
},
|
|
243
|
+
body: JSON.stringify(body)
|
|
244
|
+
});
|
|
245
|
+
if (!res.ok) {
|
|
246
|
+
let code = "UNKNOWN";
|
|
247
|
+
let message = `HTTP ${res.status}`;
|
|
248
|
+
try {
|
|
249
|
+
const errBody = await res.json();
|
|
250
|
+
code = errBody.code || code;
|
|
251
|
+
message = errBody.error || message;
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
throw new HeadroomError(res.status, code, `${message} (POST ${url})`);
|
|
255
|
+
}
|
|
256
|
+
return res.json();
|
|
257
|
+
}
|
|
135
258
|
// --- Content ---
|
|
136
259
|
async listContent(collection, opts) {
|
|
137
260
|
const params = new URLSearchParams({ collection });
|
|
@@ -190,9 +313,44 @@ var HeadroomClient = class {
|
|
|
190
313
|
const result = await this.fetch("/version");
|
|
191
314
|
return result.contentVersion;
|
|
192
315
|
}
|
|
316
|
+
// --- Submissions ---
|
|
317
|
+
/**
|
|
318
|
+
* Submit content to a submission collection.
|
|
319
|
+
* Sends a POST to `/v1/{site}/submit/{collection}`.
|
|
320
|
+
* If a sessionToken is provided, it is sent as the `X-Headroom-Session` header
|
|
321
|
+
* to associate the submission with an authenticated site user.
|
|
322
|
+
*/
|
|
323
|
+
async submit(options) {
|
|
324
|
+
const url = this.apiUrl(`/submit/${encodeURIComponent(options.collection)}`);
|
|
325
|
+
const headers = {
|
|
326
|
+
"X-Headroom-Key": this.config.apiKey,
|
|
327
|
+
"Content-Type": "application/json"
|
|
328
|
+
};
|
|
329
|
+
if (options.sessionToken) {
|
|
330
|
+
headers["X-Headroom-Session"] = options.sessionToken;
|
|
331
|
+
}
|
|
332
|
+
const res = await fetch(url, {
|
|
333
|
+
method: "POST",
|
|
334
|
+
headers,
|
|
335
|
+
body: JSON.stringify({ fields: options.fields })
|
|
336
|
+
});
|
|
337
|
+
if (!res.ok) {
|
|
338
|
+
let code = "UNKNOWN";
|
|
339
|
+
let message = `HTTP ${res.status}`;
|
|
340
|
+
try {
|
|
341
|
+
const errBody = await res.json();
|
|
342
|
+
code = errBody.code || code;
|
|
343
|
+
message = errBody.error || message;
|
|
344
|
+
} catch {
|
|
345
|
+
}
|
|
346
|
+
throw new HeadroomError(res.status, code, `${message} (POST ${url})`);
|
|
347
|
+
}
|
|
348
|
+
return res.json();
|
|
349
|
+
}
|
|
193
350
|
};
|
|
194
351
|
// Annotate the CommonJS export names for ESM import in node:
|
|
195
352
|
0 && (module.exports = {
|
|
353
|
+
HeadroomAuth,
|
|
196
354
|
HeadroomClient,
|
|
197
355
|
HeadroomError
|
|
198
356
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -151,11 +151,69 @@ interface TransformOptions {
|
|
|
151
151
|
/** Quality (1-100) */
|
|
152
152
|
quality?: number;
|
|
153
153
|
}
|
|
154
|
+
/** Options for submitting content to a submission collection. */
|
|
155
|
+
interface SubmitOptions {
|
|
156
|
+
/** The submission collection name */
|
|
157
|
+
collection: string;
|
|
158
|
+
/** Field values for the submission */
|
|
159
|
+
fields: Record<string, unknown>;
|
|
160
|
+
/** Optional site user session token (adds X-Headroom-Session header) */
|
|
161
|
+
sessionToken?: string;
|
|
162
|
+
}
|
|
163
|
+
/** Result returned from a successful submission. */
|
|
164
|
+
interface SubmitResult {
|
|
165
|
+
/** The ID of the created content item */
|
|
166
|
+
contentId: string;
|
|
167
|
+
/** Unix timestamp of creation */
|
|
168
|
+
createdAt: number;
|
|
169
|
+
/** Site user ID if the submission was authenticated */
|
|
170
|
+
siteUserId?: string;
|
|
171
|
+
}
|
|
154
172
|
interface HeadroomErrorBody {
|
|
155
173
|
error: string;
|
|
156
174
|
code?: string;
|
|
157
175
|
}
|
|
158
176
|
|
|
177
|
+
interface AuthResult {
|
|
178
|
+
token: string;
|
|
179
|
+
expiresAt: number;
|
|
180
|
+
user: AuthUser;
|
|
181
|
+
}
|
|
182
|
+
interface AuthUser {
|
|
183
|
+
userId: string;
|
|
184
|
+
email: string;
|
|
185
|
+
name?: string;
|
|
186
|
+
tags?: string[];
|
|
187
|
+
fields?: Record<string, unknown>;
|
|
188
|
+
}
|
|
189
|
+
interface AuthSession {
|
|
190
|
+
user: AuthUser;
|
|
191
|
+
expiresAt: number;
|
|
192
|
+
token: string;
|
|
193
|
+
wasRefreshed: boolean;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* HeadroomAuth provides site user authentication methods.
|
|
197
|
+
* Access via `client.auth`.
|
|
198
|
+
*/
|
|
199
|
+
declare class HeadroomAuth {
|
|
200
|
+
private client;
|
|
201
|
+
/** @internal */
|
|
202
|
+
constructor(client: HeadroomClient);
|
|
203
|
+
/** Request an OTP code be sent to the email address */
|
|
204
|
+
requestOTP(email: string): Promise<void>;
|
|
205
|
+
/** Verify OTP code and receive a long-lived session token */
|
|
206
|
+
verifyOTP(email: string, code: string): Promise<AuthResult>;
|
|
207
|
+
/**
|
|
208
|
+
* Validate a session token and return the user.
|
|
209
|
+
* Automatically refreshes the token if it's past 75% of its lifetime,
|
|
210
|
+
* so callers can update their cookie with the new token if wasRefreshed is true.
|
|
211
|
+
*/
|
|
212
|
+
getSession(token: string): Promise<AuthSession>;
|
|
213
|
+
/** Refresh a session token for a new expiry period */
|
|
214
|
+
refreshSession(token: string): Promise<AuthSession>;
|
|
215
|
+
}
|
|
216
|
+
|
|
159
217
|
declare class HeadroomError extends Error {
|
|
160
218
|
status: number;
|
|
161
219
|
code: string;
|
|
@@ -163,6 +221,8 @@ declare class HeadroomError extends Error {
|
|
|
163
221
|
}
|
|
164
222
|
declare class HeadroomClient {
|
|
165
223
|
private config;
|
|
224
|
+
/** Site user authentication methods */
|
|
225
|
+
readonly auth: HeadroomAuth;
|
|
166
226
|
constructor(config: HeadroomConfig);
|
|
167
227
|
/** Build the full URL for a public API path */
|
|
168
228
|
private apiUrl;
|
|
@@ -189,6 +249,12 @@ declare class HeadroomClient {
|
|
|
189
249
|
transformUrl(path: string | undefined, opts?: TransformOptions): string;
|
|
190
250
|
private fetch;
|
|
191
251
|
private fetchPost;
|
|
252
|
+
/** @internal Used by HeadroomAuth */
|
|
253
|
+
_fetchPost<T>(path: string, body: unknown): Promise<T>;
|
|
254
|
+
/** @internal Used by HeadroomAuth — GET with Bearer token */
|
|
255
|
+
_fetchWithAuth<T>(path: string, token: string): Promise<T>;
|
|
256
|
+
/** @internal Used by HeadroomAuth — POST with Bearer token */
|
|
257
|
+
_fetchPostWithAuth<T>(path: string, token: string, body: unknown): Promise<T>;
|
|
192
258
|
listContent(collection: string, opts?: {
|
|
193
259
|
limit?: number;
|
|
194
260
|
cursor?: string;
|
|
@@ -218,6 +284,13 @@ declare class HeadroomClient {
|
|
|
218
284
|
getCollection(name: string): Promise<Collection>;
|
|
219
285
|
listBlockTypes(): Promise<BlockTypeListResult>;
|
|
220
286
|
getVersion(): Promise<number>;
|
|
287
|
+
/**
|
|
288
|
+
* Submit content to a submission collection.
|
|
289
|
+
* Sends a POST to `/v1/{site}/submit/{collection}`.
|
|
290
|
+
* If a sessionToken is provided, it is sent as the `X-Headroom-Session` header
|
|
291
|
+
* to associate the submission with an authenticated site user.
|
|
292
|
+
*/
|
|
293
|
+
submit(options: SubmitOptions): Promise<SubmitResult>;
|
|
221
294
|
}
|
|
222
295
|
|
|
223
|
-
export { type BatchContentResult, type Block, type BlockTypeDef, type BlockTypeListResult, type Collection, type CollectionListResult, type CollectionSummary, type ContentItem, type ContentListResult, type ContentMetadata, type ContentRef, type FieldDef, HeadroomClient, type HeadroomConfig, HeadroomError, type HeadroomErrorBody, type InlineContent, type LinkContent, type PublicContentRef, type RefsMap, type RelationshipDef, type TableContent, type TableRow, type TextContent, type TextStyles, type TransformOptions };
|
|
296
|
+
export { type AuthResult, type AuthSession, type AuthUser, type BatchContentResult, type Block, type BlockTypeDef, type BlockTypeListResult, type Collection, type CollectionListResult, type CollectionSummary, type ContentItem, type ContentListResult, type ContentMetadata, type ContentRef, type FieldDef, HeadroomAuth, HeadroomClient, type HeadroomConfig, HeadroomError, type HeadroomErrorBody, type InlineContent, type LinkContent, type PublicContentRef, type RefsMap, type RelationshipDef, type SubmitOptions, type SubmitResult, type TableContent, type TableRow, type TextContent, type TextStyles, type TransformOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -151,11 +151,69 @@ interface TransformOptions {
|
|
|
151
151
|
/** Quality (1-100) */
|
|
152
152
|
quality?: number;
|
|
153
153
|
}
|
|
154
|
+
/** Options for submitting content to a submission collection. */
|
|
155
|
+
interface SubmitOptions {
|
|
156
|
+
/** The submission collection name */
|
|
157
|
+
collection: string;
|
|
158
|
+
/** Field values for the submission */
|
|
159
|
+
fields: Record<string, unknown>;
|
|
160
|
+
/** Optional site user session token (adds X-Headroom-Session header) */
|
|
161
|
+
sessionToken?: string;
|
|
162
|
+
}
|
|
163
|
+
/** Result returned from a successful submission. */
|
|
164
|
+
interface SubmitResult {
|
|
165
|
+
/** The ID of the created content item */
|
|
166
|
+
contentId: string;
|
|
167
|
+
/** Unix timestamp of creation */
|
|
168
|
+
createdAt: number;
|
|
169
|
+
/** Site user ID if the submission was authenticated */
|
|
170
|
+
siteUserId?: string;
|
|
171
|
+
}
|
|
154
172
|
interface HeadroomErrorBody {
|
|
155
173
|
error: string;
|
|
156
174
|
code?: string;
|
|
157
175
|
}
|
|
158
176
|
|
|
177
|
+
interface AuthResult {
|
|
178
|
+
token: string;
|
|
179
|
+
expiresAt: number;
|
|
180
|
+
user: AuthUser;
|
|
181
|
+
}
|
|
182
|
+
interface AuthUser {
|
|
183
|
+
userId: string;
|
|
184
|
+
email: string;
|
|
185
|
+
name?: string;
|
|
186
|
+
tags?: string[];
|
|
187
|
+
fields?: Record<string, unknown>;
|
|
188
|
+
}
|
|
189
|
+
interface AuthSession {
|
|
190
|
+
user: AuthUser;
|
|
191
|
+
expiresAt: number;
|
|
192
|
+
token: string;
|
|
193
|
+
wasRefreshed: boolean;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* HeadroomAuth provides site user authentication methods.
|
|
197
|
+
* Access via `client.auth`.
|
|
198
|
+
*/
|
|
199
|
+
declare class HeadroomAuth {
|
|
200
|
+
private client;
|
|
201
|
+
/** @internal */
|
|
202
|
+
constructor(client: HeadroomClient);
|
|
203
|
+
/** Request an OTP code be sent to the email address */
|
|
204
|
+
requestOTP(email: string): Promise<void>;
|
|
205
|
+
/** Verify OTP code and receive a long-lived session token */
|
|
206
|
+
verifyOTP(email: string, code: string): Promise<AuthResult>;
|
|
207
|
+
/**
|
|
208
|
+
* Validate a session token and return the user.
|
|
209
|
+
* Automatically refreshes the token if it's past 75% of its lifetime,
|
|
210
|
+
* so callers can update their cookie with the new token if wasRefreshed is true.
|
|
211
|
+
*/
|
|
212
|
+
getSession(token: string): Promise<AuthSession>;
|
|
213
|
+
/** Refresh a session token for a new expiry period */
|
|
214
|
+
refreshSession(token: string): Promise<AuthSession>;
|
|
215
|
+
}
|
|
216
|
+
|
|
159
217
|
declare class HeadroomError extends Error {
|
|
160
218
|
status: number;
|
|
161
219
|
code: string;
|
|
@@ -163,6 +221,8 @@ declare class HeadroomError extends Error {
|
|
|
163
221
|
}
|
|
164
222
|
declare class HeadroomClient {
|
|
165
223
|
private config;
|
|
224
|
+
/** Site user authentication methods */
|
|
225
|
+
readonly auth: HeadroomAuth;
|
|
166
226
|
constructor(config: HeadroomConfig);
|
|
167
227
|
/** Build the full URL for a public API path */
|
|
168
228
|
private apiUrl;
|
|
@@ -189,6 +249,12 @@ declare class HeadroomClient {
|
|
|
189
249
|
transformUrl(path: string | undefined, opts?: TransformOptions): string;
|
|
190
250
|
private fetch;
|
|
191
251
|
private fetchPost;
|
|
252
|
+
/** @internal Used by HeadroomAuth */
|
|
253
|
+
_fetchPost<T>(path: string, body: unknown): Promise<T>;
|
|
254
|
+
/** @internal Used by HeadroomAuth — GET with Bearer token */
|
|
255
|
+
_fetchWithAuth<T>(path: string, token: string): Promise<T>;
|
|
256
|
+
/** @internal Used by HeadroomAuth — POST with Bearer token */
|
|
257
|
+
_fetchPostWithAuth<T>(path: string, token: string, body: unknown): Promise<T>;
|
|
192
258
|
listContent(collection: string, opts?: {
|
|
193
259
|
limit?: number;
|
|
194
260
|
cursor?: string;
|
|
@@ -218,6 +284,13 @@ declare class HeadroomClient {
|
|
|
218
284
|
getCollection(name: string): Promise<Collection>;
|
|
219
285
|
listBlockTypes(): Promise<BlockTypeListResult>;
|
|
220
286
|
getVersion(): Promise<number>;
|
|
287
|
+
/**
|
|
288
|
+
* Submit content to a submission collection.
|
|
289
|
+
* Sends a POST to `/v1/{site}/submit/{collection}`.
|
|
290
|
+
* If a sessionToken is provided, it is sent as the `X-Headroom-Session` header
|
|
291
|
+
* to associate the submission with an authenticated site user.
|
|
292
|
+
*/
|
|
293
|
+
submit(options: SubmitOptions): Promise<SubmitResult>;
|
|
221
294
|
}
|
|
222
295
|
|
|
223
|
-
export { type BatchContentResult, type Block, type BlockTypeDef, type BlockTypeListResult, type Collection, type CollectionListResult, type CollectionSummary, type ContentItem, type ContentListResult, type ContentMetadata, type ContentRef, type FieldDef, HeadroomClient, type HeadroomConfig, HeadroomError, type HeadroomErrorBody, type InlineContent, type LinkContent, type PublicContentRef, type RefsMap, type RelationshipDef, type TableContent, type TableRow, type TextContent, type TextStyles, type TransformOptions };
|
|
296
|
+
export { type AuthResult, type AuthSession, type AuthUser, type BatchContentResult, type Block, type BlockTypeDef, type BlockTypeListResult, type Collection, type CollectionListResult, type CollectionSummary, type ContentItem, type ContentListResult, type ContentMetadata, type ContentRef, type FieldDef, HeadroomAuth, HeadroomClient, type HeadroomConfig, HeadroomError, type HeadroomErrorBody, type InlineContent, type LinkContent, type PublicContentRef, type RefsMap, type RelationshipDef, type SubmitOptions, type SubmitResult, type TableContent, type TableRow, type TextContent, type TextStyles, type TransformOptions };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,73 @@
|
|
|
1
1
|
// src/client.ts
|
|
2
2
|
import { createHmac } from "crypto";
|
|
3
|
+
|
|
4
|
+
// src/auth.ts
|
|
5
|
+
var HeadroomAuth = class {
|
|
6
|
+
/** @internal */
|
|
7
|
+
constructor(client) {
|
|
8
|
+
this.client = client;
|
|
9
|
+
}
|
|
10
|
+
/** Request an OTP code be sent to the email address */
|
|
11
|
+
async requestOTP(email) {
|
|
12
|
+
await this.client._fetchPost("/auth/otp/request", { email });
|
|
13
|
+
}
|
|
14
|
+
/** Verify OTP code and receive a long-lived session token */
|
|
15
|
+
async verifyOTP(email, code) {
|
|
16
|
+
return this.client._fetchPost("/auth/otp/verify", {
|
|
17
|
+
email,
|
|
18
|
+
code
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validate a session token and return the user.
|
|
23
|
+
* Automatically refreshes the token if it's past 75% of its lifetime,
|
|
24
|
+
* so callers can update their cookie with the new token if wasRefreshed is true.
|
|
25
|
+
*/
|
|
26
|
+
async getSession(token) {
|
|
27
|
+
const res = await this.client._fetchWithAuth(
|
|
28
|
+
"/auth/session",
|
|
29
|
+
token
|
|
30
|
+
);
|
|
31
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
32
|
+
const remaining = res.expiresAt - now;
|
|
33
|
+
const lifetime = res.expiresAt - res.issuedAt;
|
|
34
|
+
if (remaining < lifetime * 0.25) {
|
|
35
|
+
try {
|
|
36
|
+
const refreshed = await this.refreshSession(token);
|
|
37
|
+
return { ...refreshed, wasRefreshed: true };
|
|
38
|
+
} catch {
|
|
39
|
+
return {
|
|
40
|
+
user: res.user,
|
|
41
|
+
expiresAt: res.expiresAt,
|
|
42
|
+
token,
|
|
43
|
+
wasRefreshed: false
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
user: res.user,
|
|
49
|
+
expiresAt: res.expiresAt,
|
|
50
|
+
token,
|
|
51
|
+
wasRefreshed: false
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Refresh a session token for a new expiry period */
|
|
55
|
+
async refreshSession(token) {
|
|
56
|
+
const res = await this.client._fetchPostWithAuth(
|
|
57
|
+
"/auth/session/refresh",
|
|
58
|
+
token,
|
|
59
|
+
{}
|
|
60
|
+
);
|
|
61
|
+
return {
|
|
62
|
+
user: res.user,
|
|
63
|
+
expiresAt: res.expiresAt,
|
|
64
|
+
token: res.token,
|
|
65
|
+
wasRefreshed: true
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// src/client.ts
|
|
3
71
|
var HeadroomError = class extends Error {
|
|
4
72
|
status;
|
|
5
73
|
code;
|
|
@@ -12,11 +80,14 @@ var HeadroomError = class extends Error {
|
|
|
12
80
|
};
|
|
13
81
|
var HeadroomClient = class {
|
|
14
82
|
config;
|
|
83
|
+
/** Site user authentication methods */
|
|
84
|
+
auth;
|
|
15
85
|
constructor(config) {
|
|
16
86
|
this.config = {
|
|
17
87
|
...config,
|
|
18
88
|
url: config.url.replace(/\/+$/, "")
|
|
19
89
|
};
|
|
90
|
+
this.auth = new HeadroomAuth(this);
|
|
20
91
|
}
|
|
21
92
|
/** Build the full URL for a public API path */
|
|
22
93
|
apiUrl(path) {
|
|
@@ -105,6 +176,57 @@ var HeadroomClient = class {
|
|
|
105
176
|
}
|
|
106
177
|
return res.json();
|
|
107
178
|
}
|
|
179
|
+
/** @internal Used by HeadroomAuth */
|
|
180
|
+
async _fetchPost(path, body) {
|
|
181
|
+
return this.fetchPost(path, body);
|
|
182
|
+
}
|
|
183
|
+
/** @internal Used by HeadroomAuth — GET with Bearer token */
|
|
184
|
+
async _fetchWithAuth(path, token) {
|
|
185
|
+
const url = this.apiUrl(path);
|
|
186
|
+
const res = await fetch(url, {
|
|
187
|
+
headers: {
|
|
188
|
+
"X-Headroom-Key": this.config.apiKey,
|
|
189
|
+
Authorization: `Bearer ${token}`
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
if (!res.ok) {
|
|
193
|
+
let code = "UNKNOWN";
|
|
194
|
+
let message = `HTTP ${res.status}`;
|
|
195
|
+
try {
|
|
196
|
+
const body = await res.json();
|
|
197
|
+
code = body.code || code;
|
|
198
|
+
message = body.error || message;
|
|
199
|
+
} catch {
|
|
200
|
+
}
|
|
201
|
+
throw new HeadroomError(res.status, code, `${message} (GET ${url})`);
|
|
202
|
+
}
|
|
203
|
+
return res.json();
|
|
204
|
+
}
|
|
205
|
+
/** @internal Used by HeadroomAuth — POST with Bearer token */
|
|
206
|
+
async _fetchPostWithAuth(path, token, body) {
|
|
207
|
+
const url = this.apiUrl(path);
|
|
208
|
+
const res = await fetch(url, {
|
|
209
|
+
method: "POST",
|
|
210
|
+
headers: {
|
|
211
|
+
"X-Headroom-Key": this.config.apiKey,
|
|
212
|
+
Authorization: `Bearer ${token}`,
|
|
213
|
+
"Content-Type": "application/json"
|
|
214
|
+
},
|
|
215
|
+
body: JSON.stringify(body)
|
|
216
|
+
});
|
|
217
|
+
if (!res.ok) {
|
|
218
|
+
let code = "UNKNOWN";
|
|
219
|
+
let message = `HTTP ${res.status}`;
|
|
220
|
+
try {
|
|
221
|
+
const errBody = await res.json();
|
|
222
|
+
code = errBody.code || code;
|
|
223
|
+
message = errBody.error || message;
|
|
224
|
+
} catch {
|
|
225
|
+
}
|
|
226
|
+
throw new HeadroomError(res.status, code, `${message} (POST ${url})`);
|
|
227
|
+
}
|
|
228
|
+
return res.json();
|
|
229
|
+
}
|
|
108
230
|
// --- Content ---
|
|
109
231
|
async listContent(collection, opts) {
|
|
110
232
|
const params = new URLSearchParams({ collection });
|
|
@@ -163,8 +285,43 @@ var HeadroomClient = class {
|
|
|
163
285
|
const result = await this.fetch("/version");
|
|
164
286
|
return result.contentVersion;
|
|
165
287
|
}
|
|
288
|
+
// --- Submissions ---
|
|
289
|
+
/**
|
|
290
|
+
* Submit content to a submission collection.
|
|
291
|
+
* Sends a POST to `/v1/{site}/submit/{collection}`.
|
|
292
|
+
* If a sessionToken is provided, it is sent as the `X-Headroom-Session` header
|
|
293
|
+
* to associate the submission with an authenticated site user.
|
|
294
|
+
*/
|
|
295
|
+
async submit(options) {
|
|
296
|
+
const url = this.apiUrl(`/submit/${encodeURIComponent(options.collection)}`);
|
|
297
|
+
const headers = {
|
|
298
|
+
"X-Headroom-Key": this.config.apiKey,
|
|
299
|
+
"Content-Type": "application/json"
|
|
300
|
+
};
|
|
301
|
+
if (options.sessionToken) {
|
|
302
|
+
headers["X-Headroom-Session"] = options.sessionToken;
|
|
303
|
+
}
|
|
304
|
+
const res = await fetch(url, {
|
|
305
|
+
method: "POST",
|
|
306
|
+
headers,
|
|
307
|
+
body: JSON.stringify({ fields: options.fields })
|
|
308
|
+
});
|
|
309
|
+
if (!res.ok) {
|
|
310
|
+
let code = "UNKNOWN";
|
|
311
|
+
let message = `HTTP ${res.status}`;
|
|
312
|
+
try {
|
|
313
|
+
const errBody = await res.json();
|
|
314
|
+
code = errBody.code || code;
|
|
315
|
+
message = errBody.error || message;
|
|
316
|
+
} catch {
|
|
317
|
+
}
|
|
318
|
+
throw new HeadroomError(res.status, code, `${message} (POST ${url})`);
|
|
319
|
+
}
|
|
320
|
+
return res.json();
|
|
321
|
+
}
|
|
166
322
|
};
|
|
167
323
|
export {
|
|
324
|
+
HeadroomAuth,
|
|
168
325
|
HeadroomClient,
|
|
169
326
|
HeadroomError
|
|
170
327
|
};
|
package/dist/next.cjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/next.ts
|
|
22
|
+
var next_exports = {};
|
|
23
|
+
__export(next_exports, {
|
|
24
|
+
DevRefresh: () => DevRefresh
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(next_exports);
|
|
27
|
+
|
|
28
|
+
// src/next/DevRefresh.tsx
|
|
29
|
+
var import_react = require("react");
|
|
30
|
+
var import_navigation = require("next/navigation");
|
|
31
|
+
function DevRefresh({
|
|
32
|
+
versionUrl,
|
|
33
|
+
apiKey,
|
|
34
|
+
interval = 2e3
|
|
35
|
+
}) {
|
|
36
|
+
const router = (0, import_navigation.useRouter)();
|
|
37
|
+
const lastVersion = (0, import_react.useRef)(null);
|
|
38
|
+
(0, import_react.useEffect)(() => {
|
|
39
|
+
const controller = new AbortController();
|
|
40
|
+
const poll = async () => {
|
|
41
|
+
try {
|
|
42
|
+
const res = await fetch(versionUrl, {
|
|
43
|
+
headers: { "X-Headroom-Key": apiKey },
|
|
44
|
+
signal: controller.signal
|
|
45
|
+
});
|
|
46
|
+
if (!res.ok) return;
|
|
47
|
+
const data = await res.json();
|
|
48
|
+
const version = data.contentVersion;
|
|
49
|
+
if (lastVersion.current !== null && version !== lastVersion.current) {
|
|
50
|
+
router.refresh();
|
|
51
|
+
}
|
|
52
|
+
lastVersion.current = version;
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const id = setInterval(poll, interval);
|
|
57
|
+
poll();
|
|
58
|
+
return () => {
|
|
59
|
+
controller.abort();
|
|
60
|
+
clearInterval(id);
|
|
61
|
+
};
|
|
62
|
+
}, [versionUrl, apiKey, interval, router]);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
66
|
+
0 && (module.exports = {
|
|
67
|
+
DevRefresh
|
|
68
|
+
});
|
package/dist/next.d.cts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface DevRefreshProps {
|
|
2
|
+
/** URL to poll for version changes (full URL to /v1/{site}/version) */
|
|
3
|
+
versionUrl: string;
|
|
4
|
+
/** API key header value */
|
|
5
|
+
apiKey: string;
|
|
6
|
+
/** Poll interval in milliseconds (default: 2000) */
|
|
7
|
+
interval?: number;
|
|
8
|
+
}
|
|
9
|
+
declare function DevRefresh({ versionUrl, apiKey, interval, }: DevRefreshProps): null;
|
|
10
|
+
|
|
11
|
+
export { DevRefresh, type DevRefreshProps };
|
package/dist/next.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface DevRefreshProps {
|
|
2
|
+
/** URL to poll for version changes (full URL to /v1/{site}/version) */
|
|
3
|
+
versionUrl: string;
|
|
4
|
+
/** API key header value */
|
|
5
|
+
apiKey: string;
|
|
6
|
+
/** Poll interval in milliseconds (default: 2000) */
|
|
7
|
+
interval?: number;
|
|
8
|
+
}
|
|
9
|
+
declare function DevRefresh({ versionUrl, apiKey, interval, }: DevRefreshProps): null;
|
|
10
|
+
|
|
11
|
+
export { DevRefresh, type DevRefreshProps };
|
package/dist/next.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/next/DevRefresh.tsx
|
|
4
|
+
import { useEffect, useRef } from "react";
|
|
5
|
+
import { useRouter } from "next/navigation";
|
|
6
|
+
function DevRefresh({
|
|
7
|
+
versionUrl,
|
|
8
|
+
apiKey,
|
|
9
|
+
interval = 2e3
|
|
10
|
+
}) {
|
|
11
|
+
const router = useRouter();
|
|
12
|
+
const lastVersion = useRef(null);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const controller = new AbortController();
|
|
15
|
+
const poll = async () => {
|
|
16
|
+
try {
|
|
17
|
+
const res = await fetch(versionUrl, {
|
|
18
|
+
headers: { "X-Headroom-Key": apiKey },
|
|
19
|
+
signal: controller.signal
|
|
20
|
+
});
|
|
21
|
+
if (!res.ok) return;
|
|
22
|
+
const data = await res.json();
|
|
23
|
+
const version = data.contentVersion;
|
|
24
|
+
if (lastVersion.current !== null && version !== lastVersion.current) {
|
|
25
|
+
router.refresh();
|
|
26
|
+
}
|
|
27
|
+
lastVersion.current = version;
|
|
28
|
+
} catch {
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const id = setInterval(poll, interval);
|
|
32
|
+
poll();
|
|
33
|
+
return () => {
|
|
34
|
+
controller.abort();
|
|
35
|
+
clearInterval(id);
|
|
36
|
+
};
|
|
37
|
+
}, [versionUrl, apiKey, interval, router]);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
DevRefresh
|
|
42
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@headroom-cms/api",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
"types": "./dist/astro.d.ts",
|
|
20
20
|
"import": "./dist/astro.js"
|
|
21
21
|
},
|
|
22
|
+
"./next": {
|
|
23
|
+
"types": "./dist/next.d.ts",
|
|
24
|
+
"import": "./dist/next.js",
|
|
25
|
+
"require": "./dist/next.cjs"
|
|
26
|
+
},
|
|
22
27
|
"./codegen": {
|
|
23
28
|
"types": "./dist/codegen.d.ts",
|
|
24
29
|
"import": "./dist/codegen.js",
|
|
@@ -41,9 +46,10 @@
|
|
|
41
46
|
"typecheck": "tsc --noEmit"
|
|
42
47
|
},
|
|
43
48
|
"peerDependencies": {
|
|
49
|
+
"astro": ">=5",
|
|
50
|
+
"next": ">=14",
|
|
44
51
|
"react": ">=18",
|
|
45
|
-
"react-dom": ">=18"
|
|
46
|
-
"astro": ">=5"
|
|
52
|
+
"react-dom": ">=18"
|
|
47
53
|
},
|
|
48
54
|
"peerDependenciesMeta": {
|
|
49
55
|
"react": {
|
|
@@ -54,19 +60,23 @@
|
|
|
54
60
|
},
|
|
55
61
|
"astro": {
|
|
56
62
|
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"next": {
|
|
65
|
+
"optional": true
|
|
57
66
|
}
|
|
58
67
|
},
|
|
59
68
|
"devDependencies": {
|
|
60
69
|
"@testing-library/jest-dom": "~6.6.3",
|
|
61
70
|
"@testing-library/react": "~16.3.0",
|
|
71
|
+
"@types/node": "~22.0.0",
|
|
62
72
|
"@types/react": "~19.1.0",
|
|
73
|
+
"astro": "^5.0.0",
|
|
63
74
|
"jsdom": "~26.1.0",
|
|
75
|
+
"next": "^16.2.1",
|
|
64
76
|
"react": "~19.1.0",
|
|
65
77
|
"react-dom": "~19.1.0",
|
|
66
78
|
"tsup": "~8.5.0",
|
|
67
79
|
"typescript": "~5.9.3",
|
|
68
|
-
"astro": "^5.0.0",
|
|
69
|
-
"@types/node": "~22.0.0",
|
|
70
80
|
"vitest": "~4.0.18"
|
|
71
81
|
}
|
|
72
82
|
}
|