@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.
@@ -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).pathname;
18
- const clientCssPath = () => new URL('../client/clerk-mirror.css', import.meta.url).pathname;
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();
@@ -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
- return async function clerkTwinFetch(request) {
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.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.1"
61
+ "@volter/world-core": "2.0.2"
62
62
  },
63
63
  "devDependencies": {
64
- "@volter/world-core": "2.0.1",
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",
@@ -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
  }
@@ -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).pathname;
19
- const clientCssPath = () => new URL('../client/clerk-mirror.css', import.meta.url).pathname;
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 →
@@ -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
- return async function clerkTwinFetch(request: Request): Promise<Response> {
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 }> {