@makolabs/ripple 3.8.0 → 3.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure builders for Clerk user-API requests, extracted from
|
|
3
|
+
* `user-management.remote.ts` so the request shape is unit-testable — a
|
|
4
|
+
* `*.remote.ts` module cannot be imported in vitest (SvelteKit's plugin rejects
|
|
5
|
+
* any non-remote export).
|
|
6
|
+
*
|
|
7
|
+
* They also document the rule that caused minted API keys to silently never
|
|
8
|
+
* persist: Clerk deprecated sending `private_metadata` in the body of
|
|
9
|
+
* `PATCH /users/{id}` (it now returns 422 `form_param_deprecated`). User
|
|
10
|
+
* metadata must be written through the dedicated `PATCH /users/{id}/metadata`
|
|
11
|
+
* endpoint, which merges into the existing metadata.
|
|
12
|
+
*/
|
|
13
|
+
export interface ClerkRequest {
|
|
14
|
+
endpoint: string;
|
|
15
|
+
init: {
|
|
16
|
+
method: string;
|
|
17
|
+
body: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Build a request that persists `privateMetadata` on a Clerk user via the
|
|
22
|
+
* dedicated metadata endpoint. Clerk merges the provided keys into the user's
|
|
23
|
+
* existing private metadata.
|
|
24
|
+
*/
|
|
25
|
+
export declare function clerkMetadataPatch(userId: string, privateMetadata: Record<string, unknown>): ClerkRequest;
|
|
26
|
+
/**
|
|
27
|
+
* Build the body for a profile update (`PATCH /users/{id}`). Metadata is
|
|
28
|
+
* intentionally excluded — it must go through {@link clerkMetadataPatch}.
|
|
29
|
+
*/
|
|
30
|
+
export declare function clerkProfilePatchBody(userData: {
|
|
31
|
+
first_name?: string;
|
|
32
|
+
last_name?: string;
|
|
33
|
+
username?: string;
|
|
34
|
+
}): Record<string, string>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure builders for Clerk user-API requests, extracted from
|
|
3
|
+
* `user-management.remote.ts` so the request shape is unit-testable — a
|
|
4
|
+
* `*.remote.ts` module cannot be imported in vitest (SvelteKit's plugin rejects
|
|
5
|
+
* any non-remote export).
|
|
6
|
+
*
|
|
7
|
+
* They also document the rule that caused minted API keys to silently never
|
|
8
|
+
* persist: Clerk deprecated sending `private_metadata` in the body of
|
|
9
|
+
* `PATCH /users/{id}` (it now returns 422 `form_param_deprecated`). User
|
|
10
|
+
* metadata must be written through the dedicated `PATCH /users/{id}/metadata`
|
|
11
|
+
* endpoint, which merges into the existing metadata.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Build a request that persists `privateMetadata` on a Clerk user via the
|
|
15
|
+
* dedicated metadata endpoint. Clerk merges the provided keys into the user's
|
|
16
|
+
* existing private metadata.
|
|
17
|
+
*/
|
|
18
|
+
export function clerkMetadataPatch(userId, privateMetadata) {
|
|
19
|
+
return {
|
|
20
|
+
endpoint: `/users/${userId}/metadata`,
|
|
21
|
+
init: { method: 'PATCH', body: JSON.stringify({ private_metadata: privateMetadata }) }
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Build the body for a profile update (`PATCH /users/{id}`). Metadata is
|
|
26
|
+
* intentionally excluded — it must go through {@link clerkMetadataPatch}.
|
|
27
|
+
*/
|
|
28
|
+
export function clerkProfilePatchBody(userData) {
|
|
29
|
+
const body = {};
|
|
30
|
+
if (userData.first_name !== undefined)
|
|
31
|
+
body.first_name = userData.first_name;
|
|
32
|
+
if (userData.last_name !== undefined)
|
|
33
|
+
body.last_name = userData.last_name;
|
|
34
|
+
if (userData.username !== undefined && userData.username !== '') {
|
|
35
|
+
body.username = userData.username;
|
|
36
|
+
}
|
|
37
|
+
return body;
|
|
38
|
+
}
|
|
@@ -2,6 +2,7 @@ import { command } from '$app/server';
|
|
|
2
2
|
import { getRequestEvent } from '$app/server';
|
|
3
3
|
import { env } from '$env/dynamic/private';
|
|
4
4
|
import { building } from '$app/environment';
|
|
5
|
+
import { clerkMetadataPatch, clerkProfilePatchBody } from './clerk-requests.js';
|
|
5
6
|
const CLIENT_ID = env.CLIENT_ID;
|
|
6
7
|
const ORGANIZATION_ID = env.ALLOWED_ORG_ID;
|
|
7
8
|
if (!CLIENT_ID && !building) {
|
|
@@ -248,6 +249,16 @@ async function createUserPermissions(email, permissions, clientId = CLIENT_ID) {
|
|
|
248
249
|
log.trace('createUserPermissions', 'Result:', result);
|
|
249
250
|
return result;
|
|
250
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* Persist private metadata on a Clerk user via the dedicated metadata endpoint.
|
|
254
|
+
* Clerk deprecated `private_metadata` in the body of `PATCH /users/{id}` (it
|
|
255
|
+
* now returns 422 form_param_deprecated), which silently dropped minted API
|
|
256
|
+
* keys. Routes through `PATCH /users/{id}/metadata` (which merges) instead.
|
|
257
|
+
*/
|
|
258
|
+
async function writeClerkMetadata(userId, privateMetadata) {
|
|
259
|
+
const { endpoint, init } = clerkMetadataPatch(userId, privateMetadata);
|
|
260
|
+
return makeClerkRequest(endpoint, init);
|
|
261
|
+
}
|
|
251
262
|
export const getUsers = command('unchecked', async (options) => {
|
|
252
263
|
log.trace('getUsers', 'Called with options:', options);
|
|
253
264
|
try {
|
|
@@ -347,14 +358,9 @@ export const createUser = command('unchecked', async (userData) => {
|
|
|
347
358
|
const apiKey = adminKeyResult?.data?.key;
|
|
348
359
|
log.trace('createUser', 'Admin key created, has key:', !!apiKey);
|
|
349
360
|
if (adminKeyResult && apiKey) {
|
|
350
|
-
const updatedUser = await
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
private_metadata: {
|
|
354
|
-
...result.private_metadata,
|
|
355
|
-
mako_api_key: apiKey
|
|
356
|
-
}
|
|
357
|
-
})
|
|
361
|
+
const updatedUser = await writeClerkMetadata(result.id, {
|
|
362
|
+
...result.private_metadata,
|
|
363
|
+
mako_api_key: apiKey
|
|
358
364
|
});
|
|
359
365
|
// Ensure updatedUser is serializable
|
|
360
366
|
result = JSON.parse(JSON.stringify(updatedUser));
|
|
@@ -385,22 +391,19 @@ export const updateUser = command('unchecked', async (options) => {
|
|
|
385
391
|
const { userId, userData } = options;
|
|
386
392
|
log.trace('updateUser', 'Called for userId:', userId, 'fields:', Object.keys(userData));
|
|
387
393
|
try {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
394
|
+
// Profile fields and metadata live behind different Clerk endpoints —
|
|
395
|
+
// `private_metadata` is no longer accepted on PATCH /users/{id}.
|
|
396
|
+
const profileBody = clerkProfilePatchBody(userData);
|
|
397
|
+
log.trace('updateUser', 'Profile payload:', profileBody);
|
|
398
|
+
let result = Object.keys(profileBody).length > 0
|
|
399
|
+
? await makeClerkRequest(`/users/${userId}`, {
|
|
400
|
+
method: 'PATCH',
|
|
401
|
+
body: JSON.stringify(profileBody)
|
|
402
|
+
})
|
|
403
|
+
: await makeClerkRequest(`/users/${userId}`);
|
|
396
404
|
if (userData.private_metadata !== undefined) {
|
|
397
|
-
|
|
405
|
+
result = await writeClerkMetadata(userId, userData.private_metadata);
|
|
398
406
|
}
|
|
399
|
-
log.trace('updateUser', 'Update payload:', updateData);
|
|
400
|
-
let result = await makeClerkRequest(`/users/${userId}`, {
|
|
401
|
-
method: 'PATCH',
|
|
402
|
-
body: JSON.stringify(updateData)
|
|
403
|
-
});
|
|
404
407
|
// Ensure result is serializable
|
|
405
408
|
result = JSON.parse(JSON.stringify(result));
|
|
406
409
|
if (userData.permissions !== undefined) {
|
|
@@ -572,14 +575,9 @@ export const updateUserPermissions = command('unchecked', async (options) => {
|
|
|
572
575
|
const newKeyResult = await createUserPermissions(email, permissions);
|
|
573
576
|
const newApiKey = newKeyResult?.data?.key;
|
|
574
577
|
if (newApiKey) {
|
|
575
|
-
await
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
private_metadata: {
|
|
579
|
-
...(user.private_metadata || {}),
|
|
580
|
-
mako_api_key: newApiKey
|
|
581
|
-
}
|
|
582
|
-
})
|
|
578
|
+
await writeClerkMetadata(userId, {
|
|
579
|
+
...(user.private_metadata || {}),
|
|
580
|
+
mako_api_key: newApiKey
|
|
583
581
|
});
|
|
584
582
|
log.trace('updateUserPermissions', 'New key stored in Clerk metadata');
|
|
585
583
|
}
|
|
@@ -742,14 +740,9 @@ export const generateApiKey = command('unchecked', async (options) => {
|
|
|
742
740
|
currentUser = await makeClerkRequest(`/users/${options.userId}`);
|
|
743
741
|
}
|
|
744
742
|
if (currentUser) {
|
|
745
|
-
await
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
private_metadata: {
|
|
749
|
-
...(currentUser.private_metadata || {}),
|
|
750
|
-
mako_api_key: newApiKey
|
|
751
|
-
}
|
|
752
|
-
})
|
|
743
|
+
await writeClerkMetadata(options.userId, {
|
|
744
|
+
...(currentUser.private_metadata || {}),
|
|
745
|
+
mako_api_key: newApiKey
|
|
753
746
|
});
|
|
754
747
|
log.trace('generateApiKey', 'Clerk metadata updated with new key');
|
|
755
748
|
}
|
|
@@ -874,11 +867,9 @@ export const approveUser = command('unchecked', async (input) => {
|
|
|
874
867
|
if (!apiKey) {
|
|
875
868
|
throw new Error('Failed to mint API key during approval');
|
|
876
869
|
}
|
|
877
|
-
await
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
private_metadata: { ...(user.private_metadata || {}), mako_api_key: apiKey }
|
|
881
|
-
})
|
|
870
|
+
await writeClerkMetadata(input.userId, {
|
|
871
|
+
...(user.private_metadata || {}),
|
|
872
|
+
mako_api_key: apiKey
|
|
882
873
|
});
|
|
883
874
|
log.trace('approveUser', 'Approved and key issued');
|
|
884
875
|
return JSON.parse(JSON.stringify({ apiKey }));
|