@lucern/mcp 0.3.0-alpha.12 → 0.3.0-alpha.14

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/gateway.js CHANGED
@@ -4,6 +4,7 @@ import { basename, extname } from 'path';
4
4
  import { randomUUID } from 'crypto';
5
5
  import { anyApi } from 'convex/server';
6
6
  import { ConvexHttpClient } from 'convex/browser';
7
+ import { Permit } from 'permitio';
7
8
 
8
9
  // ../contracts/src/types/reasoning-method.ts
9
10
  var REASONING_METHODS = [
@@ -1032,6 +1033,35 @@ defineTable({
1032
1033
  { kind: "index", name: "by_source", columns: ["source"] }
1033
1034
  ]
1034
1035
  });
1036
+ defineTable({
1037
+ name: "domainEvents",
1038
+ component: "kernel",
1039
+ category: "events",
1040
+ shape: z.object({
1041
+ "eventId": z.string(),
1042
+ "type": z.string(),
1043
+ "version": z.string(),
1044
+ "timestamp": z.number(),
1045
+ "tenantId": z.string().optional(),
1046
+ "workspaceId": z.string().optional(),
1047
+ "topicId": z.string(),
1048
+ "resourceId": z.string(),
1049
+ "resourceType": z.string(),
1050
+ "actorId": z.string(),
1051
+ "actorType": z.enum(["human", "agent", "service"]),
1052
+ "data": z.record(z.any()),
1053
+ "correlationId": z.string().optional(),
1054
+ "expiresAt": z.number()
1055
+ }),
1056
+ indices: [
1057
+ { kind: "index", name: "by_eventId", columns: ["eventId"] },
1058
+ { kind: "index", name: "by_topic_timestamp", columns: ["topicId", "timestamp"] },
1059
+ { kind: "index", name: "by_tenant_workspace_timestamp", columns: ["tenantId", "workspaceId", "timestamp"] },
1060
+ { kind: "index", name: "by_type_timestamp", columns: ["type", "timestamp"] },
1061
+ { kind: "index", name: "by_resource", columns: ["resourceType", "resourceId", "timestamp"] },
1062
+ { kind: "index", name: "by_expiresAt", columns: ["expiresAt"] }
1063
+ ]
1064
+ });
1035
1065
  defineTable({
1036
1066
  name: "beliefConfidence",
1037
1067
  component: "kernel",
@@ -4438,7 +4468,10 @@ defineTable({
4438
4468
  }),
4439
4469
  indices: [
4440
4470
  { kind: "index", name: "by_principalId", columns: ["principalId"] },
4471
+ { kind: "index", name: "by_provider_subject", columns: ["provider", "providerSubjectId"] },
4472
+ { kind: "index", name: "by_provider_project_subject", columns: ["provider", "providerProjectId", "providerSubjectId"] },
4441
4473
  { kind: "index", name: "by_tenant_provider_subject", columns: ["tenantId", "provider", "providerSubjectId"] },
4474
+ { kind: "index", name: "by_tenant_provider_project_subject", columns: ["tenantId", "provider", "providerProjectId", "providerSubjectId"] },
4442
4475
  {
4443
4476
  kind: "index",
4444
4477
  name: "by_tenant_provider_alias",
@@ -9411,7 +9444,7 @@ var IDENTITY_WHOAMI = {
9411
9444
  description: "Canonical identity summary for the current session",
9412
9445
  fields: {
9413
9446
  principalId: "string \u2014 canonical federated principal identifier",
9414
- principalType: "string \u2014 human, service, or agent",
9447
+ principalType: "string \u2014 human, service, agent, group, or external_viewer",
9415
9448
  tenantId: "string | undefined \u2014 resolved tenant scope",
9416
9449
  workspaceId: "string | undefined \u2014 resolved workspace scope",
9417
9450
  scopes: "string[] | undefined \u2014 granted scopes for this session",
@@ -9422,6 +9455,49 @@ var IDENTITY_WHOAMI = {
9422
9455
  ontologyPrimitive: "identity",
9423
9456
  tier: "workhorse"
9424
9457
  };
9458
+ var RESOLVE_INTERACTIVE_PRINCIPAL = {
9459
+ name: "resolve_interactive_principal",
9460
+ description: "Read the Permit-backed Lucern principal context for an authenticated Clerk user. Like `git config --get user.email` plus the repository ACL \u2014 resolves the identity alias into the canonical authorization subject.",
9461
+ parameters: {
9462
+ clerkId: {
9463
+ type: "string",
9464
+ description: "Authenticated Clerk subject (`sub`). Clerk proves identity only; it is not the authorization record."
9465
+ },
9466
+ tenantId: {
9467
+ type: "string",
9468
+ description: "Optional tenant scope. Omit only when the Clerk alias is globally unambiguous."
9469
+ },
9470
+ workspaceId: {
9471
+ type: "string",
9472
+ description: "Optional workspace scope. Required when the principal has access to multiple workspaces and no default can be inferred."
9473
+ },
9474
+ providerProjectId: {
9475
+ type: "string",
9476
+ description: "Optional Clerk project or provider instance id for tenants with multiple identity providers."
9477
+ }
9478
+ },
9479
+ required: ["clerkId"],
9480
+ response: {
9481
+ description: "Permit-backed Lucern principal context for tenant SDK bootstrap",
9482
+ fields: {
9483
+ principalId: "string \u2014 canonical Lucern principal identifier",
9484
+ principalType: "string \u2014 human, service, agent, group, or external_viewer",
9485
+ clerkId: "string \u2014 authenticated Clerk subject alias",
9486
+ tenantId: "string \u2014 resolved tenant scope",
9487
+ workspaceId: "string | null \u2014 resolved workspace scope",
9488
+ roles: "string[] \u2014 effective Permit roles",
9489
+ scopes: "string[] \u2014 effective scopes derived from Permit/control-plane projection",
9490
+ groupIds: "string[] \u2014 active Permit group memberships",
9491
+ principalStatus: "string \u2014 active, invited, suspended, disabled, revoked, or missing",
9492
+ tenantStatus: "string \u2014 projected tenant resource status",
9493
+ workspaceStatus: "string \u2014 projected workspace resource status",
9494
+ permit: "object \u2014 Permit subject, tenant, and optional workspace tuple"
9495
+ }
9496
+ },
9497
+ ownerModule: "control-plane",
9498
+ ontologyPrimitive: "identity",
9499
+ tier: "workhorse"
9500
+ };
9425
9501
  var COMPILE_CONTEXT = {
9426
9502
  name: "compile_context",
9427
9503
  description: "Compile a focused reasoning context. If topicId is omitted, Lucern resolves the best topic from the query. Like `git log --graph --decorate` for the reasoning substrate \u2014 returns the canonical Pillar 3 context pack through the public API shape.",
@@ -11324,6 +11400,7 @@ var MCP_TOOL_CONTRACTS = {
11324
11400
  update_worktree_targets: UPDATE_WORKTREE_TARGETS,
11325
11401
  update_worktree_metadata: UPDATE_WORKTREE_METADATA,
11326
11402
  identity_whoami: IDENTITY_WHOAMI,
11403
+ resolve_interactive_principal: RESOLVE_INTERACTIVE_PRINCIPAL,
11327
11404
  compile_context: COMPILE_CONTEXT,
11328
11405
  record_scope_learning: RECORD_SCOPE_LEARNING,
11329
11406
  pipeline_snapshot: PIPELINE_SNAPSHOT,
@@ -11441,6 +11518,7 @@ function entries(names, surfaceClass, surfaceIntent, surfaces, rationale) {
11441
11518
  var MCP_CORE_OPERATION_NAMES = [
11442
11519
  "compile_context",
11443
11520
  "identity_whoami",
11521
+ "resolve_interactive_principal",
11444
11522
  "check_permission",
11445
11523
  "filter_by_permission",
11446
11524
  "create_belief",
@@ -11994,7 +12072,13 @@ function surfaceContract(args) {
11994
12072
  scopes: args.scopes ?? [
11995
12073
  args.kind === "query" ? `${args.domain}.read` : `${args.domain}.write`
11996
12074
  ],
11997
- allowedPrincipalTypes: ["user", "service", "agent"]
12075
+ allowedPrincipalTypes: [
12076
+ "user",
12077
+ "service",
12078
+ "agent",
12079
+ "group",
12080
+ "external_viewer"
12081
+ ]
11998
12082
  },
11999
12083
  convex: args.convex,
12000
12084
  gateway: args.gateway,
@@ -12136,8 +12220,6 @@ var contextContracts = [
12136
12220
  args: observationContextArgs
12137
12221
  })
12138
12222
  ];
12139
-
12140
- // ../contracts/src/function-registry/identity.ts
12141
12223
  var withPrincipal = (input, context) => ({
12142
12224
  ...input,
12143
12225
  tenantId: input.tenantId ?? context.tenantId,
@@ -12163,6 +12245,28 @@ var identityContracts = [
12163
12245
  inputProjection: withPrincipal
12164
12246
  }
12165
12247
  }),
12248
+ surfaceContract({
12249
+ name: "resolve_interactive_principal",
12250
+ kind: "query",
12251
+ domain: "controlPlane",
12252
+ surfaceClass: "platform_public",
12253
+ method: "POST",
12254
+ path: "/control-plane/identity/resolve-interactive-principal",
12255
+ sdkNamespace: "controlPlane.identity",
12256
+ sdkMethod: "resolveInteractivePrincipal",
12257
+ summary: "Resolve an authenticated Clerk user into a Permit-backed Lucern principal context.",
12258
+ args: z.object({
12259
+ clerkId: z.string().min(1),
12260
+ tenantId: z.string().min(1).optional(),
12261
+ workspaceId: z.string().min(1).optional(),
12262
+ providerProjectId: z.string().min(1).optional()
12263
+ }),
12264
+ convex: {
12265
+ module: "identity",
12266
+ functionName: "resolveInteractivePrincipal",
12267
+ kind: "query"
12268
+ }
12269
+ }),
12166
12270
  surfaceContract({
12167
12271
  name: "check_permission",
12168
12272
  kind: "query",
@@ -16255,6 +16359,13 @@ var TENANT_BOOTSTRAP_TABLE_REQUIREMENTS = [
16255
16359
  copyMode: "none",
16256
16360
  description: "Deliberation sessions are created by tenant workflows."
16257
16361
  },
16362
+ {
16363
+ component: "kernel",
16364
+ table: "domainEvents",
16365
+ prepopulation: "runtime_log",
16366
+ copyMode: "none",
16367
+ description: "Domain event rows are append-only runtime audit/exhaust data."
16368
+ },
16258
16369
  {
16259
16370
  component: "kernel",
16260
16371
  table: "epistemicAudit",
@@ -23084,23 +23195,31 @@ async function resolveTaskEventTopicId(authContext, task, operation) {
23084
23195
  });
23085
23196
  }
23086
23197
  async function emitTaskEventFromGatewayAuth(authContext, args) {
23087
- return emitDomainEvent(
23088
- (reference, input) => authContext.convex.mutation(reference, input),
23089
- {
23090
- tenantId: authContext.tenantId,
23091
- workspaceId: authContext.workspaceId,
23092
- topicId: args.topicId,
23093
- type: args.type,
23094
- resourceId: args.resourceId,
23095
- resourceType: "task",
23096
- actorId: authContext.principalId ?? authContext.userId,
23097
- actorType: inferActorType({
23098
- authMode: authContext.authMode,
23099
- principalType: authContext.principalType
23100
- }),
23101
- data: args.data
23102
- }
23103
- );
23198
+ return authContext.convex.mutation(api.events.recordEvent, {
23199
+ tenantId: authContext.tenantId,
23200
+ workspaceId: authContext.workspaceId,
23201
+ topicId: args.topicId,
23202
+ type: args.type,
23203
+ resourceId: args.resourceId,
23204
+ resourceType: "task",
23205
+ actorId: authContext.principalId ?? authContext.userId,
23206
+ actorType: inferActorType({
23207
+ authMode: authContext.authMode,
23208
+ principalType: authContext.principalType
23209
+ }),
23210
+ data: args.data
23211
+ });
23212
+ }
23213
+ async function emitTaskEventBestEffortFromGatewayAuth(authContext, args) {
23214
+ try {
23215
+ await emitTaskEventFromGatewayAuth(authContext, args);
23216
+ } catch (error) {
23217
+ console.warn("[tasks] Task write succeeded but event emission failed.", {
23218
+ taskId: args.resourceId,
23219
+ eventType: args.type,
23220
+ error: error instanceof Error ? error.message : String(error)
23221
+ });
23222
+ }
23104
23223
  }
23105
23224
  function gatewayIdempotencyArgs(authContext, options) {
23106
23225
  {
@@ -23197,7 +23316,7 @@ async function createTaskFromGatewayAuth(authContext, input, options) {
23197
23316
  ...input,
23198
23317
  topicId: resolvedTopic.topicId
23199
23318
  });
23200
- await emitTaskEventFromGatewayAuth(authContext, {
23319
+ await emitTaskEventBestEffortFromGatewayAuth(authContext, {
23201
23320
  topicId: payload.topicId ?? resolvedTopic.topicId,
23202
23321
  type: "task.created",
23203
23322
  resourceId: payload.id,
@@ -23225,7 +23344,7 @@ async function updateTaskFromGatewayAuth(authContext, input, options) {
23225
23344
  payload,
23226
23345
  "update"
23227
23346
  );
23228
- await emitTaskEventFromGatewayAuth(authContext, {
23347
+ await emitTaskEventBestEffortFromGatewayAuth(authContext, {
23229
23348
  topicId,
23230
23349
  type: "task.updated",
23231
23350
  resourceId: payload.id,
@@ -23252,7 +23371,7 @@ async function completeTaskFromGatewayAuth(authContext, input, options) {
23252
23371
  payload,
23253
23372
  "complete"
23254
23373
  );
23255
- await emitTaskEventFromGatewayAuth(authContext, {
23374
+ await emitTaskEventBestEffortFromGatewayAuth(authContext, {
23256
23375
  topicId,
23257
23376
  type: "task.completed",
23258
23377
  resourceId: payload.id,
@@ -25732,7 +25851,7 @@ function handleEventsError(error, fallbackMessage, correlationId, policyTraceId)
25732
25851
  }
25733
25852
  async function handleEventsList(args) {
25734
25853
  try {
25735
- const payload = await args.authContext.convex.query("events:listEvents", {
25854
+ const payload = await args.authContext.convex.query(api.events.listEvents, {
25736
25855
  tenantId: args.authContext.tenantId,
25737
25856
  workspaceId: args.authContext.workspaceId,
25738
25857
  topicId: args.query.topicId,
@@ -25758,7 +25877,7 @@ async function handleEventsList(args) {
25758
25877
  async function handleEventsReplay(args) {
25759
25878
  try {
25760
25879
  const payload = await args.authContext.convex.mutation(
25761
- "events:replayEvents",
25880
+ api.events.replayEvents,
25762
25881
  {
25763
25882
  tenantId: args.authContext.tenantId,
25764
25883
  workspaceId: args.authContext.workspaceId,
@@ -27077,22 +27196,69 @@ function readTenantKeyFromValue(value) {
27077
27196
  const record = asRecord25(value);
27078
27197
  return readString27(record.key) ?? readString27(record.tenant) ?? readString27(record.tenantKey) ?? readString27(record.tenant_id);
27079
27198
  }
27199
+ function hasTenantIdentifier(value) {
27200
+ if (typeof value === "string" && value.trim()) {
27201
+ return true;
27202
+ }
27203
+ const record = asRecord25(value);
27204
+ return Boolean(
27205
+ readString27(record.key) ?? readString27(record.tenant) ?? readString27(record.tenantKey) ?? readString27(record.tenant_key) ?? readString27(record.tenant_id) ?? readString27(record.id)
27206
+ );
27207
+ }
27080
27208
  function extractPermitWebhookTenantKeys(body) {
27081
27209
  const record = asRecord25(body);
27082
27210
  const candidates = [
27083
27211
  record.tenant,
27084
27212
  record.tenantKey,
27213
+ record.tenant_key,
27214
+ asRecord25(record.data).tenant,
27215
+ asRecord25(record.data).tenantKey,
27216
+ asRecord25(record.data).tenant_key,
27217
+ asRecord25(record.object).tenant,
27218
+ asRecord25(record.object).tenantKey,
27219
+ asRecord25(record.object).tenant_key,
27220
+ asRecord25(record.resource_instance).tenant,
27221
+ asRecord25(record.resource_instance).tenantKey,
27222
+ asRecord25(record.resource_instance).tenant_key,
27223
+ asRecord25(record.access_request_details).tenant,
27224
+ asRecord25(record.access_request_details).tenantKey,
27225
+ asRecord25(record.access_request_details).tenant_key,
27226
+ asRecord25(asRecord25(record.data).access_request_details).tenant,
27227
+ asRecord25(asRecord25(record.data).access_request_details).tenantKey,
27228
+ asRecord25(asRecord25(record.data).access_request_details).tenant_key
27229
+ ];
27230
+ const tenantKeys = candidates.map(readTenantKeyFromValue).filter((entry) => Boolean(entry));
27231
+ return [...new Set(tenantKeys)];
27232
+ }
27233
+ function hasPermitWebhookTenantScope(body) {
27234
+ const record = asRecord25(body);
27235
+ const candidates = [
27236
+ record.tenant,
27237
+ record.tenantKey,
27238
+ record.tenant_key,
27085
27239
  record.tenant_id,
27086
27240
  asRecord25(record.data).tenant,
27087
27241
  asRecord25(record.data).tenantKey,
27242
+ asRecord25(record.data).tenant_key,
27088
27243
  asRecord25(record.data).tenant_id,
27089
27244
  asRecord25(record.object).tenant,
27090
27245
  asRecord25(record.object).tenantKey,
27246
+ asRecord25(record.object).tenant_key,
27091
27247
  asRecord25(record.object).tenant_id,
27092
- asRecord25(record.resource_instance).tenant
27248
+ asRecord25(record.resource_instance).tenant,
27249
+ asRecord25(record.resource_instance).tenantKey,
27250
+ asRecord25(record.resource_instance).tenant_key,
27251
+ asRecord25(record.resource_instance).tenant_id,
27252
+ asRecord25(record.access_request_details).tenant,
27253
+ asRecord25(record.access_request_details).tenantKey,
27254
+ asRecord25(record.access_request_details).tenant_key,
27255
+ asRecord25(record.access_request_details).tenant_id,
27256
+ asRecord25(asRecord25(record.data).access_request_details).tenant,
27257
+ asRecord25(asRecord25(record.data).access_request_details).tenantKey,
27258
+ asRecord25(asRecord25(record.data).access_request_details).tenant_key,
27259
+ asRecord25(asRecord25(record.data).access_request_details).tenant_id
27093
27260
  ];
27094
- const tenantKeys = candidates.map(readTenantKeyFromValue).filter((entry) => Boolean(entry));
27095
- return [...new Set(tenantKeys)];
27261
+ return candidates.some(hasTenantIdentifier);
27096
27262
  }
27097
27263
  function summarizePermitWebhookEvent(body) {
27098
27264
  const record = asRecord25(body);
@@ -27160,7 +27326,8 @@ async function handlePermitProjectionWebhook(args) {
27160
27326
  try {
27161
27327
  const event = summarizePermitWebhookEvent(args.body);
27162
27328
  const tenantKeys = extractPermitWebhookTenantKeys(args.body);
27163
- if (tenantKeys.length === 0) {
27329
+ const hasTenantScope = hasPermitWebhookTenantScope(args.body);
27330
+ if (tenantKeys.length === 0 && !hasTenantScope) {
27164
27331
  return successResponse(
27165
27332
  {
27166
27333
  acknowledged: true,
@@ -27178,7 +27345,7 @@ async function handlePermitProjectionWebhook(args) {
27178
27345
  const receipt = await client.action(mcApi.permitProjectionActions.reconcile, {
27179
27346
  mode: "apply",
27180
27347
  trigger: "permit_webhook",
27181
- tenantKeys,
27348
+ tenantKeys: tenantKeys.length > 0 ? tenantKeys : void 0,
27182
27349
  environments: ["dev", "staging", "prod"],
27183
27350
  componentPath: "controlPlane",
27184
27351
  webhookSecret: readSecret(),
@@ -27202,37 +27369,1119 @@ async function handlePermitProjectionWebhook(args) {
27202
27369
  );
27203
27370
  }
27204
27371
  }
27372
+ var mcApi2 = anyApi;
27373
+ var mcClientCache2 = {
27374
+ value: null
27375
+ };
27376
+ var permitClientCache = {
27377
+ value: null
27378
+ };
27379
+ var permitClientFactory = null;
27380
+ var SYSTEM_ACTOR_ID = "clerk:system";
27381
+ var SIGNATURE_TOLERANCE_SECONDS = 300;
27382
+ var USER_EVENTS = /* @__PURE__ */ new Set([
27383
+ "user.created",
27384
+ "user.updated",
27385
+ "user.deleted"
27386
+ ]);
27387
+ var MEMBERSHIP_EVENTS = /* @__PURE__ */ new Set([
27388
+ "organizationMembership.created",
27389
+ "organizationMembership.updated",
27390
+ "organizationMembership.deleted"
27391
+ ]);
27392
+ var INVITATION_EVENTS = /* @__PURE__ */ new Set([
27393
+ "organizationInvitation.created",
27394
+ "organizationInvitation.accepted",
27395
+ "organizationInvitation.revoked"
27396
+ ]);
27397
+ var ORGANIZATION_LIFECYCLE_EVENTS = /* @__PURE__ */ new Set([
27398
+ "organization.created",
27399
+ "organization.updated",
27400
+ "organization.deleted"
27401
+ ]);
27402
+ var PERMIT_MEMBERSHIP_ROLES = /* @__PURE__ */ new Set([
27403
+ "tenant_admin",
27404
+ "viewer",
27405
+ "editor",
27406
+ "auditor",
27407
+ "service_agent",
27408
+ "platform_admin",
27409
+ "workspace_admin"
27410
+ ]);
27411
+ var CLERK_WEBHOOK_SECRETS = [
27412
+ "LUCERN_CLERK_WEBHOOK_SECRET",
27413
+ "CLERK_WEBHOOK_SECRET",
27414
+ "CLERK_WEBHOOK_SIGNING_SECRET"
27415
+ ];
27416
+ function isRecord8(value) {
27417
+ return value !== null && typeof value === "object" && !Array.isArray(value);
27418
+ }
27419
+ function readString28(value) {
27420
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
27421
+ }
27422
+ function readNumber18(value) {
27423
+ if (typeof value === "number" && Number.isFinite(value)) {
27424
+ return value;
27425
+ }
27426
+ if (typeof value === "string" && value.trim()) {
27427
+ const parsed = Number(value);
27428
+ return Number.isFinite(parsed) ? parsed : void 0;
27429
+ }
27430
+ return void 0;
27431
+ }
27432
+ var PERMIT_USER_KEY_PATTERN = /^[A-Za-z0-9|@+\-._]+$/;
27433
+ var PERMIT_USER_KEY_ESCAPE_SENTINEL = "|";
27434
+ function asRecord26(value) {
27435
+ return isRecord8(value) ? value : {};
27436
+ }
27437
+ function asArray(value) {
27438
+ return Array.isArray(value) ? value : [];
27439
+ }
27440
+ function encodeBase64(bytes) {
27441
+ const buffer = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
27442
+ let binary = "";
27443
+ for (const value of buffer) {
27444
+ binary += String.fromCharCode(value);
27445
+ }
27446
+ return btoa(binary);
27447
+ }
27448
+ function permitUserKeyForPrincipalId(principalId) {
27449
+ const trimmed = principalId.trim();
27450
+ if (PERMIT_USER_KEY_PATTERN.test(trimmed) && !trimmed.includes(PERMIT_USER_KEY_ESCAPE_SENTINEL)) {
27451
+ return trimmed;
27452
+ }
27453
+ return Array.from(trimmed).map(
27454
+ (character) => PERMIT_USER_KEY_PATTERN.test(character) && character !== PERMIT_USER_KEY_ESCAPE_SENTINEL ? character : `${PERMIT_USER_KEY_ESCAPE_SENTINEL}${character.codePointAt(0)?.toString(16) ?? "0"}${PERMIT_USER_KEY_ESCAPE_SENTINEL}`
27455
+ ).join("");
27456
+ }
27457
+ function compactRecord5(value) {
27458
+ return Object.fromEntries(
27459
+ Object.entries(value).filter(([, entry]) => entry !== void 0)
27460
+ );
27461
+ }
27462
+ function statusCodeFromError(error) {
27463
+ if (!error || typeof error !== "object") {
27464
+ return void 0;
27465
+ }
27466
+ const record = error;
27467
+ return numericStatus(record.status) ?? numericStatus(record.statusCode) ?? numericStatus(record.response?.status) ?? numericStatus(record.cause?.response?.status);
27468
+ }
27469
+ function numericStatus(value) {
27470
+ if (typeof value === "number" && Number.isFinite(value)) {
27471
+ return value;
27472
+ }
27473
+ if (typeof value === "string") {
27474
+ const parsed = Number(value);
27475
+ return Number.isFinite(parsed) ? parsed : void 0;
27476
+ }
27477
+ return void 0;
27478
+ }
27479
+ function isNotFound(error) {
27480
+ return statusCodeFromError(error) === 404 || String(error?.message ?? "").includes("404");
27481
+ }
27482
+ function isConflict(error) {
27483
+ return statusCodeFromError(error) === 409 || String(error?.message ?? "").includes("409");
27484
+ }
27485
+ function readRoleAssignments(value) {
27486
+ if (!Array.isArray(value)) {
27487
+ const record = isRecord8(value) ? value : {};
27488
+ if (Array.isArray(record.data)) {
27489
+ return record.data.filter(isRecord8);
27490
+ }
27491
+ if (Array.isArray(record.results)) {
27492
+ return record.results.filter(isRecord8);
27493
+ }
27494
+ return [];
27495
+ }
27496
+ return value.filter(isRecord8);
27497
+ }
27498
+ function roleAssignmentResourceInstance(assignment) {
27499
+ return readString28(assignment.resource_instance) ?? readString28(assignment.resourceInstance) ?? readString28(assignment.resource_instance_id) ?? readString28(assignment.resourceInstanceId);
27500
+ }
27501
+ function isTenantScopedRoleAssignment(assignment) {
27502
+ return !roleAssignmentResourceInstance(assignment);
27503
+ }
27504
+ function createPermitClient() {
27505
+ const token = readString28(process.env.LUCERN_PERMIT_API_KEY) ?? readString28(process.env.PERMIT_API_KEY);
27506
+ const pdpUrl = readString28(process.env.LUCERN_PERMIT_PDP_URL) ?? readString28(process.env.PERMIT_PDP_URL);
27507
+ const apiUrl = readString28(process.env.LUCERN_PERMIT_API_URL) ?? readString28(process.env.PERMIT_API_URL);
27508
+ if (!token || !pdpUrl) {
27509
+ throw {
27510
+ status: 502,
27511
+ code: "UPSTREAM_ERROR",
27512
+ message: "Permit projection is not configured. Set LUCERN_PERMIT_API_KEY and LUCERN_PERMIT_PDP_URL."
27513
+ };
27514
+ }
27515
+ return new Permit({
27516
+ token,
27517
+ pdp: pdpUrl,
27518
+ ...apiUrl ? { apiUrl } : {},
27519
+ throwOnError: true
27520
+ });
27521
+ }
27522
+ function getPermitClient() {
27523
+ if (permitClientCache.value) {
27524
+ return permitClientCache.value;
27525
+ }
27526
+ if (permitClientFactory) {
27527
+ permitClientCache.value = permitClientFactory();
27528
+ return permitClientCache.value;
27529
+ }
27530
+ permitClientCache.value = createPermitClient();
27531
+ return permitClientCache.value;
27532
+ }
27533
+ var __testOnly = {
27534
+ setPermitClientFactory(factory) {
27535
+ permitClientFactory = factory;
27536
+ permitClientCache.value = null;
27537
+ }
27538
+ };
27539
+ async function upsertPermitTenant(args) {
27540
+ const permit = getPermitClient();
27541
+ const tenantPayload = {
27542
+ name: args.tenantName ?? args.tenantKey,
27543
+ attributes: compactRecord5({
27544
+ clerkOrganizationId: args.clerkOrganizationId,
27545
+ clerkOrganizationSlug: args.clerkOrganizationSlug,
27546
+ mcTenantKey: args.tenantKey,
27547
+ sourceType: "organization",
27548
+ sourceEvent: args.eventType,
27549
+ eventAt: args.eventAt,
27550
+ actorId: args.actorId
27551
+ })
27552
+ };
27553
+ try {
27554
+ return await permit.api.tenants.update(args.tenantKey, tenantPayload);
27555
+ } catch (error) {
27556
+ if (!isNotFound(error)) {
27557
+ throw error;
27558
+ }
27559
+ }
27560
+ return await permit.api.tenants.create({
27561
+ key: args.tenantKey,
27562
+ ...tenantPayload
27563
+ });
27564
+ }
27565
+ async function syncPermitUser(args) {
27566
+ const permit = getPermitClient();
27567
+ return await permit.api.users.sync({
27568
+ key: permitUserKeyForPrincipalId(args.userId),
27569
+ email: args.email,
27570
+ attributes: compactRecord5({
27571
+ sourceType: "clerk_webhook_user",
27572
+ sourceEvent: args.eventType,
27573
+ clerkStatus: args.eventType,
27574
+ clerkDisplayName: args.displayName,
27575
+ eventAt: args.eventAt,
27576
+ actorId: args.actorId
27577
+ })
27578
+ });
27579
+ }
27580
+ async function upsertPermitTenantMembershipRole(args) {
27581
+ const permit = getPermitClient();
27582
+ const permitUserId = permitUserKeyForPrincipalId(args.userId);
27583
+ const existing = readRoleAssignments(
27584
+ await permit.api.roleAssignments.list({
27585
+ user: permitUserId,
27586
+ tenant: args.tenantKey,
27587
+ perPage: 100
27588
+ })
27589
+ );
27590
+ await Promise.all(
27591
+ existing.map((assignment2) => {
27592
+ const role = readString28(assignment2.role);
27593
+ if (!role || !PERMIT_MEMBERSHIP_ROLES.has(role)) {
27594
+ return Promise.resolve();
27595
+ }
27596
+ if (!isTenantScopedRoleAssignment(assignment2)) {
27597
+ return Promise.resolve();
27598
+ }
27599
+ if (role === args.role) {
27600
+ return Promise.resolve();
27601
+ }
27602
+ return unassignPermitTenantMembershipRole({
27603
+ permit,
27604
+ permitUserId,
27605
+ tenant: args.tenantKey,
27606
+ role
27607
+ });
27608
+ })
27609
+ );
27610
+ const assignment = {
27611
+ user: permitUserId,
27612
+ role: args.role,
27613
+ tenant: args.tenantKey
27614
+ };
27615
+ try {
27616
+ return await permit.api.roleAssignments.assign(assignment);
27617
+ } catch (error) {
27618
+ if (isConflict(error)) {
27619
+ return { alreadyAssigned: true };
27620
+ }
27621
+ throw error;
27622
+ }
27623
+ }
27624
+ async function unassignPermitTenantMembershipRole(args) {
27625
+ const api2 = args.permit.api;
27626
+ const assignment = {
27627
+ user: args.permitUserId,
27628
+ role: args.role,
27629
+ tenant: args.tenant,
27630
+ ...args.resourceInstance ? { resource_instance: args.resourceInstance } : {}
27631
+ };
27632
+ if (typeof api2.roleAssignments?.unassign === "function") {
27633
+ return await api2.roleAssignments.unassign(assignment);
27634
+ }
27635
+ if (typeof api2.unassignRole === "function") {
27636
+ return await api2.unassignRole(assignment);
27637
+ }
27638
+ if (typeof api2.users?.unassignRole === "function") {
27639
+ return await api2.users.unassignRole({
27640
+ user: args.permitUserId,
27641
+ role: args.role,
27642
+ tenant: args.tenant
27643
+ });
27644
+ }
27645
+ throw new Error("Permit SDK does not expose an unassignRole method");
27646
+ }
27647
+ async function revokePermitTenantMembershipRoles(args) {
27648
+ const permit = getPermitClient();
27649
+ const permitUserId = permitUserKeyForPrincipalId(args.userId);
27650
+ const assignments = readRoleAssignments(
27651
+ await permit.api.roleAssignments.list({
27652
+ user: permitUserId,
27653
+ tenant: args.tenantKey,
27654
+ perPage: 100
27655
+ })
27656
+ );
27657
+ const membershipRoles = assignments.filter(
27658
+ (assignment) => isTenantScopedRoleAssignment(assignment) && PERMIT_MEMBERSHIP_ROLES.has(readString28(assignment.role) ?? "")
27659
+ );
27660
+ await Promise.all(
27661
+ membershipRoles.map((assignment) => {
27662
+ const role = readString28(assignment.role);
27663
+ if (!role) {
27664
+ return Promise.resolve();
27665
+ }
27666
+ return unassignPermitTenantMembershipRole({
27667
+ permit,
27668
+ permitUserId,
27669
+ tenant: args.tenantKey,
27670
+ role
27671
+ });
27672
+ })
27673
+ );
27674
+ }
27675
+ function normalizeBase64(value) {
27676
+ return value.replace(/-/g, "+").replace(/_/g, "/");
27677
+ }
27678
+ function maybeBase64(value) {
27679
+ if (!value || value.length < 16) {
27680
+ return false;
27681
+ }
27682
+ if (value.length % 4 === 1) {
27683
+ return false;
27684
+ }
27685
+ return /^[A-Za-z0-9+/=_-]+$/.test(value);
27686
+ }
27687
+ function decodeBase64OrRaw(value) {
27688
+ if (!value) {
27689
+ return new Uint8Array();
27690
+ }
27691
+ const trimmed = value.trim();
27692
+ const secretMaterial = trimmed.startsWith("whsec_") ? trimmed.slice("whsec_".length) : trimmed;
27693
+ const candidate = normalizeBase64(secretMaterial);
27694
+ if (!maybeBase64(candidate)) {
27695
+ return new TextEncoder().encode(secretMaterial);
27696
+ }
27697
+ try {
27698
+ const binary = atob(candidate);
27699
+ return Uint8Array.from(binary, (entry) => entry.charCodeAt(0));
27700
+ } catch {
27701
+ return new TextEncoder().encode(secretMaterial);
27702
+ }
27703
+ }
27704
+ function readSigningSecret(env = process.env) {
27705
+ for (const key of CLERK_WEBHOOK_SECRETS) {
27706
+ const value = readString28(env[key]);
27707
+ if (value) {
27708
+ return value;
27709
+ }
27710
+ }
27711
+ return void 0;
27712
+ }
27713
+ function parseSvixSignatures(header) {
27714
+ return header.split(",").map((entry) => entry.trim()).filter(Boolean).flatMap((entry) => {
27715
+ if (entry.startsWith("v1=")) {
27716
+ return [entry.slice("v1=".length)];
27717
+ }
27718
+ return [];
27719
+ }).filter(Boolean);
27720
+ }
27721
+ function parseWebhookHeaders(headers) {
27722
+ const secret = readSigningSecret();
27723
+ const webhookId = headers.get("svix-id");
27724
+ const timestamp = headers.get("svix-timestamp");
27725
+ const signatureHeader = headers.get("svix-signature");
27726
+ if (!secret || !webhookId || !timestamp || !signatureHeader) {
27727
+ return null;
27728
+ }
27729
+ return {
27730
+ webhookId,
27731
+ timestamp,
27732
+ signatures: parseSvixSignatures(signatureHeader),
27733
+ secret
27734
+ };
27735
+ }
27736
+ function safeEquals(left, right) {
27737
+ if (left.length !== right.length) {
27738
+ return false;
27739
+ }
27740
+ let diff = 0;
27741
+ for (let index = 0; index < left.length; index += 1) {
27742
+ diff |= left.charCodeAt(index) ^ right.charCodeAt(index);
27743
+ }
27744
+ return diff === 0;
27745
+ }
27746
+ async function verifyClerkSignature(args) {
27747
+ const parsed = parseWebhookHeaders(args.headers);
27748
+ if (!parsed) {
27749
+ return "missing_headers_or_secret";
27750
+ }
27751
+ const signatureTimestamp = readNumber18(parsed.timestamp);
27752
+ if (!signatureTimestamp) {
27753
+ return "malformed_timestamp";
27754
+ }
27755
+ const nowSeconds = Math.floor(Date.now() / 1e3);
27756
+ if (Math.abs(nowSeconds - signatureTimestamp) > SIGNATURE_TOLERANCE_SECONDS) {
27757
+ return "signature_expired";
27758
+ }
27759
+ const message = `${parsed.webhookId}.${parsed.timestamp}.${args.body}`;
27760
+ const keyBytes = decodeBase64OrRaw(parsed.secret);
27761
+ const key = await crypto.subtle.importKey(
27762
+ "raw",
27763
+ keyBytes,
27764
+ { name: "HMAC", hash: "SHA-256" },
27765
+ false,
27766
+ ["sign"]
27767
+ );
27768
+ const computed = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(message));
27769
+ const computedSignature = encodeBase64(computed);
27770
+ return parsed.signatures.some((candidate) => safeEquals(candidate, computedSignature)) || "signature_mismatch";
27771
+ }
27772
+ function extractClerkActorId(payload) {
27773
+ const event = asRecord26(payload);
27774
+ const data = asRecord26(event.data);
27775
+ return readString28(event.actor_id) || readString28(asRecord26(event.actor).id) || readString28(data.actor_id) || readString28(asRecord26(data.actor).id) || readString28(data.created_by) || readString28(asRecord26(data.public_user_data).user_id) || SYSTEM_ACTOR_ID;
27776
+ }
27777
+ function extractUserData(data) {
27778
+ const user = asRecord26(data.user);
27779
+ if (Object.keys(user).length > 0) {
27780
+ return user;
27781
+ }
27782
+ const publicUser = asRecord26(data.public_user_data);
27783
+ if (Object.keys(publicUser).length > 0) {
27784
+ return publicUser;
27785
+ }
27786
+ return data;
27787
+ }
27788
+ function extractOrganizationIds(data) {
27789
+ const organization = asRecord26(data.organization);
27790
+ return {
27791
+ organizationId: readString28(data.organization_id) || readString28(data.id) || readString28(organization.id),
27792
+ organizationSlug: readString28(data.organization_slug) || readString28(data.slug) || readString28(organization.slug)
27793
+ };
27794
+ }
27795
+ function readPrimaryEmail(userData) {
27796
+ const direct = readString28(userData.primary_email_address) || readString28(userData.email) || readString28(userData.emailAddress);
27797
+ if (direct) {
27798
+ return direct;
27799
+ }
27800
+ for (const entry of asArray(userData.email_addresses)) {
27801
+ const row = asRecord26(entry);
27802
+ const value = readString28(row.email_address) || readString28(row.emailAddress) || readString28(row.address);
27803
+ if (value) {
27804
+ return value;
27805
+ }
27806
+ }
27807
+ return void 0;
27808
+ }
27809
+ function readDisplayName(userData) {
27810
+ const first = readString28(userData.first_name) || readString28(userData.firstName);
27811
+ const last = readString28(userData.last_name) || readString28(userData.lastName);
27812
+ if (first || last) {
27813
+ return [first, last].filter(Boolean).join(" ");
27814
+ }
27815
+ return readString28(userData.username) || readString28(userData.name);
27816
+ }
27817
+ function normalizeRole(value) {
27818
+ const normalized = readString28(value)?.toLowerCase() ?? "viewer";
27819
+ if (normalized === "admin" || normalized === "owner" || normalized === "org:admin") {
27820
+ return "tenant_admin";
27821
+ }
27822
+ if (normalized === "editor" || normalized === "viewer" || normalized === "auditor" || normalized === "service_agent" || normalized === "platform_admin" || normalized === "tenant_admin" || normalized === "workspace_admin") {
27823
+ return normalized;
27824
+ }
27825
+ if (normalized === "basic_member" || normalized === "org:member") {
27826
+ return "viewer";
27827
+ }
27828
+ return "viewer";
27829
+ }
27830
+ function buildWebhookMetadata(args) {
27831
+ return {
27832
+ source: "clerk_webhook",
27833
+ eventType: args.eventType,
27834
+ eventId: args.eventId,
27835
+ eventAt: args.eventAt,
27836
+ actorId: args.actorId,
27837
+ ...args.extra
27838
+ };
27839
+ }
27840
+ function extractOrganizationName(organization) {
27841
+ return readString28(organization.name) || readString28(organization.slug) || readString28(organization.title);
27842
+ }
27843
+ async function getMasterControlConvexClient2() {
27844
+ if (mcClientCache2.value) {
27845
+ return mcClientCache2.value;
27846
+ }
27847
+ const convexUrl = readString28(process.env.CONVEX_MC_URL);
27848
+ const deployKey = readString28(process.env.CONVEX_MC_DEPLOY_KEY);
27849
+ if (!convexUrl || !deployKey) {
27850
+ throw new Error(
27851
+ "Master Control is not configured. Set CONVEX_MC_URL and CONVEX_MC_DEPLOY_KEY."
27852
+ );
27853
+ }
27854
+ const client = new ConvexHttpClient(convexUrl);
27855
+ client.setAdminAuth(
27856
+ deployKey
27857
+ );
27858
+ mcClientCache2.value = client;
27859
+ return client;
27860
+ }
27861
+ async function resolveTenantByOrgSlug(args) {
27862
+ if (!args.organizationSlug) {
27863
+ return void 0;
27864
+ }
27865
+ const tenant = await args.client.query(mcApi2.tenants.getBySlug, {
27866
+ slug: args.organizationSlug
27867
+ });
27868
+ if (!tenant || !isRecord8(tenant)) {
27869
+ return void 0;
27870
+ }
27871
+ const tenantId = readString28(tenant._id);
27872
+ const tenantSlug = readString28(tenant.slug);
27873
+ if (!tenantId || !tenantSlug) {
27874
+ return void 0;
27875
+ }
27876
+ return { tenantId, tenantSlug };
27877
+ }
27878
+ function webhookError(code, status, message, correlationId, policyTraceId, details) {
27879
+ return errorResponse({
27880
+ code,
27881
+ status,
27882
+ message,
27883
+ correlationId,
27884
+ policyTraceId,
27885
+ details
27886
+ });
27887
+ }
27888
+ function handleClerkWebhookError(error, correlationId, policyTraceId) {
27889
+ const resolved = resolveServerCoreError(error, "Failed to reconcile Clerk webhook.");
27890
+ return errorResponse({
27891
+ code: resolved.code,
27892
+ message: resolved.message,
27893
+ status: resolved.status,
27894
+ correlationId,
27895
+ policyTraceId,
27896
+ invariant: resolved.invariant,
27897
+ suggestion: resolved.suggestion,
27898
+ details: resolved.details
27899
+ });
27900
+ }
27901
+ async function handleClerkWebhook(args) {
27902
+ try {
27903
+ const rawBody = await args.request.clone().text();
27904
+ const verification = await verifyClerkSignature({
27905
+ body: rawBody,
27906
+ headers: args.request.headers
27907
+ });
27908
+ if (verification !== true) {
27909
+ let message = "Clerk webhook signature verification failed.";
27910
+ if (verification === "signature_expired") {
27911
+ message = "Clerk webhook signature is too old.";
27912
+ }
27913
+ if (verification === "malformed_timestamp") {
27914
+ message = "Malformed Clerk webhook timestamp header.";
27915
+ }
27916
+ if (verification === "missing_headers_or_secret") {
27917
+ message = "Missing Clerk webhook signature headers or secret.";
27918
+ }
27919
+ return webhookError(
27920
+ "AUTH_REQUIRED",
27921
+ 401,
27922
+ message,
27923
+ args.correlationId,
27924
+ args.policyTraceId
27925
+ );
27926
+ }
27927
+ let payload;
27928
+ try {
27929
+ payload = JSON.parse(rawBody);
27930
+ } catch {
27931
+ return webhookError(
27932
+ "INVALID_REQUEST",
27933
+ 400,
27934
+ "Clerk webhook body must be valid JSON.",
27935
+ args.correlationId,
27936
+ args.policyTraceId
27937
+ );
27938
+ }
27939
+ const eventType = readString28(payload.type);
27940
+ if (!eventType) {
27941
+ return webhookError(
27942
+ "INVALID_REQUEST",
27943
+ 400,
27944
+ "Clerk webhook payload must include event type.",
27945
+ args.correlationId,
27946
+ args.policyTraceId
27947
+ );
27948
+ }
27949
+ const data = asRecord26(payload.data);
27950
+ const actorId = extractClerkActorId(payload);
27951
+ const eventId = readString28(payload.id);
27952
+ const eventTimestamp = readString28(payload.created_at) || readString28(payload.timestamp);
27953
+ const isOrgLifecycleEvent = ORGANIZATION_LIFECYCLE_EVENTS.has(eventType);
27954
+ const isUserEvent = USER_EVENTS.has(eventType);
27955
+ const isMembershipEvent = MEMBERSHIP_EVENTS.has(eventType);
27956
+ const isInvitationEvent = INVITATION_EVENTS.has(eventType);
27957
+ const getClient = async () => args.convexClient ?? await getMasterControlConvexClient2();
27958
+ if (isOrgLifecycleEvent) {
27959
+ const nestedOrganization = asRecord26(data.organization);
27960
+ const organizationRecord = Object.keys(nestedOrganization).length > 0 ? nestedOrganization : data;
27961
+ const organizationId = readString28(data.id) || readString28(data.organization_id) || readString28(organizationRecord.id);
27962
+ const organizationIds = extractOrganizationIds(data);
27963
+ if (!organizationId) {
27964
+ return webhookError(
27965
+ "INVALID_REQUEST",
27966
+ 400,
27967
+ "Clerk organization webhook payload missing organization id.",
27968
+ args.correlationId,
27969
+ args.policyTraceId
27970
+ );
27971
+ }
27972
+ const client = await getClient();
27973
+ const tenant = await resolveTenantByOrgSlug({
27974
+ client,
27975
+ organizationSlug: organizationIds.organizationSlug
27976
+ });
27977
+ if (!tenant) {
27978
+ return webhookError(
27979
+ "NOT_FOUND",
27980
+ 404,
27981
+ "Could not resolve tenant for Clerk organization webhook event.",
27982
+ args.correlationId,
27983
+ args.policyTraceId,
27984
+ {
27985
+ eventType,
27986
+ organizationId,
27987
+ organizationSlug: organizationIds.organizationSlug
27988
+ }
27989
+ );
27990
+ }
27991
+ await upsertPermitTenant({
27992
+ clerkOrganizationId: organizationId,
27993
+ clerkOrganizationSlug: organizationIds.organizationSlug,
27994
+ tenantKey: tenant.tenantSlug,
27995
+ tenantName: extractOrganizationName(organizationRecord),
27996
+ eventType,
27997
+ eventAt: eventTimestamp,
27998
+ actorId
27999
+ });
28000
+ const principal = await client.mutation(mcApi2.identity.upsertPrincipal, {
28001
+ principalId: organizationId,
28002
+ principalType: "group",
28003
+ clerkId: organizationId,
28004
+ displayName: extractOrganizationName(organizationRecord),
28005
+ status: eventType === "organization.deleted" ? "disabled" : "active",
28006
+ actorClerkId: actorId,
28007
+ tenantId: tenant.tenantId,
28008
+ metadata: buildWebhookMetadata({
28009
+ eventType,
28010
+ eventId,
28011
+ actorId,
28012
+ eventAt: eventTimestamp,
28013
+ extra: {
28014
+ sourceType: "organization",
28015
+ organizationId,
28016
+ organizationSlug: organizationIds.organizationSlug,
28017
+ organizationName: extractOrganizationName(organizationRecord),
28018
+ organizationStatus: eventType
28019
+ }
28020
+ })
28021
+ });
28022
+ const alias = await client.mutation(mcApi2.identity.upsertPrincipalIdentityAlias, {
28023
+ principalId: organizationId,
28024
+ principalRefId: void 0,
28025
+ provider: "clerk",
28026
+ providerProjectId: void 0,
28027
+ externalSubjectId: organizationId,
28028
+ tenantId: tenant.tenantId,
28029
+ email: void 0,
28030
+ metadata: buildWebhookMetadata({
28031
+ eventType,
28032
+ eventId,
28033
+ actorId,
28034
+ eventAt: eventTimestamp,
28035
+ extra: {
28036
+ sourceType: "organization",
28037
+ organizationId,
28038
+ organizationSlug: organizationIds.organizationSlug,
28039
+ organizationName: extractOrganizationName(organizationRecord),
28040
+ organizationStatus: eventType
28041
+ }
28042
+ }),
28043
+ actorClerkId: actorId
28044
+ });
28045
+ return successResponse(
28046
+ {
28047
+ acknowledged: true,
28048
+ eventType,
28049
+ tenantId: tenant.tenantId,
28050
+ principalId: organizationId,
28051
+ principal,
28052
+ alias
28053
+ },
28054
+ {
28055
+ correlationId: args.correlationId,
28056
+ policyTraceId: args.policyTraceId
28057
+ }
28058
+ );
28059
+ }
28060
+ if (isUserEvent) {
28061
+ const client = await getClient();
28062
+ const userData = extractUserData(data);
28063
+ const userId = readString28(userData.id) || readString28(data.id);
28064
+ if (!userId) {
28065
+ return webhookError(
28066
+ "INVALID_REQUEST",
28067
+ 400,
28068
+ "Clerk user webhook payload missing user id.",
28069
+ args.correlationId,
28070
+ args.policyTraceId
28071
+ );
28072
+ }
28073
+ await syncPermitUser({
28074
+ userId,
28075
+ email: readPrimaryEmail(userData),
28076
+ displayName: readDisplayName(userData),
28077
+ eventType,
28078
+ eventAt: eventTimestamp,
28079
+ actorId
28080
+ });
28081
+ const principal = await client.mutation(mcApi2.identity.upsertPrincipal, {
28082
+ principalId: userId,
28083
+ principalType: "user",
28084
+ clerkId: userId,
28085
+ email: readPrimaryEmail(userData),
28086
+ displayName: readDisplayName(userData),
28087
+ status: eventType === "user.deleted" ? "disabled" : "active",
28088
+ actorClerkId: actorId,
28089
+ metadata: buildWebhookMetadata({
28090
+ eventType,
28091
+ eventId,
28092
+ actorId,
28093
+ eventAt: eventTimestamp,
28094
+ extra: {
28095
+ userId,
28096
+ clerkStatus: eventType,
28097
+ user: userData
28098
+ }
28099
+ })
28100
+ });
28101
+ const alias = await client.mutation(mcApi2.identity.upsertPrincipalIdentityAlias, {
28102
+ principalId: userId,
28103
+ principalRefId: void 0,
28104
+ provider: "clerk",
28105
+ providerProjectId: void 0,
28106
+ externalSubjectId: userId,
28107
+ tenantId: void 0,
28108
+ email: readPrimaryEmail(userData),
28109
+ metadata: buildWebhookMetadata({
28110
+ eventType,
28111
+ eventId,
28112
+ actorId,
28113
+ eventAt: eventTimestamp,
28114
+ extra: {
28115
+ userId,
28116
+ sourceType: "user",
28117
+ status: eventType,
28118
+ email: readPrimaryEmail(userData),
28119
+ displayName: readDisplayName(userData)
28120
+ }
28121
+ }),
28122
+ actorClerkId: actorId
28123
+ });
28124
+ return successResponse(
28125
+ {
28126
+ acknowledged: true,
28127
+ eventType,
28128
+ principal,
28129
+ alias,
28130
+ source: {
28131
+ eventType,
28132
+ eventId
28133
+ }
28134
+ },
28135
+ {
28136
+ correlationId: args.correlationId,
28137
+ policyTraceId: args.policyTraceId
28138
+ }
28139
+ );
28140
+ }
28141
+ if (isMembershipEvent || isInvitationEvent) {
28142
+ const client = await getClient();
28143
+ const org = extractOrganizationIds(data);
28144
+ const tenant = await resolveTenantByOrgSlug({
28145
+ client,
28146
+ organizationSlug: org.organizationSlug
28147
+ });
28148
+ if (!tenant) {
28149
+ return webhookError(
28150
+ "NOT_FOUND",
28151
+ 404,
28152
+ "Could not resolve tenant for Clerk organization webhook event.",
28153
+ args.correlationId,
28154
+ args.policyTraceId,
28155
+ {
28156
+ eventType,
28157
+ organizationId: org.organizationId,
28158
+ organizationSlug: org.organizationSlug
28159
+ }
28160
+ );
28161
+ }
28162
+ const userId = readString28(data.user_id) || readString28(asRecord26(data.public_user_data).user_id) || readString28(asRecord26(data.user).id);
28163
+ const rawRole = readString28(data.role);
28164
+ const role = normalizeRole(rawRole);
28165
+ const permitTenantKey = tenant.tenantSlug;
28166
+ if (!permitTenantKey) {
28167
+ return webhookError(
28168
+ "INVALID_REQUEST",
28169
+ 400,
28170
+ "Clerk organization webhook payload missing organization tenant key.",
28171
+ args.correlationId,
28172
+ args.policyTraceId
28173
+ );
28174
+ }
28175
+ if (INVITATION_EVENTS.has(eventType)) {
28176
+ const invitationId = readString28(data.id);
28177
+ const invitationAccepted = eventType === "organizationInvitation.accepted";
28178
+ const invitationRevoked = eventType === "organizationInvitation.revoked";
28179
+ let fallbackInvitationStatus = "created";
28180
+ if (invitationAccepted) {
28181
+ fallbackInvitationStatus = "accepted";
28182
+ } else if (invitationRevoked) {
28183
+ fallbackInvitationStatus = "revoked";
28184
+ }
28185
+ const invitationStatus = readString28(data.status) || fallbackInvitationStatus;
28186
+ if (!invitationId) {
28187
+ return webhookError(
28188
+ "INVALID_REQUEST",
28189
+ 400,
28190
+ "Clerk organization invitation webhook payload missing invitation id.",
28191
+ args.correlationId,
28192
+ args.policyTraceId
28193
+ );
28194
+ }
28195
+ if (userId) {
28196
+ const userEmail = readPrimaryEmail(asRecord26(data.public_user_data));
28197
+ await syncPermitUser({
28198
+ userId,
28199
+ email: userEmail,
28200
+ displayName: void 0,
28201
+ eventType,
28202
+ eventAt: eventTimestamp,
28203
+ actorId
28204
+ });
28205
+ const existingPrincipal = invitationAccepted ? null : await client.query(mcApi2.identity.getPrincipalByPrincipalId, {
28206
+ principalId: userId
28207
+ });
28208
+ const principalStatus = invitationAccepted ? "active" : readString28(asRecord26(existingPrincipal).status) ?? "invited";
28209
+ await client.mutation(mcApi2.identity.upsertPrincipal, {
28210
+ principalId: userId,
28211
+ principalType: "user",
28212
+ clerkId: userId,
28213
+ actorClerkId: actorId,
28214
+ status: principalStatus,
28215
+ metadata: buildWebhookMetadata({
28216
+ eventType,
28217
+ eventId,
28218
+ actorId,
28219
+ eventAt: eventTimestamp,
28220
+ extra: {
28221
+ sourceType: "organization_invitation",
28222
+ invitationId,
28223
+ organizationId: org.organizationId,
28224
+ organizationSlug: org.organizationSlug,
28225
+ membershipId: readString28(data.membership_id),
28226
+ role,
28227
+ tenantId: tenant.tenantId
28228
+ }
28229
+ })
28230
+ });
28231
+ if (invitationAccepted) {
28232
+ await upsertPermitTenantMembershipRole({
28233
+ userId,
28234
+ tenantKey: permitTenantKey,
28235
+ role
28236
+ });
28237
+ await client.mutation(mcApi2.identity.upsertMembership, {
28238
+ principalId: userId,
28239
+ principalRefId: void 0,
28240
+ tenantId: tenant.tenantId,
28241
+ role,
28242
+ source: "api",
28243
+ actorClerkId: actorId
28244
+ });
28245
+ }
28246
+ await client.mutation(mcApi2.identity.upsertPrincipalIdentityAlias, {
28247
+ principalId: userId,
28248
+ principalRefId: void 0,
28249
+ provider: "clerk",
28250
+ providerProjectId: void 0,
28251
+ externalSubjectId: userId,
28252
+ tenantId: tenant.tenantId,
28253
+ email: readPrimaryEmail(asRecord26(data.public_user_data)),
28254
+ metadata: buildWebhookMetadata({
28255
+ eventType,
28256
+ eventId,
28257
+ actorId,
28258
+ eventAt: eventTimestamp,
28259
+ extra: {
28260
+ sourceType: "organization_invitation",
28261
+ organizationId: org.organizationId,
28262
+ organizationSlug: org.organizationSlug,
28263
+ invitationId,
28264
+ invitationStatus,
28265
+ role,
28266
+ tenantId: tenant.tenantId,
28267
+ membershipId: readString28(data.membership_id)
28268
+ }
28269
+ }),
28270
+ actorClerkId: actorId
28271
+ });
28272
+ if (invitationRevoked) {
28273
+ await revokePermitTenantMembershipRoles({
28274
+ userId,
28275
+ tenantKey: permitTenantKey
28276
+ });
28277
+ const existing = await client.query(mcApi2.identity.getMembershipForPrincipal, {
28278
+ principalId: userId,
28279
+ tenantId: tenant.tenantId,
28280
+ workspaceId: void 0
28281
+ });
28282
+ if (existing) {
28283
+ await client.mutation(mcApi2.identity.revokeMembership, {
28284
+ membershipId: existing._id,
28285
+ actorClerkId: actorId
28286
+ });
28287
+ }
28288
+ }
28289
+ }
28290
+ return successResponse(
28291
+ {
28292
+ acknowledged: true,
28293
+ eventType,
28294
+ tenantId: tenant.tenantId,
28295
+ principalId: userId,
28296
+ invitationId,
28297
+ userMatched: Boolean(userId),
28298
+ skipped: userId ? void 0 : "no_user_reference"
28299
+ },
28300
+ {
28301
+ correlationId: args.correlationId,
28302
+ policyTraceId: args.policyTraceId
28303
+ }
28304
+ );
28305
+ }
28306
+ if (!userId) {
28307
+ return webhookError(
28308
+ "INVALID_REQUEST",
28309
+ 400,
28310
+ "Clerk membership webhook payload missing user id.",
28311
+ args.correlationId,
28312
+ args.policyTraceId
28313
+ );
28314
+ }
28315
+ await syncPermitUser({
28316
+ userId,
28317
+ email: readPrimaryEmail(asRecord26(data.public_user_data)),
28318
+ displayName: void 0,
28319
+ eventType,
28320
+ eventAt: eventTimestamp,
28321
+ actorId
28322
+ });
28323
+ await client.mutation(mcApi2.identity.upsertPrincipal, {
28324
+ principalId: userId,
28325
+ principalType: "user",
28326
+ clerkId: userId,
28327
+ actorClerkId: actorId,
28328
+ status: "active",
28329
+ metadata: buildWebhookMetadata({
28330
+ eventType,
28331
+ eventId,
28332
+ actorId,
28333
+ eventAt: eventTimestamp,
28334
+ extra: {
28335
+ sourceType: "organization_membership",
28336
+ organizationId: org.organizationId,
28337
+ organizationSlug: org.organizationSlug,
28338
+ membershipId: readString28(data.id),
28339
+ role,
28340
+ tenantId: tenant.tenantId
28341
+ }
28342
+ })
28343
+ });
28344
+ await client.mutation(mcApi2.identity.upsertPrincipalIdentityAlias, {
28345
+ principalId: userId,
28346
+ principalRefId: void 0,
28347
+ provider: "clerk",
28348
+ providerProjectId: void 0,
28349
+ externalSubjectId: userId,
28350
+ tenantId: tenant.tenantId,
28351
+ email: readPrimaryEmail(asRecord26(data.public_user_data)),
28352
+ metadata: buildWebhookMetadata({
28353
+ eventType,
28354
+ eventId,
28355
+ actorId,
28356
+ eventAt: eventTimestamp,
28357
+ extra: {
28358
+ sourceType: "organization_membership",
28359
+ organizationId: org.organizationId,
28360
+ organizationSlug: org.organizationSlug,
28361
+ membershipId: readString28(data.id),
28362
+ role,
28363
+ tenantId: tenant.tenantId,
28364
+ organizationEventType: eventType
28365
+ }
28366
+ }),
28367
+ actorClerkId: actorId
28368
+ });
28369
+ if (eventType === "organizationMembership.deleted") {
28370
+ await revokePermitTenantMembershipRoles({
28371
+ userId,
28372
+ tenantKey: permitTenantKey
28373
+ });
28374
+ const existing = await client.query(mcApi2.identity.getMembershipForPrincipal, {
28375
+ principalId: userId,
28376
+ tenantId: tenant.tenantId,
28377
+ workspaceId: void 0
28378
+ });
28379
+ if (!existing) {
28380
+ return successResponse(
28381
+ {
28382
+ acknowledged: true,
28383
+ eventType,
28384
+ principalId: userId,
28385
+ tenantId: tenant.tenantId,
28386
+ skipped: "membership_not_found"
28387
+ },
28388
+ {
28389
+ correlationId: args.correlationId,
28390
+ policyTraceId: args.policyTraceId
28391
+ }
28392
+ );
28393
+ }
28394
+ const revoked = await client.mutation(mcApi2.identity.revokeMembership, {
28395
+ membershipId: existing._id,
28396
+ actorClerkId: actorId
28397
+ });
28398
+ return successResponse(
28399
+ {
28400
+ acknowledged: true,
28401
+ eventType,
28402
+ tenantId: tenant.tenantId,
28403
+ principalId: userId,
28404
+ revoked
28405
+ },
28406
+ {
28407
+ correlationId: args.correlationId,
28408
+ policyTraceId: args.policyTraceId
28409
+ }
28410
+ );
28411
+ }
28412
+ const membership = await client.mutation(mcApi2.identity.upsertMembership, {
28413
+ principalId: userId,
28414
+ principalRefId: void 0,
28415
+ tenantId: tenant.tenantId,
28416
+ role,
28417
+ source: "api",
28418
+ actorClerkId: actorId
28419
+ });
28420
+ await upsertPermitTenantMembershipRole({
28421
+ userId,
28422
+ tenantKey: permitTenantKey,
28423
+ role
28424
+ });
28425
+ return successResponse(
28426
+ {
28427
+ acknowledged: true,
28428
+ eventType,
28429
+ tenantId: tenant.tenantId,
28430
+ principalId: userId,
28431
+ membership
28432
+ },
28433
+ {
28434
+ correlationId: args.correlationId,
28435
+ policyTraceId: args.policyTraceId
28436
+ }
28437
+ );
28438
+ }
28439
+ return successResponse(
28440
+ {
28441
+ acknowledged: true,
28442
+ eventType,
28443
+ reason: "Unsupported Clerk event type"
28444
+ },
28445
+ {
28446
+ correlationId: args.correlationId,
28447
+ policyTraceId: args.policyTraceId
28448
+ }
28449
+ );
28450
+ } catch (error) {
28451
+ return handleClerkWebhookError(error, args.correlationId, args.policyTraceId);
28452
+ }
28453
+ }
27205
28454
 
27206
28455
  // ../../apps/gateway/src/routes/questions.ts
27207
- function asRecord26(value) {
28456
+ function asRecord27(value) {
27208
28457
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
27209
28458
  }
27210
- function readString28(value) {
28459
+ function readString29(value) {
27211
28460
  if (typeof value !== "string") {
27212
28461
  return void 0;
27213
28462
  }
27214
28463
  const normalized = value.trim();
27215
28464
  return normalized.length > 0 ? normalized : void 0;
27216
28465
  }
27217
- function readNumber18(value) {
28466
+ function readNumber19(value) {
27218
28467
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
27219
28468
  }
27220
28469
  function readStringArray14(value) {
27221
28470
  if (!Array.isArray(value)) {
27222
28471
  return void 0;
27223
28472
  }
27224
- const items = value.map((entry) => readString28(entry)).filter((entry) => Boolean(entry));
28473
+ const items = value.map((entry) => readString29(entry)).filter((entry) => Boolean(entry));
27225
28474
  return items.length > 0 ? items : void 0;
27226
28475
  }
27227
28476
  async function handleQuestionCreate(args) {
27228
28477
  try {
27229
- const body = asRecord26(args.body);
28478
+ const body = asRecord27(args.body);
27230
28479
  const payload = await createQuestionFromGatewayAuth(args.authContext, {
27231
- topicId: readString28(body.topicId),
27232
- text: readString28(body.text) ?? "",
27233
- priority: readString28(body.priority),
27234
- linkedBeliefId: readString28(body.linkedBeliefId),
27235
- metadata: asRecord26(body.metadata)
28480
+ topicId: readString29(body.topicId),
28481
+ text: readString29(body.text) ?? "",
28482
+ priority: readString29(body.priority),
28483
+ linkedBeliefId: readString29(body.linkedBeliefId),
28484
+ metadata: asRecord27(body.metadata)
27236
28485
  });
27237
28486
  return successResponse(payload, {
27238
28487
  status: 201,
@@ -27279,10 +28528,10 @@ async function handleQuestionGet(args) {
27279
28528
  }
27280
28529
  async function handleQuestionArchive(args) {
27281
28530
  try {
27282
- const body = asRecord26(args.body);
28531
+ const body = asRecord27(args.body);
27283
28532
  const payload = await archiveQuestionFromGatewayAuth(args.authContext, {
27284
28533
  id: args.questionId,
27285
- rationale: readString28(body.reason) ?? readString28(body.rationale)
28534
+ rationale: readString29(body.reason) ?? readString29(body.rationale)
27286
28535
  });
27287
28536
  return successResponse(payload, {
27288
28537
  correlationId: args.correlationId,
@@ -27325,13 +28574,13 @@ async function handleQuestionList(args) {
27325
28574
  }
27326
28575
  async function handleQuestionAnswer(args) {
27327
28576
  try {
27328
- const body = asRecord26(args.body);
28577
+ const body = asRecord27(args.body);
27329
28578
  const payload = await answerQuestionFromGatewayAuth(args.authContext, {
27330
28579
  id: args.questionId,
27331
- text: readString28(body.text) ?? "",
27332
- confidence: readString28(body.confidence),
28580
+ text: readString29(body.text) ?? "",
28581
+ confidence: readString29(body.confidence),
27333
28582
  evidenceIds: readStringArray14(body.evidenceIds),
27334
- rationale: readString28(body.rationale)
28583
+ rationale: readString29(body.rationale)
27335
28584
  });
27336
28585
  return successResponse(payload, {
27337
28586
  correlationId: args.correlationId,
@@ -27377,11 +28626,11 @@ async function handleQuestionGetAnswer(args) {
27377
28626
  }
27378
28627
  async function handleQuestionRefine(args) {
27379
28628
  try {
27380
- const body = asRecord26(args.body);
28629
+ const body = asRecord27(args.body);
27381
28630
  const payload = await refineQuestionFromGatewayAuth(args.authContext, {
27382
28631
  id: args.questionId,
27383
- text: readString28(body.text) ?? "",
27384
- rationale: readString28(body.rationale)
28632
+ text: readString29(body.text) ?? "",
28633
+ rationale: readString29(body.rationale)
27385
28634
  });
27386
28635
  return successResponse(payload, {
27387
28636
  correlationId: args.correlationId,
@@ -27403,11 +28652,11 @@ async function handleQuestionRefine(args) {
27403
28652
  }
27404
28653
  async function handleQuestionUpdateStatus(args) {
27405
28654
  try {
27406
- const body = asRecord26(args.body);
28655
+ const body = asRecord27(args.body);
27407
28656
  const payload = await updateQuestionStatusFromGatewayAuth(args.authContext, {
27408
28657
  id: args.questionId,
27409
- status: readString28(body.status) ?? "",
27410
- rationale: readString28(body.rationale)
28658
+ status: readString29(body.status) ?? "",
28659
+ rationale: readString29(body.rationale)
27411
28660
  });
27412
28661
  return successResponse(payload, {
27413
28662
  correlationId: args.correlationId,
@@ -27432,19 +28681,19 @@ async function handleQuestionUpdateStatus(args) {
27432
28681
  }
27433
28682
  async function handleQuestionBatchCreate(args) {
27434
28683
  try {
27435
- const body = asRecord26(args.body);
27436
- const questions = Array.isArray(body.questions) ? body.questions.map((entry) => asRecord26(entry)).map((entry) => ({
27437
- question: readString28(entry.question) ?? readString28(entry.text) ?? "",
27438
- category: readString28(entry.category),
27439
- priority: readString28(entry.priority),
27440
- linkedBeliefNodeId: readString28(entry.linkedBeliefNodeId) ?? readString28(entry.linkedBeliefId),
27441
- linkedWorktreeId: readString28(entry.linkedWorktreeId),
27442
- testType: readString28(entry.testType)
28684
+ const body = asRecord27(args.body);
28685
+ const questions = Array.isArray(body.questions) ? body.questions.map((entry) => asRecord27(entry)).map((entry) => ({
28686
+ question: readString29(entry.question) ?? readString29(entry.text) ?? "",
28687
+ category: readString29(entry.category),
28688
+ priority: readString29(entry.priority),
28689
+ linkedBeliefNodeId: readString29(entry.linkedBeliefNodeId) ?? readString29(entry.linkedBeliefId),
28690
+ linkedWorktreeId: readString29(entry.linkedWorktreeId),
28691
+ testType: readString29(entry.testType)
27443
28692
  })) : [];
27444
28693
  const payload = await createQuestionsBatchFromGatewayAuth(args.authContext, {
27445
- topicId: readString28(body.topicId),
28694
+ topicId: readString29(body.topicId),
27446
28695
  questions,
27447
- source: readString28(body.source)
28696
+ source: readString29(body.source)
27448
28697
  });
27449
28698
  return successResponse(payload, {
27450
28699
  status: 201,
@@ -27470,20 +28719,20 @@ async function handleQuestionBatchCreate(args) {
27470
28719
  }
27471
28720
  async function handleQuestionAdd(args) {
27472
28721
  try {
27473
- const body = asRecord26(args.body);
28722
+ const body = asRecord27(args.body);
27474
28723
  const payload = await addQuestionFromGatewayAuth(args.authContext, {
27475
- topicId: readString28(body.topicId),
27476
- question: readString28(body.question) ?? readString28(body.text),
27477
- category: readString28(body.category),
27478
- priority: readString28(body.priority),
27479
- source: readString28(body.source),
27480
- beliefId: readString28(body.beliefId) ?? readString28(body.linkedBeliefId),
27481
- linkedWorktreeId: readString28(body.linkedWorktreeId),
27482
- chatId: readString28(body.chatId),
27483
- importance: readNumber18(body.importance),
27484
- epistemicUnlock: readString28(body.epistemicUnlock),
27485
- metadata: asRecord26(body.metadata),
27486
- questionType: readString28(body.questionType)
28724
+ topicId: readString29(body.topicId),
28725
+ question: readString29(body.question) ?? readString29(body.text),
28726
+ category: readString29(body.category),
28727
+ priority: readString29(body.priority),
28728
+ source: readString29(body.source),
28729
+ beliefId: readString29(body.beliefId) ?? readString29(body.linkedBeliefId),
28730
+ linkedWorktreeId: readString29(body.linkedWorktreeId),
28731
+ chatId: readString29(body.chatId),
28732
+ importance: readNumber19(body.importance),
28733
+ epistemicUnlock: readString29(body.epistemicUnlock),
28734
+ metadata: asRecord27(body.metadata),
28735
+ questionType: readString29(body.questionType)
27487
28736
  });
27488
28737
  return successResponse(payload, {
27489
28738
  status: 201,
@@ -27506,12 +28755,12 @@ async function handleQuestionAdd(args) {
27506
28755
  }
27507
28756
  async function handleQuestionUpdatePriority(args) {
27508
28757
  try {
27509
- const body = asRecord26(args.body);
28758
+ const body = asRecord27(args.body);
27510
28759
  const payload = await updateQuestionPriorityFromGatewayAuth(
27511
28760
  args.authContext,
27512
28761
  {
27513
- id: readString28(body.id) ?? readString28(body.nodeId) ?? readString28(body.questionId),
27514
- priority: readString28(body.priority) ?? "medium"
28762
+ id: readString29(body.id) ?? readString29(body.nodeId) ?? readString29(body.questionId),
28763
+ priority: readString29(body.priority) ?? "medium"
27515
28764
  }
27516
28765
  );
27517
28766
  return successResponse(payload, {
@@ -27537,12 +28786,12 @@ async function handleQuestionUpdatePriority(args) {
27537
28786
  }
27538
28787
  async function handleQuestionAdvanceToConviction(args) {
27539
28788
  try {
27540
- const body = asRecord26(args.body);
28789
+ const body = asRecord27(args.body);
27541
28790
  const payload = await advanceQuestionToConvictionFromGatewayAuth(
27542
28791
  args.authContext,
27543
28792
  {
27544
- questionId: readString28(body.questionId) ?? readString28(body.id) ?? readString28(body.nodeId),
27545
- worktreeId: readString28(body.worktreeId)
28793
+ questionId: readString29(body.questionId) ?? readString29(body.id) ?? readString29(body.nodeId),
28794
+ worktreeId: readString29(body.worktreeId)
27546
28795
  }
27547
28796
  );
27548
28797
  return successResponse(payload, {
@@ -27568,14 +28817,14 @@ async function handleQuestionAdvanceToConviction(args) {
27568
28817
  }
27569
28818
  async function handleQuestionUpdateConviction(args) {
27570
28819
  try {
27571
- const body = asRecord26(args.body);
28820
+ const body = asRecord27(args.body);
27572
28821
  const payload = await updateQuestionConvictionFromGatewayAuth(
27573
28822
  args.authContext,
27574
28823
  {
27575
- questionId: readString28(body.questionId) ?? readString28(body.id) ?? readString28(body.nodeId),
27576
- conviction: readNumber18(body.conviction),
27577
- answerCompleteness: readString28(body.answerCompleteness),
27578
- convictionRationale: readString28(body.convictionRationale)
28824
+ questionId: readString29(body.questionId) ?? readString29(body.id) ?? readString29(body.nodeId),
28825
+ conviction: readNumber19(body.conviction),
28826
+ answerCompleteness: readString29(body.answerCompleteness),
28827
+ convictionRationale: readString29(body.convictionRationale)
27579
28828
  }
27580
28829
  );
27581
28830
  return successResponse(payload, {
@@ -27601,16 +28850,16 @@ async function handleQuestionUpdateConviction(args) {
27601
28850
  }
27602
28851
  async function handleQuestionFinalizeConviction(args) {
27603
28852
  try {
27604
- const body = asRecord26(args.body);
28853
+ const body = asRecord27(args.body);
27605
28854
  const payload = await finalizeQuestionConvictionFromGatewayAuth(
27606
28855
  args.authContext,
27607
28856
  {
27608
- questionId: readString28(body.questionId) ?? readString28(body.id) ?? readString28(body.nodeId),
27609
- conviction: readNumber18(body.conviction) ?? Number.NaN,
27610
- answer: readString28(body.answer) ?? "",
27611
- convictionRationale: readString28(body.convictionRationale),
27612
- answerCompleteness: readString28(body.answerCompleteness),
27613
- whatWeNeed: readString28(body.whatWeNeed)
28857
+ questionId: readString29(body.questionId) ?? readString29(body.id) ?? readString29(body.nodeId),
28858
+ conviction: readNumber19(body.conviction) ?? Number.NaN,
28859
+ answer: readString29(body.answer) ?? "",
28860
+ convictionRationale: readString29(body.convictionRationale),
28861
+ answerCompleteness: readString29(body.answerCompleteness),
28862
+ whatWeNeed: readString29(body.whatWeNeed)
27614
28863
  }
27615
28864
  );
27616
28865
  return successResponse(payload, {
@@ -27636,12 +28885,12 @@ async function handleQuestionFinalizeConviction(args) {
27636
28885
  }
27637
28886
  async function handleQuestionUpdate(args) {
27638
28887
  try {
27639
- const body = asRecord26(args.body);
28888
+ const body = asRecord27(args.body);
27640
28889
  const payload = await updateQuestionFromGatewayAuth(args.authContext, {
27641
- questionId: readString28(body.questionId) ?? readString28(body.id) ?? readString28(body.nodeId),
27642
- question: readString28(body.question) ?? readString28(body.text),
27643
- category: readString28(body.category),
27644
- priority: readString28(body.priority)
28890
+ questionId: readString29(body.questionId) ?? readString29(body.id) ?? readString29(body.nodeId),
28891
+ question: readString29(body.question) ?? readString29(body.text),
28892
+ category: readString29(body.category),
28893
+ priority: readString29(body.priority)
27645
28894
  });
27646
28895
  return successResponse(payload, {
27647
28896
  correlationId: args.correlationId,
@@ -27663,9 +28912,9 @@ async function handleQuestionUpdate(args) {
27663
28912
  }
27664
28913
  async function handleQuestionDelete(args) {
27665
28914
  try {
27666
- const body = asRecord26(args.body);
28915
+ const body = asRecord27(args.body);
27667
28916
  const payload = await deleteQuestionFromGatewayAuth(args.authContext, {
27668
- questionId: readString28(body.questionId) ?? readString28(body.id) ?? readString28(body.nodeId)
28917
+ questionId: readString29(body.questionId) ?? readString29(body.id) ?? readString29(body.nodeId)
27669
28918
  });
27670
28919
  return successResponse(payload, {
27671
28920
  correlationId: args.correlationId,
@@ -27687,30 +28936,30 @@ async function handleQuestionDelete(args) {
27687
28936
  }
27688
28937
 
27689
28938
  // ../../apps/gateway/src/routes/search.ts
27690
- function asRecord27(value) {
28939
+ function asRecord28(value) {
27691
28940
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
27692
28941
  }
27693
- function readString29(value) {
28942
+ function readString30(value) {
27694
28943
  if (typeof value !== "string") {
27695
28944
  return void 0;
27696
28945
  }
27697
28946
  const normalized = value.trim();
27698
28947
  return normalized.length > 0 ? normalized : void 0;
27699
28948
  }
27700
- function readNumber19(value) {
28949
+ function readNumber20(value) {
27701
28950
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
27702
28951
  }
27703
28952
  function readStringArray15(value) {
27704
28953
  if (!Array.isArray(value)) {
27705
28954
  return void 0;
27706
28955
  }
27707
- const items = value.map((entry) => readString29(entry)).filter((entry) => Boolean(entry));
28956
+ const items = value.map((entry) => readString30(entry)).filter((entry) => Boolean(entry));
27708
28957
  return items.length > 0 ? items : void 0;
27709
28958
  }
27710
28959
  async function handleSearchResources(args) {
27711
- const body = asRecord27(args.body);
27712
- const q = readString29(body.q) ?? readString29(body.query);
27713
- const topicId = readString29(body.topicId) ?? readString29(body.projectId);
28960
+ const body = asRecord28(args.body);
28961
+ const q = readString30(body.q) ?? readString30(body.query);
28962
+ const topicId = readString30(body.topicId) ?? readString30(body.projectId);
27714
28963
  if (!q) {
27715
28964
  return errorResponse({
27716
28965
  code: "INVALID_REQUEST",
@@ -27734,10 +28983,10 @@ async function handleSearchResources(args) {
27734
28983
  q,
27735
28984
  topicId,
27736
28985
  types: readStringArray15(body.types),
27737
- status: readString29(body.status),
27738
- minConfidence: readNumber19(body.minConfidence),
27739
- limit: readNumber19(body.limit),
27740
- cursor: readString29(body.cursor)
28986
+ status: readString30(body.status),
28987
+ minConfidence: readNumber20(body.minConfidence),
28988
+ limit: readNumber20(body.limit),
28989
+ cursor: readString30(body.cursor)
27741
28990
  });
27742
28991
  return successResponse(payload, {
27743
28992
  correlationId: args.correlationId,
@@ -27759,17 +29008,17 @@ async function handleSearchResources(args) {
27759
29008
  }
27760
29009
 
27761
29010
  // ../../apps/gateway/src/routes/sources.ts
27762
- function asRecord28(value) {
29011
+ function asRecord29(value) {
27763
29012
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
27764
29013
  }
27765
- function readString30(value) {
29014
+ function readString31(value) {
27766
29015
  if (typeof value !== "string") {
27767
29016
  return void 0;
27768
29017
  }
27769
29018
  const normalized = value.trim();
27770
29019
  return normalized.length > 0 ? normalized : void 0;
27771
29020
  }
27772
- function readNumber20(value) {
29021
+ function readNumber21(value) {
27773
29022
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
27774
29023
  }
27775
29024
  function handleSourcesError(error, fallbackMessage, correlationId, policyTraceId) {
@@ -27787,15 +29036,15 @@ function handleSourcesError(error, fallbackMessage, correlationId, policyTraceId
27787
29036
  }
27788
29037
  async function handleSourceUpsert(args) {
27789
29038
  try {
27790
- const body = asRecord28(args.body);
29039
+ const body = asRecord29(args.body);
27791
29040
  const payload = await upsertSourceFromGatewayAuth(args.authContext, {
27792
- url: readString30(body.url),
27793
- sha: readString30(body.sha),
27794
- kind: readString30(body.kind) ?? "",
27795
- title: readString30(body.title),
27796
- capturedAt: readNumber20(body.capturedAt),
27797
- topicId: readString30(body.topicId),
27798
- metadata: asRecord28(body.metadata)
29041
+ url: readString31(body.url),
29042
+ sha: readString31(body.sha),
29043
+ kind: readString31(body.kind) ?? "",
29044
+ title: readString31(body.title),
29045
+ capturedAt: readNumber21(body.capturedAt),
29046
+ topicId: readString31(body.topicId),
29047
+ metadata: asRecord29(body.metadata)
27799
29048
  });
27800
29049
  return successResponse(payload, {
27801
29050
  status: 201,
@@ -27829,10 +29078,10 @@ async function handleSourceGet(args) {
27829
29078
  }
27830
29079
 
27831
29080
  // ../../apps/gateway/src/routes/tasks.ts
27832
- function asRecord29(value) {
29081
+ function asRecord30(value) {
27833
29082
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
27834
29083
  }
27835
- function readString31(value) {
29084
+ function readString32(value) {
27836
29085
  if (typeof value !== "string") {
27837
29086
  return void 0;
27838
29087
  }
@@ -27854,18 +29103,18 @@ function handleTasksError(error, fallbackMessage, correlationId, policyTraceId)
27854
29103
  }
27855
29104
  async function handleTaskCreate(args) {
27856
29105
  try {
27857
- const body = asRecord29(args.body);
29106
+ const body = asRecord30(args.body);
27858
29107
  const payload = await createTaskFromGatewayAuth(args.authContext, {
27859
- topicId: readString31(body.topicId),
27860
- title: readString31(body.title) ?? "",
27861
- description: readString31(body.description),
27862
- taskType: readString31(body.taskType),
27863
- priority: readString31(body.priority),
27864
- status: readString31(body.status),
27865
- linkedBeliefId: readString31(body.linkedBeliefId),
27866
- linkedQuestionId: readString31(body.linkedQuestionId),
27867
- linkedWorktreeId: readString31(body.linkedWorktreeId),
27868
- tags: Array.isArray(body.tags) ? body.tags.map((entry) => readString31(entry)).filter((entry) => Boolean(entry)) : void 0,
29108
+ topicId: readString32(body.topicId),
29109
+ title: readString32(body.title) ?? "",
29110
+ description: readString32(body.description),
29111
+ taskType: readString32(body.taskType),
29112
+ priority: readString32(body.priority),
29113
+ status: readString32(body.status),
29114
+ linkedBeliefId: readString32(body.linkedBeliefId),
29115
+ linkedQuestionId: readString32(body.linkedQuestionId),
29116
+ linkedWorktreeId: readString32(body.linkedWorktreeId),
29117
+ tags: Array.isArray(body.tags) ? body.tags.map((entry) => readString32(entry)).filter((entry) => Boolean(entry)) : void 0,
27869
29118
  metadata: body.metadata && typeof body.metadata === "object" && !Array.isArray(body.metadata) ? body.metadata : void 0
27870
29119
  });
27871
29120
  return successResponse(payload, {
@@ -27900,16 +29149,16 @@ async function handleTaskList(args) {
27900
29149
  }
27901
29150
  async function handleTaskUpdate(args) {
27902
29151
  try {
27903
- const body = asRecord29(args.body);
29152
+ const body = asRecord30(args.body);
27904
29153
  const payload = await updateTaskFromGatewayAuth(args.authContext, {
27905
29154
  id: args.taskId,
27906
- title: readString31(body.title),
27907
- description: readString31(body.description),
27908
- priority: readString31(body.priority),
27909
- status: readString31(body.status),
27910
- linkedBeliefId: readString31(body.linkedBeliefId),
27911
- linkedQuestionId: readString31(body.linkedQuestionId),
27912
- linkedWorktreeId: readString31(body.linkedWorktreeId),
29155
+ title: readString32(body.title),
29156
+ description: readString32(body.description),
29157
+ priority: readString32(body.priority),
29158
+ status: readString32(body.status),
29159
+ linkedBeliefId: readString32(body.linkedBeliefId),
29160
+ linkedQuestionId: readString32(body.linkedQuestionId),
29161
+ linkedWorktreeId: readString32(body.linkedWorktreeId),
27913
29162
  metadata: body.metadata && typeof body.metadata === "object" && !Array.isArray(body.metadata) ? body.metadata : void 0
27914
29163
  });
27915
29164
  return successResponse(payload, {
@@ -27927,10 +29176,10 @@ async function handleTaskUpdate(args) {
27927
29176
  }
27928
29177
  async function handleTaskComplete(args) {
27929
29178
  try {
27930
- const body = asRecord29(args.body);
29179
+ const body = asRecord30(args.body);
27931
29180
  const payload = await completeTaskFromGatewayAuth(args.authContext, {
27932
29181
  id: args.taskId,
27933
- outputSummary: readString31(body.outputSummary)
29182
+ outputSummary: readString32(body.outputSummary)
27934
29183
  });
27935
29184
  return successResponse(payload, {
27936
29185
  correlationId: args.correlationId,
@@ -27947,10 +29196,10 @@ async function handleTaskComplete(args) {
27947
29196
  }
27948
29197
 
27949
29198
  // ../../apps/gateway/src/routes/topics.ts
27950
- function asRecord30(value) {
29199
+ function asRecord31(value) {
27951
29200
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
27952
29201
  }
27953
- function readString32(value) {
29202
+ function readString33(value) {
27954
29203
  if (typeof value !== "string") {
27955
29204
  return void 0;
27956
29205
  }
@@ -27960,14 +29209,14 @@ function readString32(value) {
27960
29209
  function readBoolean(value) {
27961
29210
  return typeof value === "boolean" ? value : void 0;
27962
29211
  }
27963
- function readNumber21(value) {
29212
+ function readNumber22(value) {
27964
29213
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
27965
29214
  }
27966
29215
  function readStringArray16(value) {
27967
29216
  if (!Array.isArray(value)) {
27968
29217
  return void 0;
27969
29218
  }
27970
- const items = value.map((entry) => readString32(entry)).filter((entry) => Boolean(entry));
29219
+ const items = value.map((entry) => readString33(entry)).filter((entry) => Boolean(entry));
27971
29220
  return items.length > 0 ? items : void 0;
27972
29221
  }
27973
29222
  function handleTopicsError(error, fallbackMessage, correlationId, policyTraceId) {
@@ -27985,17 +29234,17 @@ function handleTopicsError(error, fallbackMessage, correlationId, policyTraceId)
27985
29234
  }
27986
29235
  async function handleTopicCreate(args) {
27987
29236
  try {
27988
- const body = asRecord30(args.body);
29237
+ const body = asRecord31(args.body);
27989
29238
  const payload = await createTopicFromGatewayAuth(args.authContext, {
27990
- name: readString32(body.name) ?? "",
27991
- description: readString32(body.description),
27992
- type: readString32(body.type),
27993
- parentTopicId: readString32(body.parentTopicId),
27994
- ontologyId: readString32(body.ontologyId),
27995
- tenantId: readString32(body.tenantId),
27996
- workspaceId: readString32(body.workspaceId),
27997
- visibility: readString32(body.visibility),
27998
- createdBy: readString32(body.createdBy)
29239
+ name: readString33(body.name) ?? "",
29240
+ description: readString33(body.description),
29241
+ type: readString33(body.type),
29242
+ parentTopicId: readString33(body.parentTopicId),
29243
+ ontologyId: readString33(body.ontologyId),
29244
+ tenantId: readString33(body.tenantId),
29245
+ workspaceId: readString33(body.workspaceId),
29246
+ visibility: readString33(body.visibility),
29247
+ createdBy: readString33(body.createdBy)
27999
29248
  });
28000
29249
  return successResponse(payload, {
28001
29250
  status: 201,
@@ -28013,16 +29262,16 @@ async function handleTopicCreate(args) {
28013
29262
  }
28014
29263
  async function handleTopicUpdate(args) {
28015
29264
  try {
28016
- const body = asRecord30(args.body);
29265
+ const body = asRecord31(args.body);
28017
29266
  const payload = await updateTopicFromGatewayAuth(args.authContext, {
28018
29267
  id: args.topicId,
28019
- name: readString32(body.name),
28020
- description: readString32(body.description),
28021
- type: readString32(body.type),
28022
- ontologyId: readString32(body.ontologyId),
29268
+ name: readString33(body.name),
29269
+ description: readString33(body.description),
29270
+ type: readString33(body.type),
29271
+ ontologyId: readString33(body.ontologyId),
28023
29272
  clearOntologyId: readBoolean(body.clearOntologyId),
28024
- status: readString32(body.status),
28025
- visibility: readString32(body.visibility)
29273
+ status: readString33(body.status),
29274
+ visibility: readString33(body.visibility)
28026
29275
  });
28027
29276
  return successResponse(payload, {
28028
29277
  correlationId: args.correlationId,
@@ -28073,7 +29322,7 @@ async function handleTopicTree(args) {
28073
29322
  try {
28074
29323
  const payload = await getTopicTreeFromGatewayAuth(args.authContext, {
28075
29324
  id: args.topicId,
28076
- maxDepth: readNumber21(args.query.maxDepth)
29325
+ maxDepth: readNumber22(args.query.maxDepth)
28077
29326
  });
28078
29327
  return successResponse(payload, {
28079
29328
  correlationId: args.correlationId,
@@ -28093,7 +29342,7 @@ async function handleTopicCoverage(args) {
28093
29342
  const payload = await getTopicCoverageFromGatewayAuth(args.authContext, {
28094
29343
  id: args.topicId,
28095
29344
  includeDescendants: typeof args.query.includeDescendants === "boolean" ? args.query.includeDescendants : void 0,
28096
- maxDepth: readNumber21(args.query.maxDepth)
29345
+ maxDepth: readNumber22(args.query.maxDepth)
28097
29346
  });
28098
29347
  return successResponse(payload, {
28099
29348
  correlationId: args.correlationId,
@@ -28110,9 +29359,9 @@ async function handleTopicCoverage(args) {
28110
29359
  }
28111
29360
  async function handleTopicRemove(args) {
28112
29361
  try {
28113
- const body = asRecord30(args.body);
29362
+ const body = asRecord31(args.body);
28114
29363
  const payload = await removeTopicFromGatewayAuth(args.authContext, {
28115
- id: readString32(body.id) ?? readString32(body.topicId) ?? ""
29364
+ id: readString33(body.id) ?? readString33(body.topicId) ?? ""
28116
29365
  });
28117
29366
  return successResponse(payload, {
28118
29367
  correlationId: args.correlationId,
@@ -28129,22 +29378,22 @@ async function handleTopicRemove(args) {
28129
29378
  }
28130
29379
  async function handleTopicBulkCreate(args) {
28131
29380
  try {
28132
- const body = asRecord30(args.body);
28133
- const topics2 = Array.isArray(body.topics) ? body.topics.map((entry) => asRecord30(entry)).map((entry) => ({
28134
- globalId: readString32(entry.globalId) ?? "",
28135
- name: readString32(entry.name) ?? "",
28136
- description: readString32(entry.description),
28137
- type: readString32(entry.type) ?? "theme",
28138
- parentTopicId: readString32(entry.parentTopicId),
28139
- depth: readNumber21(entry.depth) ?? 0,
29381
+ const body = asRecord31(args.body);
29382
+ const topics2 = Array.isArray(body.topics) ? body.topics.map((entry) => asRecord31(entry)).map((entry) => ({
29383
+ globalId: readString33(entry.globalId) ?? "",
29384
+ name: readString33(entry.name) ?? "",
29385
+ description: readString33(entry.description),
29386
+ type: readString33(entry.type) ?? "theme",
29387
+ parentTopicId: readString33(entry.parentTopicId),
29388
+ depth: readNumber22(entry.depth) ?? 0,
28140
29389
  path: readStringArray16(entry.path) ?? [],
28141
- tenantId: readString32(entry.tenantId),
28142
- workspaceId: readString32(entry.workspaceId),
28143
- graphScopeProjectId: readString32(entry.graphScopeProjectId),
28144
- status: readString32(entry.status) ?? "active",
28145
- visibility: readString32(entry.visibility),
28146
- metadata: asRecord30(entry.metadata),
28147
- createdBy: readString32(entry.createdBy)
29390
+ tenantId: readString33(entry.tenantId),
29391
+ workspaceId: readString33(entry.workspaceId),
29392
+ graphScopeProjectId: readString33(entry.graphScopeProjectId),
29393
+ status: readString33(entry.status) ?? "active",
29394
+ visibility: readString33(entry.visibility),
29395
+ metadata: asRecord31(entry.metadata),
29396
+ createdBy: readString33(entry.createdBy)
28148
29397
  })) : [];
28149
29398
  const payload = await bulkCreateTopicsFromGatewayAuth(args.authContext, {
28150
29399
  topics: topics2
@@ -28165,10 +29414,10 @@ async function handleTopicBulkCreate(args) {
28165
29414
  }
28166
29415
 
28167
29416
  // ../../apps/gateway/src/routes/webhooks.ts
28168
- function asRecord31(value) {
29417
+ function asRecord32(value) {
28169
29418
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
28170
29419
  }
28171
- function readString33(value) {
29420
+ function readString34(value) {
28172
29421
  if (typeof value !== "string") {
28173
29422
  return void 0;
28174
29423
  }
@@ -28182,7 +29431,7 @@ function readStringArray17(value) {
28182
29431
  if (!Array.isArray(value)) {
28183
29432
  return void 0;
28184
29433
  }
28185
- const normalized = value.map((entry) => readString33(entry)).filter((entry) => Boolean(entry));
29434
+ const normalized = value.map((entry) => readString34(entry)).filter((entry) => Boolean(entry));
28186
29435
  return normalized.length > 0 ? normalized : void 0;
28187
29436
  }
28188
29437
  function handleWebhooksError(error, fallbackMessage, correlationId, policyTraceId) {
@@ -28200,16 +29449,16 @@ function handleWebhooksError(error, fallbackMessage, correlationId, policyTraceI
28200
29449
  }
28201
29450
  async function handleWebhookCreate(args) {
28202
29451
  try {
28203
- const body = asRecord31(args.body);
29452
+ const body = asRecord32(args.body);
28204
29453
  const payload = await args.authContext.convex.mutation(
28205
29454
  "events:createWebhook",
28206
29455
  {
28207
29456
  tenantId: args.authContext.tenantId,
28208
29457
  workspaceId: args.authContext.workspaceId,
28209
- topicId: readString33(body.topicId),
28210
- url: readString33(body.url) ?? "",
29458
+ topicId: readString34(body.topicId),
29459
+ url: readString34(body.url) ?? "",
28211
29460
  events: readStringArray17(body.events) ?? [],
28212
- secret: readString33(body.secret) ?? "",
29461
+ secret: readString34(body.secret) ?? "",
28213
29462
  active: readBoolean2(body.active),
28214
29463
  createdBy: args.authContext.principalId ?? args.authContext.userId
28215
29464
  }
@@ -28270,17 +29519,17 @@ async function handleWebhookGet(args) {
28270
29519
  }
28271
29520
  async function handleWebhookUpdate(args) {
28272
29521
  try {
28273
- const body = asRecord31(args.body);
29522
+ const body = asRecord32(args.body);
28274
29523
  const payload = await args.authContext.convex.mutation(
28275
29524
  "events:updateWebhook",
28276
29525
  {
28277
29526
  webhookId: args.webhookId,
28278
29527
  tenantId: args.authContext.tenantId,
28279
29528
  workspaceId: args.authContext.workspaceId,
28280
- url: readString33(body.url),
29529
+ url: readString34(body.url),
28281
29530
  events: readStringArray17(body.events),
28282
- secret: readString33(body.secret),
28283
- topicId: readString33(body.topicId),
29531
+ secret: readString34(body.secret),
29532
+ topicId: readString34(body.topicId),
28284
29533
  clearTopicId: body.topicId === null ? true : readBoolean2(body.clearTopicId),
28285
29534
  active: readBoolean2(body.active),
28286
29535
  updatedBy: args.authContext.principalId ?? args.authContext.userId
@@ -28324,12 +29573,12 @@ async function handleWebhookDelete(args) {
28324
29573
  }
28325
29574
  async function handleWebhookTest(args) {
28326
29575
  try {
28327
- const body = asRecord31(args.body);
29576
+ const body = asRecord32(args.body);
28328
29577
  const payload = await args.authContext.convex.action("events:testWebhook", {
28329
29578
  webhookId: args.webhookId,
28330
29579
  tenantId: args.authContext.tenantId,
28331
29580
  workspaceId: args.authContext.workspaceId,
28332
- topicId: readString33(body.topicId),
29581
+ topicId: readString34(body.topicId),
28333
29582
  actorId: args.authContext.principalId ?? args.authContext.userId,
28334
29583
  actorType: inferActorType({
28335
29584
  authMode: args.authContext.authMode,
@@ -28399,31 +29648,31 @@ async function handleWebhookHealth(args) {
28399
29648
  }
28400
29649
 
28401
29650
  // ../../apps/gateway/src/routes/worktrees.ts
28402
- function asRecord32(value) {
29651
+ function asRecord33(value) {
28403
29652
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
28404
29653
  }
28405
- function readString34(value) {
29654
+ function readString35(value) {
28406
29655
  if (typeof value !== "string") {
28407
29656
  return void 0;
28408
29657
  }
28409
29658
  const normalized = value.trim();
28410
29659
  return normalized.length > 0 ? normalized : void 0;
28411
29660
  }
28412
- function readNumber22(value) {
29661
+ function readNumber23(value) {
28413
29662
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
28414
29663
  }
28415
29664
  function readStringArray18(value) {
28416
29665
  if (!Array.isArray(value)) {
28417
29666
  return void 0;
28418
29667
  }
28419
- const normalized = value.map((entry) => readString34(entry)).filter((entry) => Boolean(entry));
29668
+ const normalized = value.map((entry) => readString35(entry)).filter((entry) => Boolean(entry));
28420
29669
  return normalized.length > 0 ? normalized : void 0;
28421
29670
  }
28422
29671
  function readObjectArray(value) {
28423
29672
  if (!Array.isArray(value)) {
28424
29673
  return void 0;
28425
29674
  }
28426
- const normalized = value.map((entry) => asRecord32(entry)).filter((entry) => Object.keys(entry).length > 0);
29675
+ const normalized = value.map((entry) => asRecord33(entry)).filter((entry) => Object.keys(entry).length > 0);
28427
29676
  return normalized.length > 0 ? normalized : void 0;
28428
29677
  }
28429
29678
  function readConfidenceImpact(value) {
@@ -28434,18 +29683,18 @@ function normalizeMergeOutcomes2(value) {
28434
29683
  return [];
28435
29684
  }
28436
29685
  return value.map((entry) => {
28437
- const finding = readString34(entry);
29686
+ const finding = readString35(entry);
28438
29687
  if (finding) {
28439
29688
  return finding;
28440
29689
  }
28441
- const row = asRecord32(entry);
29690
+ const row = asRecord33(entry);
28442
29691
  if (!Object.keys(row).length) {
28443
29692
  return null;
28444
29693
  }
28445
29694
  return {
28446
- beliefId: readString34(row.beliefId) ?? "",
28447
- confidence: readNumber22(row.confidence) ?? Number.NaN,
28448
- rationale: readString34(row.rationale) ?? ""
29695
+ beliefId: readString35(row.beliefId) ?? "",
29696
+ confidence: readNumber23(row.confidence) ?? Number.NaN,
29697
+ rationale: readString35(row.rationale) ?? ""
28449
29698
  };
28450
29699
  }).filter((entry) => entry !== null);
28451
29700
  }
@@ -28464,22 +29713,22 @@ function handleWorktreesError(error, fallbackMessage, correlationId, policyTrace
28464
29713
  }
28465
29714
  async function handleWorktreeCreate(args) {
28466
29715
  try {
28467
- const body = asRecord32(args.body);
29716
+ const body = asRecord33(args.body);
28468
29717
  const goCriteria = readStringArray18(body.goCriteria);
28469
29718
  const noGoSignals = readStringArray18(body.noGoSignals);
28470
29719
  const payload = await createWorktreeFromGatewayAuth(args.authContext, {
28471
- title: readString34(body.title) ?? readString34(body.name) ?? "",
28472
- topicId: readString34(body.topicId ?? body.projectId) ?? "",
28473
- topicHint: readString34(body.topicHint),
28474
- objective: readString34(body.objective),
28475
- hypothesis: readString34(body.hypothesis),
28476
- rationale: readString34(body.rationale),
28477
- worktreeType: readString34(body.worktreeType),
28478
- startDate: readNumber22(body.startDate),
28479
- endDate: readNumber22(body.endDate),
28480
- durationWeeks: readNumber22(body.durationWeeks),
29720
+ title: readString35(body.title) ?? readString35(body.name) ?? "",
29721
+ topicId: readString35(body.topicId ?? body.projectId) ?? "",
29722
+ topicHint: readString35(body.topicHint),
29723
+ objective: readString35(body.objective),
29724
+ hypothesis: readString35(body.hypothesis),
29725
+ rationale: readString35(body.rationale),
29726
+ worktreeType: readString35(body.worktreeType),
29727
+ startDate: readNumber23(body.startDate),
29728
+ endDate: readNumber23(body.endDate),
29729
+ durationWeeks: readNumber23(body.durationWeeks),
28481
29730
  confidenceImpact: readConfidenceImpact(body.confidenceImpact),
28482
- beliefFocus: readString34(body.beliefFocus),
29731
+ beliefFocus: readString35(body.beliefFocus),
28483
29732
  beliefIds: readStringArray18(body.targetBeliefIds) ?? readStringArray18(body.beliefIds) ?? readStringArray18(body.beliefs),
28484
29733
  targetBeliefIds: readStringArray18(body.targetBeliefIds),
28485
29734
  targetQuestionIds: readStringArray18(body.targetQuestionIds),
@@ -28490,23 +29739,23 @@ async function handleWorktreeCreate(args) {
28490
29739
  noGoSignals: noGoSignals ?? []
28491
29740
  } : void 0,
28492
29741
  autoShape: typeof body.autoShape === "boolean" ? body.autoShape : void 0,
28493
- domainPackId: readString34(body.domainPackId),
29742
+ domainPackId: readString35(body.domainPackId),
28494
29743
  tags: readStringArray18(body.tags),
28495
29744
  touchedPaths: readStringArray18(body.touchedPaths),
28496
- sourceRef: readString34(body.sourceRef),
28497
- sourceKind: readString34(body.sourceKind),
28498
- campaign: readNumber22(body.campaign),
28499
- lane: readString34(body.lane),
28500
- laneOrderInCampaign: readNumber22(body.laneOrderInCampaign),
28501
- orderInLane: readNumber22(body.orderInLane),
29745
+ sourceRef: readString35(body.sourceRef),
29746
+ sourceKind: readString35(body.sourceKind),
29747
+ campaign: readNumber23(body.campaign),
29748
+ lane: readString35(body.lane),
29749
+ laneOrderInCampaign: readNumber23(body.laneOrderInCampaign),
29750
+ orderInLane: readNumber23(body.orderInLane),
28502
29751
  dependsOn: readStringArray18(body.dependsOn),
28503
29752
  blocks: readStringArray18(body.blocks),
28504
- gate: readString34(body.gate),
29753
+ gate: readString35(body.gate),
28505
29754
  proofArtifacts: Array.isArray(body.proofArtifacts) ? body.proofArtifacts : void 0,
28506
- staffingHint: readString34(body.staffingHint),
28507
- lastReconciledAt: readNumber22(body.lastReconciledAt),
29755
+ staffingHint: readString35(body.staffingHint),
29756
+ lastReconciledAt: readNumber23(body.lastReconciledAt),
28508
29757
  autoFixPolicy: body.autoFixPolicy && typeof body.autoFixPolicy === "object" && !Array.isArray(body.autoFixPolicy) ? body.autoFixPolicy : void 0,
28509
- lensId: readString34(body.lensId)
29758
+ lensId: readString35(body.lensId)
28510
29759
  });
28511
29760
  return successResponse(payload, {
28512
29761
  status: 201,
@@ -28525,12 +29774,12 @@ async function handleWorktreeCreate(args) {
28525
29774
  async function handleWorktreeList(args) {
28526
29775
  try {
28527
29776
  const payload = await listWorktreesFromGatewayAuth(args.authContext, {
28528
- topicId: readString34(args.query.topicId) ?? "",
28529
- status: readString34(args.query.status),
28530
- groupBy: readString34(args.query.groupBy),
28531
- lane: readString34(args.query.lane),
28532
- campaign: readNumber22(args.query.campaign),
28533
- limit: readNumber22(args.query.limit)
29777
+ topicId: readString35(args.query.topicId) ?? "",
29778
+ status: readString35(args.query.status),
29779
+ groupBy: readString35(args.query.groupBy),
29780
+ lane: readString35(args.query.lane),
29781
+ campaign: readNumber23(args.query.campaign),
29782
+ limit: readNumber23(args.query.limit)
28534
29783
  });
28535
29784
  return successResponse(payload, {
28536
29785
  correlationId: args.correlationId,
@@ -28548,11 +29797,11 @@ async function handleWorktreeList(args) {
28548
29797
  async function handleWorktreeListAll(args) {
28549
29798
  try {
28550
29799
  const payload = await listAllWorktreesFromGatewayAuth(args.authContext, {
28551
- status: readString34(args.query.status),
28552
- lane: readString34(args.query.lane),
28553
- campaign: readNumber22(args.query.campaign),
28554
- groupBy: readString34(args.query.groupBy),
28555
- limit: readNumber22(args.query.limit)
29800
+ status: readString35(args.query.status),
29801
+ lane: readString35(args.query.lane),
29802
+ campaign: readNumber23(args.query.campaign),
29803
+ groupBy: readString35(args.query.groupBy),
29804
+ limit: readNumber23(args.query.limit)
28556
29805
  });
28557
29806
  return successResponse(payload, {
28558
29807
  correlationId: args.correlationId,
@@ -28570,9 +29819,9 @@ async function handleWorktreeListAll(args) {
28570
29819
  async function handleWorktreeListCampaigns(args) {
28571
29820
  try {
28572
29821
  const payload = await listCampaignsFromGatewayAuth(args.authContext, {
28573
- topicId: readString34(args.query.topicId),
28574
- status: readString34(args.query.status),
28575
- limit: readNumber22(args.query.limit)
29822
+ topicId: readString35(args.query.topicId),
29823
+ status: readString35(args.query.status),
29824
+ limit: readNumber23(args.query.limit)
28576
29825
  });
28577
29826
  return successResponse(payload, {
28578
29827
  correlationId: args.correlationId,
@@ -28607,27 +29856,27 @@ async function handleWorktreeActivate(args) {
28607
29856
  }
28608
29857
  async function handleWorktreeUpdate(args) {
28609
29858
  try {
28610
- const body = asRecord32(args.body);
29859
+ const body = asRecord33(args.body);
28611
29860
  const payload = await updateWorktreeFromGatewayAuth(args.authContext, {
28612
29861
  id: args.worktreeId,
28613
- objective: readString34(body.objective),
28614
- hypothesis: readString34(body.hypothesis),
28615
- rationale: readString34(body.rationale),
28616
- campaign: readNumber22(body.campaign),
28617
- lane: readString34(body.lane),
28618
- laneOrderInCampaign: readNumber22(body.laneOrderInCampaign),
28619
- orderInLane: readNumber22(body.orderInLane),
29862
+ objective: readString35(body.objective),
29863
+ hypothesis: readString35(body.hypothesis),
29864
+ rationale: readString35(body.rationale),
29865
+ campaign: readNumber23(body.campaign),
29866
+ lane: readString35(body.lane),
29867
+ laneOrderInCampaign: readNumber23(body.laneOrderInCampaign),
29868
+ orderInLane: readNumber23(body.orderInLane),
28620
29869
  dependsOn: readStringArray18(body.dependsOn),
28621
29870
  blocks: readStringArray18(body.blocks),
28622
- gate: readString34(body.gate),
28623
- status: readString34(body.status),
28624
- topicId: readString34(body.topicId),
29871
+ gate: readString35(body.gate),
29872
+ status: readString35(body.status),
29873
+ topicId: readString35(body.topicId),
28625
29874
  additionalTopicIds: readStringArray18(body.additionalTopicIds),
28626
29875
  proofArtifacts: Array.isArray(body.proofArtifacts) ? body.proofArtifacts : void 0,
28627
- staffingHint: readString34(body.staffingHint),
28628
- lastReconciledAt: readNumber22(body.lastReconciledAt),
29876
+ staffingHint: readString35(body.staffingHint),
29877
+ lastReconciledAt: readNumber23(body.lastReconciledAt),
28629
29878
  autoFixPolicy: body.autoFixPolicy && typeof body.autoFixPolicy === "object" ? body.autoFixPolicy : void 0,
28630
- lensId: readString34(body.lensId)
29879
+ lensId: readString35(body.lensId)
28631
29880
  });
28632
29881
  return successResponse(payload, {
28633
29882
  correlationId: args.correlationId,
@@ -28644,11 +29893,11 @@ async function handleWorktreeUpdate(args) {
28644
29893
  }
28645
29894
  async function handleWorktreeMerge(args) {
28646
29895
  try {
28647
- const body = asRecord32(args.body);
29896
+ const body = asRecord33(args.body);
28648
29897
  const outcomes = normalizeMergeOutcomes2(body.outcomes);
28649
29898
  const payload = await mergeWorktreeFromGatewayAuth(args.authContext, {
28650
29899
  id: args.worktreeId,
28651
- summary: readString34(body.summary),
29900
+ summary: readString35(body.summary),
28652
29901
  outcomes
28653
29902
  });
28654
29903
  return successResponse(payload, {
@@ -28666,7 +29915,7 @@ async function handleWorktreeMerge(args) {
28666
29915
  }
28667
29916
  async function handleWorktreeUpdateTargets(args) {
28668
29917
  try {
28669
- const body = asRecord32(args.body);
29918
+ const body = asRecord33(args.body);
28670
29919
  const payload = await updateWorktreeTargetsFromGatewayAuth(
28671
29920
  args.authContext,
28672
29921
  {
@@ -28692,11 +29941,11 @@ async function handleWorktreeUpdateTargets(args) {
28692
29941
  }
28693
29942
  async function handleWorktreeComplete(args) {
28694
29943
  try {
28695
- const body = asRecord32(args.body);
29944
+ const body = asRecord33(args.body);
28696
29945
  const payload = await completeWorktreeRecordFromGatewayAuth(
28697
29946
  args.authContext,
28698
29947
  {
28699
- worktreeId: readString34(body.worktreeId) ?? "",
29948
+ worktreeId: readString35(body.worktreeId) ?? "",
28700
29949
  keyFindings: readStringArray18(body.keyFindings),
28701
29950
  decisionsReached: readStringArray18(body.decisionsReached),
28702
29951
  nextSteps: readStringArray18(body.nextSteps)
@@ -28717,9 +29966,9 @@ async function handleWorktreeComplete(args) {
28717
29966
  }
28718
29967
  async function handleWorktreeAdvancePhase(args) {
28719
29968
  try {
28720
- const body = asRecord32(args.body);
29969
+ const body = asRecord33(args.body);
28721
29970
  const payload = await advanceWorktreePhaseFromGatewayAuth(args.authContext, {
28722
- worktreeId: readString34(body.worktreeId) ?? ""
29971
+ worktreeId: readString35(body.worktreeId) ?? ""
28723
29972
  });
28724
29973
  return successResponse(payload, {
28725
29974
  correlationId: args.correlationId,
@@ -28736,10 +29985,10 @@ async function handleWorktreeAdvancePhase(args) {
28736
29985
  }
28737
29986
  async function handleWorktreeSetPhase(args) {
28738
29987
  try {
28739
- const body = asRecord32(args.body);
29988
+ const body = asRecord33(args.body);
28740
29989
  const payload = await setWorktreePhaseFromGatewayAuth(args.authContext, {
28741
- worktreeId: readString34(body.worktreeId) ?? "",
28742
- phase: readString34(body.phase) ?? ""
29990
+ worktreeId: readString35(body.worktreeId) ?? "",
29991
+ phase: readString35(body.phase) ?? ""
28743
29992
  });
28744
29993
  return successResponse(payload, {
28745
29994
  correlationId: args.correlationId,
@@ -28756,12 +30005,12 @@ async function handleWorktreeSetPhase(args) {
28756
30005
  }
28757
30006
  async function handleWorktreePatchState(args) {
28758
30007
  try {
28759
- const body = asRecord32(args.body);
30008
+ const body = asRecord33(args.body);
28760
30009
  const payload = await patchWorktreeStateFromGatewayAuth(
28761
30010
  args.authContext,
28762
30011
  {
28763
- worktreeId: readString34(body.worktreeId) ?? "",
28764
- patch: asRecord32(body.patch)
30012
+ worktreeId: readString35(body.worktreeId) ?? "",
30013
+ patch: asRecord33(body.patch)
28765
30014
  }
28766
30015
  );
28767
30016
  return successResponse(payload, {
@@ -28779,7 +30028,7 @@ async function handleWorktreePatchState(args) {
28779
30028
  }
28780
30029
  async function handleWorktreeBulkCreate(args) {
28781
30030
  try {
28782
- const body = asRecord32(args.body);
30031
+ const body = asRecord33(args.body);
28783
30032
  const payload = await bulkCreateWorktreesFromGatewayAuth(args.authContext, {
28784
30033
  worktrees: Array.isArray(body.worktrees) ? body.worktrees : []
28785
30034
  });
@@ -28798,6 +30047,6 @@ async function handleWorktreeBulkCreate(args) {
28798
30047
  }
28799
30048
  }
28800
30049
 
28801
- export { extractPermitWebhookTenantKeys, handleBeliefArchive, handleBeliefBatchUpdateCriticality, handleBeliefBisect, handleBeliefConfidenceHistory, handleBeliefCreate, handleBeliefCreateContract, handleBeliefFork, handleBeliefGet, handleBeliefLineage, handleBeliefLink, handleBeliefList, handleBeliefReassignTopic, handleBeliefRefine, handleBeliefRelationships, handleBeliefUnlinkEvidence, handleBeliefUpdateConfidence, handleBeliefUpdateCriticality, handleBeliefUpdateRationale, handleBeliefUpdateStatus, handleContradictionFlag, handleContradictionGet, handleContradictionList, handleEdgeBatchCreate, handleEdgeCreate, handleEdgeDelete, handleEdgeList, handleEdgeRemove, handleEdgeTraverse, handleEdgeUpdate, handleEdgesRemoveBetween, handleEventsList, handleEventsReplay, handleEvidenceClassify, handleEvidenceClassifyBatch, handleEvidenceCreate, handleEvidenceFlagIncorrect, handleEvidenceGet, handleEvidenceLink, handleEvidenceList, handleEvidenceRemove, handleEvidenceSearch, handleEvidenceUpdate, handleEvidenceUpdateStatus, handleEvidenceUpdateVerificationStatus, handleGraphAnalysisCompute, handleGraphAnalysisLatest, handleGraphAnalysisList, handleGraphAnalysisListChanges, handleGraphAnalysisListSuggestions, handleGraphAnalysisSave, handleGraphAnalysisSaveSuggestions, handleGraphAnalysisUpdateSuggestion, handleGraphAnalyze, handleGraphBias, handleGraphEdgeList, handleGraphFalsify, handleGraphGaps, handleGraphNeighborhood, handleGraphNodeList, handleGraphRecommendationGet, handleGraphRecommendationStatus, handleGraphRecommendationsList, handleGraphTraverse, handleIdentityWhoami, handleOntologyBind, handleOntologyGet, handleOntologyList, handleOntologyMatch, handleOrgGraphByProvenance, handleOrgGraphNodeGet, handleOrgGraphPublished, handleOrgGraphSearch, handlePermitProjectionWebhook, handleQuestionAdd, handleQuestionAdvanceToConviction, handleQuestionAnswer, handleQuestionArchive, handleQuestionBatchCreate, handleQuestionCreate, handleQuestionDelete, handleQuestionFinalizeConviction, handleQuestionGet, handleQuestionGetAnswer, handleQuestionList, handleQuestionRefine, handleQuestionUpdate, handleQuestionUpdateConviction, handleQuestionUpdatePriority, handleQuestionUpdateStatus, handleSearchResources, handleSourceGet, handleSourceUpsert, handleTaskComplete, handleTaskCreate, handleTaskList, handleTaskUpdate, handleTopicBulkCreate, handleTopicCoverage, handleTopicCreate, handleTopicGet, handleTopicList, handleTopicRemove, handleTopicTree, handleTopicUpdate, handleWebhookCreate, handleWebhookDelete, handleWebhookDeliveries, handleWebhookGet, handleWebhookHealth, handleWebhookList, handleWebhookTest, handleWebhookUpdate, handleWorktreeActivate, handleWorktreeAdvancePhase, handleWorktreeBulkCreate, handleWorktreeComplete, handleWorktreeCreate, handleWorktreeList, handleWorktreeListAll, handleWorktreeListCampaigns, handleWorktreeMerge, handleWorktreePatchState, handleWorktreeSetPhase, handleWorktreeUpdate, handleWorktreeUpdateTargets, isPermitWebhookAuthorized };
30050
+ export { __testOnly, extractPermitWebhookTenantKeys, handleBeliefArchive, handleBeliefBatchUpdateCriticality, handleBeliefBisect, handleBeliefConfidenceHistory, handleBeliefCreate, handleBeliefCreateContract, handleBeliefFork, handleBeliefGet, handleBeliefLineage, handleBeliefLink, handleBeliefList, handleBeliefReassignTopic, handleBeliefRefine, handleBeliefRelationships, handleBeliefUnlinkEvidence, handleBeliefUpdateConfidence, handleBeliefUpdateCriticality, handleBeliefUpdateRationale, handleBeliefUpdateStatus, handleClerkWebhook, handleContradictionFlag, handleContradictionGet, handleContradictionList, handleEdgeBatchCreate, handleEdgeCreate, handleEdgeDelete, handleEdgeList, handleEdgeRemove, handleEdgeTraverse, handleEdgeUpdate, handleEdgesRemoveBetween, handleEventsList, handleEventsReplay, handleEvidenceClassify, handleEvidenceClassifyBatch, handleEvidenceCreate, handleEvidenceFlagIncorrect, handleEvidenceGet, handleEvidenceLink, handleEvidenceList, handleEvidenceRemove, handleEvidenceSearch, handleEvidenceUpdate, handleEvidenceUpdateStatus, handleEvidenceUpdateVerificationStatus, handleGraphAnalysisCompute, handleGraphAnalysisLatest, handleGraphAnalysisList, handleGraphAnalysisListChanges, handleGraphAnalysisListSuggestions, handleGraphAnalysisSave, handleGraphAnalysisSaveSuggestions, handleGraphAnalysisUpdateSuggestion, handleGraphAnalyze, handleGraphBias, handleGraphEdgeList, handleGraphFalsify, handleGraphGaps, handleGraphNeighborhood, handleGraphNodeList, handleGraphRecommendationGet, handleGraphRecommendationStatus, handleGraphRecommendationsList, handleGraphTraverse, handleIdentityWhoami, handleOntologyBind, handleOntologyGet, handleOntologyList, handleOntologyMatch, handleOrgGraphByProvenance, handleOrgGraphNodeGet, handleOrgGraphPublished, handleOrgGraphSearch, handlePermitProjectionWebhook, handleQuestionAdd, handleQuestionAdvanceToConviction, handleQuestionAnswer, handleQuestionArchive, handleQuestionBatchCreate, handleQuestionCreate, handleQuestionDelete, handleQuestionFinalizeConviction, handleQuestionGet, handleQuestionGetAnswer, handleQuestionList, handleQuestionRefine, handleQuestionUpdate, handleQuestionUpdateConviction, handleQuestionUpdatePriority, handleQuestionUpdateStatus, handleSearchResources, handleSourceGet, handleSourceUpsert, handleTaskComplete, handleTaskCreate, handleTaskList, handleTaskUpdate, handleTopicBulkCreate, handleTopicCoverage, handleTopicCreate, handleTopicGet, handleTopicList, handleTopicRemove, handleTopicTree, handleTopicUpdate, handleWebhookCreate, handleWebhookDelete, handleWebhookDeliveries, handleWebhookGet, handleWebhookHealth, handleWebhookList, handleWebhookTest, handleWebhookUpdate, handleWorktreeActivate, handleWorktreeAdvancePhase, handleWorktreeBulkCreate, handleWorktreeComplete, handleWorktreeCreate, handleWorktreeList, handleWorktreeListAll, handleWorktreeListCampaigns, handleWorktreeMerge, handleWorktreePatchState, handleWorktreeSetPhase, handleWorktreeUpdate, handleWorktreeUpdateTargets, hasPermitWebhookTenantScope, isPermitWebhookAuthorized };
28802
30051
  //# sourceMappingURL=gateway.js.map
28803
30052
  //# sourceMappingURL=gateway.js.map