@foir/sdk 0.1.0 → 0.3.0
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/README.md +72 -0
- package/dist/next.d.ts +178 -0
- package/dist/next.js +275 -0
- package/dist/push.d.ts +109 -0
- package/dist/push.js +259 -0
- package/dist/react.d.ts +244 -0
- package/dist/react.js +608 -0
- package/dist/server.d.ts +78 -1
- package/dist/server.js +63 -0
- package/package.json +13 -1
package/dist/server.js
CHANGED
|
@@ -184,6 +184,67 @@ function parseContextHeader(raw) {
|
|
|
184
184
|
return out;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
// src/server/require-scoped-token.ts
|
|
188
|
+
var TOKEN_HEADER = "X-Foir-Token";
|
|
189
|
+
var CONTEXT_HEADER = "X-Foir-Context";
|
|
190
|
+
var DEFAULT_JWKS_URL = "https://api.foir.dev/.well-known/jwks.json";
|
|
191
|
+
var ScopedTokenError = class extends Error {
|
|
192
|
+
status;
|
|
193
|
+
constructor(message, status) {
|
|
194
|
+
super(message);
|
|
195
|
+
this.name = "ScopedTokenError";
|
|
196
|
+
this.status = status;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
async function requireScopedToken(request, options) {
|
|
200
|
+
const token = request.headers.get(TOKEN_HEADER);
|
|
201
|
+
if (!token) {
|
|
202
|
+
throw new ScopedTokenError(
|
|
203
|
+
`missing ${TOKEN_HEADER} header \u2014 this route only accepts platform-dispatched requests`,
|
|
204
|
+
401
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
let claims;
|
|
208
|
+
try {
|
|
209
|
+
claims = await verifyScopedToken(
|
|
210
|
+
token,
|
|
211
|
+
options?.jwksUrl ?? DEFAULT_JWKS_URL,
|
|
212
|
+
options
|
|
213
|
+
);
|
|
214
|
+
} catch (err) {
|
|
215
|
+
throw new ScopedTokenError(
|
|
216
|
+
`invalid scoped token: ${err instanceof Error ? err.message : String(err)}`,
|
|
217
|
+
401
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
let subject;
|
|
221
|
+
try {
|
|
222
|
+
subject = parseSubject(claims.sub);
|
|
223
|
+
} catch (err) {
|
|
224
|
+
throw new ScopedTokenError(
|
|
225
|
+
`invalid scoped token subject: ${err instanceof Error ? err.message : String(err)}`,
|
|
226
|
+
401
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
if (options?.expectedProjectId && subject.projectId !== options.expectedProjectId) {
|
|
230
|
+
throw new ScopedTokenError(
|
|
231
|
+
"scoped token is bound to a different project",
|
|
232
|
+
403
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
if (options?.expectedTenantId && subject.tenantId !== options.expectedTenantId) {
|
|
236
|
+
throw new ScopedTokenError(
|
|
237
|
+
"scoped token is bound to a different tenant",
|
|
238
|
+
403
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
claims,
|
|
243
|
+
subject,
|
|
244
|
+
context: parseContextHeader(request.headers.get(CONTEXT_HEADER))
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
187
248
|
// src/server/callback-client.ts
|
|
188
249
|
function createCallbackClient(callback, opts) {
|
|
189
250
|
const { executionId, signingSecret } = opts;
|
|
@@ -284,6 +345,7 @@ async function hmacSha256Hex(secret, body) {
|
|
|
284
345
|
return Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
285
346
|
}
|
|
286
347
|
export {
|
|
348
|
+
ScopedTokenError,
|
|
287
349
|
ServerClientError,
|
|
288
350
|
createCallbackClient,
|
|
289
351
|
createServerClient,
|
|
@@ -291,6 +353,7 @@ export {
|
|
|
291
353
|
parseSubject,
|
|
292
354
|
recordsReadModels,
|
|
293
355
|
recordsWriteModels,
|
|
356
|
+
requireScopedToken,
|
|
294
357
|
verifyScopedToken,
|
|
295
358
|
verifyWebhookSignature
|
|
296
359
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foir/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Official Foir SDK — editor iframe client + server-side platform helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -33,6 +33,18 @@
|
|
|
33
33
|
"types": "./dist/auth.d.ts",
|
|
34
34
|
"import": "./dist/auth.js"
|
|
35
35
|
},
|
|
36
|
+
"./react": {
|
|
37
|
+
"types": "./dist/react.d.ts",
|
|
38
|
+
"import": "./dist/react.js"
|
|
39
|
+
},
|
|
40
|
+
"./next": {
|
|
41
|
+
"types": "./dist/next.d.ts",
|
|
42
|
+
"import": "./dist/next.js"
|
|
43
|
+
},
|
|
44
|
+
"./push": {
|
|
45
|
+
"types": "./dist/push.d.ts",
|
|
46
|
+
"import": "./dist/push.js"
|
|
47
|
+
},
|
|
36
48
|
"./realtime": {
|
|
37
49
|
"types": "./dist/realtime.d.ts",
|
|
38
50
|
"import": "./dist/realtime.js"
|