@volter/twin-clerk 0.1.1 → 0.1.2
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/client/clerk-mirror.bundle.js +220 -223
- package/dist/src/clerk-events.js +2 -2
- package/dist/src/clerk-mirror-ui.js +3 -3
- package/dist/src/clerk-server.js +5 -3
- package/package.json +3 -3
- package/src/clerk-events.ts +2 -2
- package/src/clerk-mirror-ui.ts +3 -3
- package/src/clerk-server.ts +5 -3
package/dist/src/clerk-events.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { nodeBuiltin, worldNow } from '@volter/world-core';
|
|
1
|
+
import { nodeBuiltin, worldNow, deliveryTraceHeaders } from '@volter/world-core';
|
|
2
2
|
import { appDestination, appFetch } from '@volter/world-core/app-route';
|
|
3
3
|
import { worldEgressRefusal } from '@volter/world-core/network-policy';
|
|
4
4
|
function nodeCrypto() {
|
|
@@ -104,7 +104,7 @@ const httpDelivery = async (url, body, headers) => {
|
|
|
104
104
|
if (!appDestination(url) && worldEgressRefusal(url) !== null)
|
|
105
105
|
return; // the World's egress rule, the application's own hostnames reaching it inside the World: refused like an unreachable endpoint
|
|
106
106
|
try {
|
|
107
|
-
await appFetch(url, { method: 'POST', headers: { 'content-type': 'application/json', ...headers }, body });
|
|
107
|
+
await appFetch(url, { method: 'POST', headers: { 'content-type': 'application/json', ...headers, ...deliveryTraceHeaders() }, body });
|
|
108
108
|
}
|
|
109
109
|
catch {
|
|
110
110
|
/* fire-and-forget, like the real vendor */
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// pack's OWN fetch adapter (createClerkTwinFetch) as its API backend and reads every byte of
|
|
7
7
|
// state back over the wire, exactly as the browser client does.
|
|
8
8
|
import { readFile } from 'node:fs/promises';
|
|
9
|
-
import { bundleClient, fileResponse } from '@volter/world-core';
|
|
9
|
+
import { bundleClient, fileResponse, filePathOf } from '@volter/world-core';
|
|
10
10
|
import { serveHttp } from '@volter/world-core';
|
|
11
11
|
import { createClerkTwinFetch } from "./clerk-server.js";
|
|
12
12
|
// Resolved LAZILY (on first serve), not at module load: `new URL(..., import.meta.url)` at
|
|
@@ -14,8 +14,8 @@ import { createClerkTwinFetch } from "./clerk-server.js";
|
|
|
14
14
|
// `import.meta.url` is not a valid file base (e.g. workerd) even though the mirror UI is never
|
|
15
15
|
// served there. Computing them on demand keeps Node/Bun behavior identical while letting a
|
|
16
16
|
// serverless host import this module's barrel without a startup crash.
|
|
17
|
-
const clientEntryPath = () => new URL('../client/clerk-mirror.tsx', import.meta.url)
|
|
18
|
-
const clientCssPath = () => new URL('../client/clerk-mirror.css', import.meta.url)
|
|
17
|
+
const clientEntryPath = () => filePathOf(new URL('../client/clerk-mirror.tsx', import.meta.url));
|
|
18
|
+
const clientCssPath = () => filePathOf(new URL('../client/clerk-mirror.css', import.meta.url));
|
|
19
19
|
/** A user's display name: "First Last", else username, else primary email, else id. */
|
|
20
20
|
export function formatUserName(u) {
|
|
21
21
|
const name = [u?.first_name, u?.last_name].filter(Boolean).join(' ').trim();
|
package/dist/src/clerk-server.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// Personas are world state: pass `personas` (a JSON file of users with passwords) and the
|
|
8
8
|
// server seeds them as ordinary user rows at start — sign-in is a protocol, never a default.
|
|
9
9
|
// JSON bodies pass through to the handler. Writable by default; readOnly rejects writes (R4).
|
|
10
|
-
import { serveHttp } from '@volter/world-core';
|
|
10
|
+
import { runWithRequestTrace, serveHttp } from '@volter/world-core';
|
|
11
11
|
import { handleClerkTwinRequest } from "./clerk-twin.js";
|
|
12
12
|
import { worldNow, statefulTwinManifest, packAsset } from '@volter/world-core';
|
|
13
13
|
import { handleClerkFapiRequest } from "./clerk-fapi.js";
|
|
@@ -89,7 +89,9 @@ export function createClerkTwinFetch(options = {}) {
|
|
|
89
89
|
// the pack CONSTRUCTS on any host (workerd included) and only the local-CDN route itself needs
|
|
90
90
|
// Bun — until the dist rides a pack-asset seam (`TwinPack.assets`, the pack-asset seam), that route is the
|
|
91
91
|
// pack's one host-bound surface, not the whole pack.
|
|
92
|
-
|
|
92
|
+
// a request's W3C trace context scopes everything it writes and delivers (world-core trace-context)
|
|
93
|
+
return (request) => runWithRequestTrace(request, () => clerkTwinFetch(request));
|
|
94
|
+
async function clerkTwinFetch(request) {
|
|
93
95
|
await seeded;
|
|
94
96
|
const url = new URL(request.url);
|
|
95
97
|
// GET /twin — the discovery manifest (education inside the twin).
|
|
@@ -160,7 +162,7 @@ export function createClerkTwinFetch(options = {}) {
|
|
|
160
162
|
...(options.root !== undefined ? { root: options.root } : {}),
|
|
161
163
|
});
|
|
162
164
|
return new Response(JSON.stringify(out), { status, headers: { 'content-type': 'application/json', 'clerk-trace-id': 'trace_twin', ...cors } });
|
|
163
|
-
}
|
|
165
|
+
}
|
|
164
166
|
}
|
|
165
167
|
export async function createClerkTwinServer(options) {
|
|
166
168
|
const server = await serveHttp({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/twin-clerk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Local Clerk twin — a faithful, stateful local Clerk Backend API your real `@clerk/backend` SDK talks to unmodified. Users, sessions, orgs, real signed JWTs + a JWKS endpoint. Mirror, simulate, and fork. Built on @volter/world-core.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"twin",
|
|
@@ -58,10 +58,10 @@
|
|
|
58
58
|
"react-dom": "^19.2.7"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@volter/world-core": "2.0.
|
|
61
|
+
"@volter/world-core": "2.0.2"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@volter/world-core": "2.0.
|
|
64
|
+
"@volter/world-core": "2.0.2",
|
|
65
65
|
"@volter/world-tooling": "0.1.0",
|
|
66
66
|
"@clerk/backend": "^1.15.0",
|
|
67
67
|
"@types/bun": "^1.2.20",
|
package/src/clerk-events.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { nodeBuiltin, worldNow } from '@volter/world-core';
|
|
1
|
+
import { nodeBuiltin, worldNow, deliveryTraceHeaders } from '@volter/world-core';
|
|
2
2
|
import { appDestination, appFetch } from '@volter/world-core/app-route';
|
|
3
3
|
import { worldEgressRefusal } from '@volter/world-core/network-policy';
|
|
4
4
|
// Clerk webhook emission — svix-style signed webhooks on user/session/org events.
|
|
@@ -124,7 +124,7 @@ function svixMessageId(url: string, timestamp: number, body: string): string { l
|
|
|
124
124
|
const httpDelivery: ClerkWebhookDelivery = async (url, body, headers) => {
|
|
125
125
|
if (!appDestination(url) && worldEgressRefusal(url) !== null) return; // the World's egress rule, the application's own hostnames reaching it inside the World: refused like an unreachable endpoint
|
|
126
126
|
try {
|
|
127
|
-
await appFetch(url, { method: 'POST', headers: { 'content-type': 'application/json', ...headers }, body });
|
|
127
|
+
await appFetch(url, { method: 'POST', headers: { 'content-type': 'application/json', ...headers, ...deliveryTraceHeaders() }, body });
|
|
128
128
|
} catch {
|
|
129
129
|
/* fire-and-forget, like the real vendor */
|
|
130
130
|
}
|
package/src/clerk-mirror-ui.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// pack's OWN fetch adapter (createClerkTwinFetch) as its API backend and reads every byte of
|
|
7
7
|
// state back over the wire, exactly as the browser client does.
|
|
8
8
|
import { readFile } from 'node:fs/promises';
|
|
9
|
-
import { bundleClient, fileResponse } from '@volter/world-core';
|
|
9
|
+
import { bundleClient, fileResponse, filePathOf } from '@volter/world-core';
|
|
10
10
|
import { serveHttp } from '@volter/world-core';
|
|
11
11
|
import { createClerkTwinFetch } from './clerk-server.ts';
|
|
12
12
|
|
|
@@ -15,8 +15,8 @@ import { createClerkTwinFetch } from './clerk-server.ts';
|
|
|
15
15
|
// `import.meta.url` is not a valid file base (e.g. workerd) even though the mirror UI is never
|
|
16
16
|
// served there. Computing them on demand keeps Node/Bun behavior identical while letting a
|
|
17
17
|
// serverless host import this module's barrel without a startup crash.
|
|
18
|
-
const clientEntryPath = () => new URL('../client/clerk-mirror.tsx', import.meta.url)
|
|
19
|
-
const clientCssPath = () => new URL('../client/clerk-mirror.css', import.meta.url)
|
|
18
|
+
const clientEntryPath = () => filePathOf(new URL('../client/clerk-mirror.tsx', import.meta.url));
|
|
19
|
+
const clientCssPath = () => filePathOf(new URL('../client/clerk-mirror.css', import.meta.url));
|
|
20
20
|
|
|
21
21
|
// ---------------------------------------------------------------------------
|
|
22
22
|
// Pure, dependency-free render/format helpers. Framework-agnostic (plain data in →
|
package/src/clerk-server.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// Personas are world state: pass `personas` (a JSON file of users with passwords) and the
|
|
8
8
|
// server seeds them as ordinary user rows at start — sign-in is a protocol, never a default.
|
|
9
9
|
// JSON bodies pass through to the handler. Writable by default; readOnly rejects writes (R4).
|
|
10
|
-
import { serveHttp } from '@volter/world-core';
|
|
10
|
+
import { runWithRequestTrace, serveHttp } from '@volter/world-core';
|
|
11
11
|
import { handleClerkTwinRequest } from './clerk-twin.ts';
|
|
12
12
|
import { worldNow, statefulTwinManifest, packAsset } from '@volter/world-core';
|
|
13
13
|
import { handleClerkFapiRequest } from './clerk-fapi.ts';
|
|
@@ -97,7 +97,9 @@ export function createClerkTwinFetch(options: ClerkTwinFetchOptions = {}): (requ
|
|
|
97
97
|
// the pack CONSTRUCTS on any host (workerd included) and only the local-CDN route itself needs
|
|
98
98
|
// Bun — until the dist rides a pack-asset seam (`TwinPack.assets`, the pack-asset seam), that route is the
|
|
99
99
|
// pack's one host-bound surface, not the whole pack.
|
|
100
|
-
|
|
100
|
+
// a request's W3C trace context scopes everything it writes and delivers (world-core trace-context)
|
|
101
|
+
return (request: Request): Promise<Response> => runWithRequestTrace(request, () => clerkTwinFetch(request));
|
|
102
|
+
async function clerkTwinFetch(request: Request): Promise<Response> {
|
|
101
103
|
await seeded;
|
|
102
104
|
const url = new URL(request.url);
|
|
103
105
|
// GET /twin — the discovery manifest (education inside the twin).
|
|
@@ -162,7 +164,7 @@ export function createClerkTwinFetch(options: ClerkTwinFetchOptions = {}): (requ
|
|
|
162
164
|
...(options.root !== undefined ? { root: options.root } : {}),
|
|
163
165
|
});
|
|
164
166
|
return new Response(JSON.stringify(out), { status, headers: { 'content-type': 'application/json', 'clerk-trace-id': 'trace_twin', ...cors } });
|
|
165
|
-
}
|
|
167
|
+
}
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
export async function createClerkTwinServer(options: { root?: string; port?: number; readOnly?: boolean; personas?: Array<Record<string, unknown>> }): Promise<{ port: number; stop: () => void }> {
|