@lucern/mcp 0.3.0-alpha.16 → 0.3.0-alpha.17

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
@@ -810,7 +810,7 @@ defineTable({
810
810
  shape: z.object({
811
811
  "tenantId": idOf("tenants").optional(),
812
812
  "apiKeyId": idOf("apiKeys").optional(),
813
- "action": z.enum(["key_created", "key_revoked", "key_expired", "key_used", "tenant_secret_created", "tenant_secret_rotated", "tenant_secret_revoked", "tenant_slot_binding_upserted", "tenant_slot_binding_revoked", "proxy_token_minted", "proxy_token_lease_issued", "proxy_token_lease_renewed", "proxy_token_lease_revoked", "proxy_request_recorded", "tenant_created", "tenant_updated", "tenant_suspended", "tenant_archived", "tenant_reactivated", "principal_created", "principal_updated", "principal_suspended", "principal_identity_alias_upserted", "principal_identity_alias_revoked", "membership_created", "membership_updated", "membership_revoked", "group_created", "group_updated", "group_deleted", "group_member_added", "group_member_removed", "workspace_created", "workspace_updated", "workspace_archived", "workspace_deployment_set", "workspace_deployment_removed", "deployment_host_registered", "deployment_host_revoked", "service_key_created", "service_key_rotated", "service_key_revoked", "service_key_used", "service_key_auth_failed", "session_created", "session_validated", "session_revoked", "session_cascade_revoked", "session_expired", "sandbox_created", "sandbox_secret_injected", "sandbox_execution_started", "sandbox_execution_completed", "sandbox_limit_violated", "policy_created", "policy_updated", "policy_enforced", "policy_archived", "permit_sync_enqueued", "permit_sync_succeeded", "permit_sync_failed", "permit_sync_skipped", "agent_registered", "agent_updated", "tool_registered", "tool_updated", "pack_entitled", "pack_installed", "pack_enabled", "pack_disabled", "pack_entitlement_revoked", "pack_upgraded", "pack_upgrade_committed", "pack_upgrade_rolled_back", "pack_group_assigned", "pack_group_unassigned", "methodology_pack_created", "methodology_pack_updated", "methodology_pack_assigned", "methodology_pack_removed", "pack_assigned_to_group", "pack_revoked_from_group", "pack_ontology_materialized", "pack_ontology_topic_bound", "cutover_flag_set", "cutover_flag_cleared"]),
813
+ "action": z.enum(["key_created", "key_revoked", "key_expired", "key_used", "tenant_secret_created", "tenant_secret_rotated", "tenant_secret_revoked", "tenant_slot_binding_upserted", "tenant_slot_binding_revoked", "proxy_token_minted", "proxy_token_lease_issued", "proxy_token_lease_renewed", "proxy_token_lease_revoked", "proxy_request_recorded", "tenant_created", "tenant_updated", "tenant_suspended", "tenant_archived", "tenant_reactivated", "tenant_clerk_organization_linked", "principal_created", "principal_updated", "principal_suspended", "principal_identity_alias_upserted", "principal_identity_alias_revoked", "membership_created", "membership_updated", "membership_revoked", "group_created", "group_updated", "group_deleted", "group_member_added", "group_member_removed", "workspace_created", "workspace_updated", "workspace_archived", "workspace_deployment_set", "workspace_deployment_removed", "deployment_host_registered", "deployment_host_revoked", "service_key_created", "service_key_rotated", "service_key_revoked", "service_key_used", "service_key_auth_failed", "session_created", "session_validated", "session_revoked", "session_cascade_revoked", "session_expired", "sandbox_created", "sandbox_secret_injected", "sandbox_execution_started", "sandbox_execution_completed", "sandbox_limit_violated", "policy_created", "policy_updated", "policy_enforced", "policy_archived", "permit_sync_enqueued", "permit_sync_succeeded", "permit_sync_failed", "permit_sync_skipped", "agent_registered", "agent_updated", "tool_registered", "tool_updated", "pack_entitled", "pack_installed", "pack_enabled", "pack_disabled", "pack_entitlement_revoked", "pack_upgraded", "pack_upgrade_committed", "pack_upgrade_rolled_back", "pack_group_assigned", "pack_group_unassigned", "methodology_pack_created", "methodology_pack_updated", "methodology_pack_assigned", "methodology_pack_removed", "pack_assigned_to_group", "pack_revoked_from_group", "pack_ontology_materialized", "pack_ontology_topic_bound", "cutover_flag_set", "cutover_flag_cleared"]),
814
814
  "actorClerkId": z.string(),
815
815
  "details": z.any().optional(),
816
816
  "createdAt": z.number()
@@ -9448,7 +9448,7 @@ var IDENTITY_WHOAMI = {
9448
9448
  response: {
9449
9449
  description: "Canonical identity summary for the current session",
9450
9450
  fields: {
9451
- principalId: "string \u2014 canonical federated principal identifier",
9451
+ principalId: "string \u2014 canonical principal identifier; for humans this is the Clerk user_... ID",
9452
9452
  principalType: "string \u2014 human, service, agent, group, or external_viewer",
9453
9453
  tenantId: "string | undefined \u2014 resolved tenant scope",
9454
9454
  workspaceId: "string | undefined \u2014 resolved workspace scope",
@@ -9462,7 +9462,7 @@ var IDENTITY_WHOAMI = {
9462
9462
  };
9463
9463
  var RESOLVE_INTERACTIVE_PRINCIPAL = {
9464
9464
  name: "resolve_interactive_principal",
9465
- 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.",
9465
+ 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 Clerk subject into tenant/workspace authorization context.",
9466
9466
  parameters: {
9467
9467
  clerkId: {
9468
9468
  type: "string",
@@ -9485,7 +9485,7 @@ var RESOLVE_INTERACTIVE_PRINCIPAL = {
9485
9485
  response: {
9486
9486
  description: "Permit-backed Lucern principal context for tenant SDK bootstrap",
9487
9487
  fields: {
9488
- principalId: "string \u2014 canonical Lucern principal identifier",
9488
+ principalId: "string \u2014 canonical Clerk user_... ID for human sessions",
9489
9489
  principalType: "string \u2014 human, service, agent, group, or external_viewer",
9490
9490
  clerkId: "string \u2014 authenticated Clerk subject alias",
9491
9491
  tenantId: "string \u2014 resolved tenant scope",
@@ -10313,7 +10313,7 @@ var MANAGE_WRITE_POLICY = {
10313
10313
  },
10314
10314
  role: {
10315
10315
  type: "string",
10316
- description: "Role to set policy for (required for 'set'). E.g. 'agent:internal', 'user:analyst'."
10316
+ description: "Role to set policy for (required for 'set'). E.g. 'agent:internal' or a Permit role key such as 'workspace_admin'."
10317
10317
  },
10318
10318
  permission: {
10319
10319
  type: "string",
@@ -14094,6 +14094,19 @@ var worktreeEvidenceSignalInputSchema = z.object({
14094
14094
  progress: z.string().optional().describe("Collection progress note for the signal."),
14095
14095
  notes: z.string().optional().describe("Additional evidence collection notes.")
14096
14096
  }).passthrough().describe("Evidence signal embedded in the worktree plan.");
14097
+ var worktreeDocCompanionTargetSchema = z.object({
14098
+ docPath: z.string().describe(
14099
+ "Repo-relative path to a documentation file the worktree promises to update."
14100
+ ),
14101
+ sectionAnchor: z.string().optional().describe(
14102
+ "Markdown heading anchor (e.g. '## Function-surface manifest') that scopes the promised update."
14103
+ ),
14104
+ reason: z.string().describe(
14105
+ "Why this doc section must be updated for the worktree to be complete."
14106
+ )
14107
+ }).passthrough().describe(
14108
+ "Intent-driven docs companion target. pr-gate-reviewer verifies that the PR actually touches each declared (docPath, sectionAnchor). Distinct from the touch-driven docs-loop. See docs/development/docs-sync-discipline.md Lock 3."
14109
+ );
14097
14110
  var worktreeDecisionGateInputSchema = z.object({
14098
14111
  goCriteria: z.array(z.string()).describe("Criteria that must hold for the worktree to proceed."),
14099
14112
  noGoSignals: z.array(z.string()).describe("Signals that stop or redirect the worktree."),
@@ -14126,6 +14139,9 @@ var addWorktreeArgs = z.object({
14126
14139
  keyQuestions: z.array(worktreeKeyQuestionInputSchema).optional().describe("Inline key questions captured as part of the worktree plan."),
14127
14140
  evidenceSignals: z.array(worktreeEvidenceSignalInputSchema).optional().describe("Evidence signals the worktree needs to collect or validate."),
14128
14141
  decisionGate: worktreeDecisionGateInputSchema.optional(),
14142
+ docCompanionTargets: z.array(worktreeDocCompanionTargetSchema).optional().describe(
14143
+ "Doc sections the worktree promises to update at PR time. Enforced by pr-gate-reviewer (Lock 3)."
14144
+ ),
14129
14145
  goCriteria: z.array(z.string()).optional().describe("Shorthand go criteria used to build decisionGate."),
14130
14146
  noGoSignals: z.array(z.string()).optional().describe("Shorthand no-go signals used to build decisionGate."),
14131
14147
  proofArtifacts: z.array(z.unknown()).optional().describe("Expected proof artifacts required to close the worktree."),
@@ -18460,7 +18476,7 @@ async function resolveBeliefTopicId(ctx, beliefId) {
18460
18476
  if (!normalizedBeliefId) {
18461
18477
  return void 0;
18462
18478
  }
18463
- return fetchRecordTopicId(ctx, api.epistemicBeliefs.getById, {
18479
+ return fetchRecordTopicId(ctx, api.beliefs.getById, {
18464
18480
  beliefId: normalizedBeliefId,
18465
18481
  nodeId: normalizedBeliefId
18466
18482
  });
@@ -18470,7 +18486,7 @@ async function resolveQuestionTopicId(ctx, questionId) {
18470
18486
  if (!normalizedQuestionId) {
18471
18487
  return void 0;
18472
18488
  }
18473
- return fetchRecordTopicId(ctx, api.epistemicQuestions.getById, {
18489
+ return fetchRecordTopicId(ctx, api.questions.getById, {
18474
18490
  questionId: normalizedQuestionId,
18475
18491
  nodeId: normalizedQuestionId
18476
18492
  });
@@ -18875,7 +18891,7 @@ function readStringArray3(value) {
18875
18891
  async function resolveBeliefTopicIdWithGatewayAuth(authContext, beliefId) {
18876
18892
  const normalizedBeliefId = resolveExternalId(beliefId) ?? beliefId;
18877
18893
  const belief = await authContext.convex.query(
18878
- api.epistemicBeliefs.getById,
18894
+ api.beliefs.getById,
18879
18895
  {
18880
18896
  beliefId: normalizedBeliefId,
18881
18897
  nodeId: normalizedBeliefId
@@ -18905,13 +18921,13 @@ async function emitBeliefEventFromGatewayAuth(authContext, args) {
18905
18921
  function createGatewayBeliefPort(authContext) {
18906
18922
  return {
18907
18923
  fetchBelief(rawId) {
18908
- return authContext.convex.query(api.epistemicBeliefs.getById, {
18924
+ return authContext.convex.query(api.beliefs.getById, {
18909
18925
  beliefId: rawId,
18910
18926
  nodeId: rawId
18911
18927
  });
18912
18928
  },
18913
18929
  listBeliefsByTopic(args) {
18914
- return authContext.convex.query(api.epistemicBeliefs.getByTopic, {
18930
+ return authContext.convex.query(api.beliefs.getByTopic, {
18915
18931
  topicId: args.topicId,
18916
18932
  userId: authContext.userId,
18917
18933
  status: args.status,
@@ -18922,7 +18938,7 @@ function createGatewayBeliefPort(authContext) {
18922
18938
  });
18923
18939
  },
18924
18940
  createBelief(input) {
18925
- return authContext.convex.mutation(api.epistemicBeliefs.create, {
18941
+ return authContext.convex.mutation(api.beliefs.create, {
18926
18942
  topicId: input.topicId,
18927
18943
  formulation: input.text,
18928
18944
  rationale: input.rationale,
@@ -18939,7 +18955,7 @@ function createGatewayBeliefPort(authContext) {
18939
18955
  });
18940
18956
  },
18941
18957
  refineBelief(input) {
18942
- return authContext.convex.mutation(api.epistemicBeliefs.refineBelief, {
18958
+ return authContext.convex.mutation(api.beliefs.refineBelief, {
18943
18959
  nodeId: input.beliefRawId,
18944
18960
  canonicalText: input.text,
18945
18961
  rationale: input.rationale,
@@ -18947,7 +18963,7 @@ function createGatewayBeliefPort(authContext) {
18947
18963
  });
18948
18964
  },
18949
18965
  forkBelief(input) {
18950
- return authContext.convex.mutation(api.epistemicBeliefs.forkBelief, {
18966
+ return authContext.convex.mutation(api.beliefs.forkBelief, {
18951
18967
  parentNodeId: input.beliefRawId,
18952
18968
  newFormulation: input.text,
18953
18969
  forkReason: input.forkReason,
@@ -18956,7 +18972,7 @@ function createGatewayBeliefPort(authContext) {
18956
18972
  });
18957
18973
  },
18958
18974
  modulateConfidence(input) {
18959
- return authContext.convex.mutation(api.epistemicBeliefs.modulateConfidence, {
18975
+ return authContext.convex.mutation(api.beliefs.modulateConfidence, {
18960
18976
  nodeId: input.beliefRawId,
18961
18977
  trigger: input.trigger,
18962
18978
  rationale: input.rationale,
@@ -18973,25 +18989,25 @@ function createGatewayBeliefPort(authContext) {
18973
18989
  });
18974
18990
  },
18975
18991
  archiveBelief(input) {
18976
- return authContext.convex.mutation(api.epistemicBeliefs.archive, {
18992
+ return authContext.convex.mutation(api.beliefs.archive, {
18977
18993
  nodeId: input.beliefRawId,
18978
18994
  reason: input.reason,
18979
18995
  userId: authContext.userId
18980
18996
  });
18981
18997
  },
18982
18998
  getLineage(rawId) {
18983
- return authContext.convex.query(api.epistemicBeliefs.getLineage, {
18999
+ return authContext.convex.query(api.beliefs.getLineage, {
18984
19000
  nodeId: rawId
18985
19001
  });
18986
19002
  },
18987
19003
  getConfidenceHistory(rawId) {
18988
- return authContext.convex.query(api.epistemicBeliefs.getConfidenceHistory, {
19004
+ return authContext.convex.query(api.beliefs.getConfidenceHistory, {
18989
19005
  nodeId: rawId
18990
19006
  });
18991
19007
  },
18992
19008
  createContract(args) {
18993
19009
  return authContext.convex.mutation(
18994
- api.epistemicContracts.createEpistemicContract,
19010
+ api.contracts.createEpistemicContract,
18995
19011
  {
18996
19012
  beliefNodeId: args.beliefRawId,
18997
19013
  title: args.input.title,
@@ -19010,7 +19026,7 @@ function createGatewayBeliefPort(authContext) {
19010
19026
  );
19011
19027
  },
19012
19028
  getRelationships(rawId) {
19013
- return authContext.convex.query(api.epistemicBeliefs.getRelationships, {
19029
+ return authContext.convex.query(api.beliefs.getRelationships, {
19014
19030
  nodeId: rawId,
19015
19031
  direction: "both"
19016
19032
  });
@@ -19158,7 +19174,7 @@ async function getBeliefRelationshipsFromGatewayAuth(authContext, id, direction)
19158
19174
  }
19159
19175
  function updateBeliefStatusFromGatewayAuth(authContext, input) {
19160
19176
  const externalNodeId = input.id ?? input.nodeId ?? input.beliefId;
19161
- return authContext.convex.mutation(api.epistemicBeliefs.updateStatus, {
19177
+ return authContext.convex.mutation(api.beliefs.updateStatus, {
19162
19178
  nodeId: resolveBeliefNodeId(input),
19163
19179
  status: input.status,
19164
19180
  reason: input.reason,
@@ -19170,7 +19186,7 @@ function updateBeliefStatusFromGatewayAuth(authContext, input) {
19170
19186
  }
19171
19187
  function updateBeliefRationaleFromGatewayAuth(authContext, input) {
19172
19188
  const externalNodeId = input.id ?? input.nodeId ?? input.beliefId;
19173
- return authContext.convex.mutation(api.epistemicBeliefs.updateRationale, {
19189
+ return authContext.convex.mutation(api.beliefs.updateRationale, {
19174
19190
  nodeId: resolveBeliefNodeId(input),
19175
19191
  rationale: input.rationale,
19176
19192
  userId: authContext.userId
@@ -19180,7 +19196,7 @@ function updateBeliefRationaleFromGatewayAuth(authContext, input) {
19180
19196
  }));
19181
19197
  }
19182
19198
  function linkBeliefsFromGatewayAuth(authContext, input) {
19183
- return authContext.convex.mutation(api.epistemicBeliefs.linkBeliefs, {
19199
+ return authContext.convex.mutation(api.beliefs.linkBeliefs, {
19184
19200
  fromNodeId: resolveExternalId(input.fromNodeId) ?? "",
19185
19201
  toNodeId: resolveExternalId(input.toNodeId) ?? "",
19186
19202
  edgeType: input.edgeType,
@@ -19190,7 +19206,7 @@ function linkBeliefsFromGatewayAuth(authContext, input) {
19190
19206
  });
19191
19207
  }
19192
19208
  function unlinkBeliefEvidenceFromGatewayAuth(authContext, input) {
19193
- return authContext.convex.mutation(api.epistemicBeliefs.unlinkEvidence, {
19209
+ return authContext.convex.mutation(api.beliefs.unlinkEvidence, {
19194
19210
  beliefNodeId: input.beliefNodeId ?? resolveExternalId(input.beliefId) ?? resolveExternalId(input.nodeId) ?? "",
19195
19211
  insightId: resolveExternalId(input.insightId ?? input.evidenceId) ?? "",
19196
19212
  userId: authContext.userId
@@ -19198,7 +19214,7 @@ function unlinkBeliefEvidenceFromGatewayAuth(authContext, input) {
19198
19214
  }
19199
19215
  function updateBeliefCriticalityFromGatewayAuth(authContext, input) {
19200
19216
  const externalNodeId = input.id ?? input.nodeId ?? input.beliefId;
19201
- return authContext.convex.mutation(api.epistemicBeliefs.updateCriticality, {
19217
+ return authContext.convex.mutation(api.beliefs.updateCriticality, {
19202
19218
  nodeId: resolveBeliefNodeId(input),
19203
19219
  criticality: input.criticality,
19204
19220
  userId: authContext.userId
@@ -19208,7 +19224,7 @@ function updateBeliefCriticalityFromGatewayAuth(authContext, input) {
19208
19224
  }));
19209
19225
  }
19210
19226
  function batchUpdateBeliefCriticalityFromGatewayAuth(authContext, input) {
19211
- return authContext.convex.mutation(api.epistemicBeliefs.batchUpdateCriticality, {
19227
+ return authContext.convex.mutation(api.beliefs.batchUpdateCriticality, {
19212
19228
  updates: input.updates.map((update) => ({
19213
19229
  ...update,
19214
19230
  beliefId: resolveExternalId(update.beliefId) ?? update.beliefId,
@@ -19223,7 +19239,7 @@ function batchUpdateBeliefCriticalityFromGatewayAuth(authContext, input) {
19223
19239
  });
19224
19240
  }
19225
19241
  function reassignBeliefsTopicFromGatewayAuth(authContext, input) {
19226
- return authContext.convex.mutation(api.epistemicBeliefs.reassignBeliefsTopic, {
19242
+ return authContext.convex.mutation(api.beliefs.reassignBeliefsTopic, {
19227
19243
  beliefNodeIds: (input.beliefNodeIds ?? input.beliefIds ?? []).map(
19228
19244
  (id) => resolveExternalId(id) ?? id
19229
19245
  ),
@@ -19519,7 +19535,7 @@ async function emitContradictionEventFromGatewayAuth(authContext, args) {
19519
19535
  function createGatewayContradictionsPort(authContext) {
19520
19536
  return {
19521
19537
  fetchBelief(rawId) {
19522
- return authContext.convex.query(api.epistemicBeliefs.getById, {
19538
+ return authContext.convex.query(api.beliefs.getById, {
19523
19539
  beliefId: rawId
19524
19540
  });
19525
19541
  },
@@ -19841,7 +19857,7 @@ async function fetchNodeWithQuery(runQuery, id) {
19841
19857
  const rawId = resolveNodeId(id);
19842
19858
  const byNodeId = await queryWithFallback(
19843
19859
  `fetchNodeWithQuery local id lookup for ${id}`,
19844
- () => runQuery(api.epistemicNodes.get, {
19860
+ () => runQuery(api.nodes.get, {
19845
19861
  nodeId: rawId
19846
19862
  }),
19847
19863
  null
@@ -19851,7 +19867,7 @@ async function fetchNodeWithQuery(runQuery, id) {
19851
19867
  }
19852
19868
  return await queryWithFallback(
19853
19869
  `fetchNodeWithQuery global id lookup for ${id}`,
19854
- () => runQuery(api.epistemicNodes.getByGlobalId, {
19870
+ () => runQuery(api.nodes.getByGlobalId, {
19855
19871
  globalId: id
19856
19872
  }),
19857
19873
  null
@@ -19939,7 +19955,7 @@ function createGatewayEdgesPort(authContext) {
19939
19955
  input.targetRawId
19940
19956
  );
19941
19957
  const inferredTopicId = input.topicId ?? resolveTopicIdFromNode(sourceNode) ?? resolveTopicIdFromNode(targetNode);
19942
- return authContext.convex.mutation(api.epistemicEdges.create, {
19958
+ return authContext.convex.mutation(api.edges.create, {
19943
19959
  fromNodeId: input.sourceRawId,
19944
19960
  toNodeId: input.targetRawId,
19945
19961
  edgeType: input.edgeType,
@@ -19964,7 +19980,7 @@ function createGatewayEdgesPort(authContext) {
19964
19980
  "list"
19965
19981
  );
19966
19982
  const rows = await authContext.convex.query(
19967
- api.epistemicEdges.getBySourceNode,
19983
+ api.edges.getBySourceNode,
19968
19984
  {
19969
19985
  sourceNodeId: args.sourceRawId,
19970
19986
  edgeType: args.edgeType
@@ -20006,7 +20022,7 @@ function traverseEdgesFromGatewayAuth(authContext, input) {
20006
20022
  return traverseEdges(createGatewayEdgesPort(authContext), input);
20007
20023
  }
20008
20024
  function updateEdgeFromGatewayAuth(authContext, input) {
20009
- return authContext.convex.mutation(api.epistemicEdges.update, {
20025
+ return authContext.convex.mutation(api.edges.update, {
20010
20026
  edgeId: resolveExternalId2(input.edgeId) ?? input.edgeId,
20011
20027
  weight: input.weight,
20012
20028
  confidence: input.confidence,
@@ -20016,13 +20032,13 @@ function updateEdgeFromGatewayAuth(authContext, input) {
20016
20032
  });
20017
20033
  }
20018
20034
  function removeEdgeFromGatewayAuth(authContext, input) {
20019
- return authContext.convex.mutation(api.epistemicEdges.remove, {
20035
+ return authContext.convex.mutation(api.edges.remove, {
20020
20036
  edgeId: resolveExternalId2(input.edgeId) ?? input.edgeId,
20021
20037
  userId: authContext.userId
20022
20038
  });
20023
20039
  }
20024
20040
  function removeEdgesBetweenFromGatewayAuth(authContext, input) {
20025
- return authContext.convex.mutation(api.epistemicEdges.removeBetween, {
20041
+ return authContext.convex.mutation(api.edges.removeBetween, {
20026
20042
  fromNodeId: resolveExternalId2(input.fromNodeId) ?? input.fromNodeId,
20027
20043
  toNodeId: resolveExternalId2(input.toNodeId) ?? input.toNodeId,
20028
20044
  edgeType: input.edgeType,
@@ -20030,7 +20046,7 @@ function removeEdgesBetweenFromGatewayAuth(authContext, input) {
20030
20046
  });
20031
20047
  }
20032
20048
  function batchCreateEdgesFromGatewayAuth(authContext, input) {
20033
- return authContext.convex.mutation(api.epistemicEdges.batchCreate, {
20049
+ return authContext.convex.mutation(api.edges.batchCreate, {
20034
20050
  edges: input.edges.map((edge) => ({
20035
20051
  globalId: edge.globalId ?? randomUUID(),
20036
20052
  fromNodeId: resolveExternalId2(edge.fromNodeId ?? edge.sourceId) ?? edge.fromNodeId ?? edge.sourceId ?? "",
@@ -20049,7 +20065,7 @@ function batchCreateEdgesFromGatewayAuth(authContext, input) {
20049
20065
  });
20050
20066
  }
20051
20067
  function deleteEdgesFromGatewayAuth(authContext, input) {
20052
- return authContext.convex.mutation(api.epistemicEdges.deleteEdges, {
20068
+ return authContext.convex.mutation(api.edges.deleteEdges, {
20053
20069
  edgeIds: input.edgeIds.map((edgeId) => resolveExternalId2(edgeId) ?? edgeId),
20054
20070
  userId: authContext.userId
20055
20071
  });
@@ -20377,14 +20393,14 @@ function resolveExternalId3(value) {
20377
20393
  }
20378
20394
  }
20379
20395
  async function resolveEvidenceTopicIdWithGatewayAuth(authContext, evidenceId) {
20380
- const evidence = await authContext.convex.query(api.epistemicEvidence.getById, {
20396
+ const evidence = await authContext.convex.query(api.evidence.getById, {
20381
20397
  evidenceId,
20382
20398
  nodeId: evidenceId
20383
20399
  });
20384
20400
  return readString8(evidence?.topicId);
20385
20401
  }
20386
20402
  async function resolveEvidenceNodeIdWithGatewayAuth(authContext, evidenceId) {
20387
- const evidence = await authContext.convex.query(api.epistemicEvidence.getById, {
20403
+ const evidence = await authContext.convex.query(api.evidence.getById, {
20388
20404
  evidenceId,
20389
20405
  nodeId: evidenceId
20390
20406
  });
@@ -20412,20 +20428,20 @@ async function emitEvidenceEventFromGatewayAuth(authContext, args) {
20412
20428
  function createGatewayEvidencePort(authContext) {
20413
20429
  return {
20414
20430
  fetchEvidence(rawId) {
20415
- return authContext.convex.query(api.epistemicEvidence.getById, {
20431
+ return authContext.convex.query(api.evidence.getById, {
20416
20432
  evidenceId: rawId,
20417
20433
  nodeId: rawId
20418
20434
  });
20419
20435
  },
20420
20436
  listEvidenceByTopic(args) {
20421
- return authContext.convex.query(api.epistemicEvidence.getByTopic, {
20437
+ return authContext.convex.query(api.evidence.getByTopic, {
20422
20438
  topicId: args.topicId,
20423
20439
  userId: authContext.userId,
20424
20440
  limit: args.limit
20425
20441
  });
20426
20442
  },
20427
20443
  listEvidenceForBelief(rawBeliefId) {
20428
- return authContext.convex.query(api.epistemicEvidence.getForBelief, {
20444
+ return authContext.convex.query(api.evidence.getForBelief, {
20429
20445
  beliefNodeId: rawBeliefId
20430
20446
  });
20431
20447
  },
@@ -20438,7 +20454,7 @@ function createGatewayEvidencePort(authContext) {
20438
20454
  );
20439
20455
  },
20440
20456
  async createEvidence(input) {
20441
- const created = await authContext.convex.mutation(api.epistemicEvidence.create, {
20457
+ const created = await authContext.convex.mutation(api.evidence.create, {
20442
20458
  topicId: input.topicId,
20443
20459
  text: input.text,
20444
20460
  title: input.title,
@@ -20471,7 +20487,7 @@ function createGatewayEvidencePort(authContext) {
20471
20487
  ...linkArgs
20472
20488
  });
20473
20489
  } else {
20474
- await authContext.convex.mutation(api.epistemicBeliefs.linkEvidence, {
20490
+ await authContext.convex.mutation(api.beliefs.linkEvidence, {
20475
20491
  beliefNodeId: input.target.rawId,
20476
20492
  insightId: rawId,
20477
20493
  type: input.weight < 0 ? "contradicting" : "supporting",
@@ -20482,7 +20498,7 @@ function createGatewayEvidencePort(authContext) {
20482
20498
  return created;
20483
20499
  },
20484
20500
  linkEvidenceToBelief(input) {
20485
- return authContext.convex.mutation(api.epistemicBeliefs.linkEvidence, {
20501
+ return authContext.convex.mutation(api.beliefs.linkEvidence, {
20486
20502
  beliefNodeId: input.targetRawId,
20487
20503
  insightId: input.evidenceRawId,
20488
20504
  type: input.weight < 0 ? "contradicting" : "supporting",
@@ -20614,7 +20630,7 @@ async function updateEvidenceStatusFromGatewayAuth(authContext, input) {
20614
20630
  input.id ?? input.nodeId ?? input.evidenceId ?? input.insightId ?? ""
20615
20631
  ) ?? ""
20616
20632
  );
20617
- return authContext.convex.mutation(api.epistemicEvidence.updateStatus, {
20633
+ return authContext.convex.mutation(api.evidence.updateStatus, {
20618
20634
  nodeId: resolvedNodeId ?? input.nodeId ?? input.id,
20619
20635
  status: input.status,
20620
20636
  userId: authContext.userId
@@ -20624,7 +20640,7 @@ function updateEvidenceFromGatewayAuth(authContext, input) {
20624
20640
  const evidenceId = resolveExternalId3(
20625
20641
  input.id ?? input.evidenceId ?? input.insightId ?? input.nodeId ?? ""
20626
20642
  ) ?? "";
20627
- return authContext.convex.mutation(api.epistemicEvidence.update, {
20643
+ return authContext.convex.mutation(api.evidence.update, {
20628
20644
  insightId: evidenceId,
20629
20645
  text: input.text,
20630
20646
  kind: input.kind,
@@ -20638,7 +20654,7 @@ function flagEvidenceAsIncorrectFromGatewayAuth(authContext, input) {
20638
20654
  const evidenceId = resolveExternalId3(
20639
20655
  input.id ?? input.evidenceId ?? input.insightId ?? input.nodeId ?? ""
20640
20656
  ) ?? "";
20641
- return authContext.convex.mutation(api.epistemicEvidence.flagAsIncorrect, {
20657
+ return authContext.convex.mutation(api.evidence.flagAsIncorrect, {
20642
20658
  insightId: evidenceId,
20643
20659
  reason: input.reason,
20644
20660
  suggestedCorrection: input.suggestedCorrection,
@@ -20649,7 +20665,7 @@ function removeEvidenceFromGatewayAuth(authContext, input) {
20649
20665
  const evidenceId = resolveExternalId3(
20650
20666
  input.id ?? input.evidenceId ?? input.insightId ?? input.nodeId ?? ""
20651
20667
  ) ?? "";
20652
- return authContext.convex.mutation(api.epistemicEvidence.remove, {
20668
+ return authContext.convex.mutation(api.evidence.remove, {
20653
20669
  insightId: evidenceId,
20654
20670
  userId: authContext.userId
20655
20671
  });
@@ -20661,7 +20677,7 @@ async function updateEvidenceVerificationStatusFromGatewayAuth(authContext, inpu
20661
20677
  input.id ?? input.nodeId ?? input.evidenceId ?? input.insightId ?? ""
20662
20678
  ) ?? ""
20663
20679
  );
20664
- return authContext.convex.mutation(api.epistemicEvidence.updateVerificationStatus, {
20680
+ return authContext.convex.mutation(api.evidence.updateVerificationStatus, {
20665
20681
  nodeId: resolvedNodeId ?? input.nodeId ?? input.id,
20666
20682
  verificationHash: input.verificationHash,
20667
20683
  verificationStatus: input.verificationStatus,
@@ -21245,7 +21261,7 @@ function isRecord5(value) {
21245
21261
  }
21246
21262
  async function resolveQuestionTopicIdWithGatewayAuth(authContext, questionId) {
21247
21263
  const question = await authContext.convex.query(
21248
- api.epistemicQuestions.getById,
21264
+ api.questions.getById,
21249
21265
  {
21250
21266
  questionId,
21251
21267
  nodeId: questionId
@@ -21301,20 +21317,20 @@ function normalizeLatestAnswerRecord(questionId, answer) {
21301
21317
  function createGatewayQuestionsPort(authContext) {
21302
21318
  return {
21303
21319
  fetchQuestion(rawId) {
21304
- return authContext.convex.query(api.epistemicQuestions.getById, {
21320
+ return authContext.convex.query(api.questions.getById, {
21305
21321
  questionId: rawId,
21306
21322
  nodeId: rawId
21307
21323
  });
21308
21324
  },
21309
21325
  listQuestionsByTopic(args) {
21310
- return authContext.convex.query(api.epistemicQuestions.getByTopic, {
21326
+ return authContext.convex.query(api.questions.getByTopic, {
21311
21327
  topicId: args.topicId,
21312
21328
  userId: authContext.userId,
21313
21329
  limit: args.limit
21314
21330
  });
21315
21331
  },
21316
21332
  createQuestion(input) {
21317
- return authContext.convex.mutation(api.epistemicQuestions.create, {
21333
+ return authContext.convex.mutation(api.questions.create, {
21318
21334
  topicId: input.topicId,
21319
21335
  question: input.text,
21320
21336
  priority: input.priority,
@@ -21324,7 +21340,7 @@ function createGatewayQuestionsPort(authContext) {
21324
21340
  },
21325
21341
  refineQuestion(input) {
21326
21342
  return authContext.convex.mutation(
21327
- api.epistemicQuestions.updateQuestion,
21343
+ api.questions.updateQuestion,
21328
21344
  {
21329
21345
  questionId: input.questionRawId,
21330
21346
  question: input.text
@@ -21332,14 +21348,14 @@ function createGatewayQuestionsPort(authContext) {
21332
21348
  );
21333
21349
  },
21334
21350
  updateQuestionStatus(input) {
21335
- return authContext.convex.mutation(api.epistemicQuestions.updateStatus, {
21351
+ return authContext.convex.mutation(api.questions.updateStatus, {
21336
21352
  questionId: input.questionRawId,
21337
21353
  status: input.status,
21338
21354
  userId: authContext.userId
21339
21355
  });
21340
21356
  },
21341
21357
  createAnswer(input) {
21342
- return authContext.convex.mutation(api.epistemicAnswers.create, {
21358
+ return authContext.convex.mutation(api.answers.create, {
21343
21359
  questionNodeId: input.questionRawId,
21344
21360
  topicId: input.topicId,
21345
21361
  answerText: input.text,
@@ -21424,7 +21440,7 @@ async function answerQuestionFromGatewayAuth(authContext, input) {
21424
21440
  }
21425
21441
  async function getQuestionAnswerFromGatewayAuth(authContext, questionId) {
21426
21442
  const answer = await authContext.convex.query(
21427
- api.epistemicAnswers.getLatestForQuestion,
21443
+ api.answers.getLatestForQuestion,
21428
21444
  {
21429
21445
  questionNodeId: questionId
21430
21446
  }
@@ -21517,7 +21533,7 @@ function createQuestionsBatchFromGatewayAuth(authContext, input) {
21517
21533
  sourceKind: "question_batch",
21518
21534
  autoCreate: input.topicId ? false : true
21519
21535
  })).topicId;
21520
- return authContext.convex.mutation(api.epistemicQuestions.createBatch, {
21536
+ return authContext.convex.mutation(api.questions.createBatch, {
21521
21537
  topicId: resolvedTopicId,
21522
21538
  questions: input.questions.map((question) => ({
21523
21539
  ...question,
@@ -21554,7 +21570,7 @@ async function addQuestionFromGatewayAuth(authContext, input) {
21554
21570
  autoCreate: input.topicId ? false : true
21555
21571
  })).topicId;
21556
21572
  const questionId = await authContext.convex.mutation(
21557
- api.epistemicQuestions.addQuestion,
21573
+ api.questions.addQuestion,
21558
21574
  {
21559
21575
  topicId: resolvedTopicId,
21560
21576
  question: input.question ?? input.text ?? "",
@@ -21577,7 +21593,7 @@ async function addQuestionFromGatewayAuth(authContext, input) {
21577
21593
  return getQuestionFromGatewayAuth(authContext, String(questionId));
21578
21594
  }
21579
21595
  async function updateQuestionPriorityFromGatewayAuth(authContext, input) {
21580
- await authContext.convex.mutation(api.epistemicQuestions.updatePriority, {
21596
+ await authContext.convex.mutation(api.questions.updatePriority, {
21581
21597
  nodeId: normalizePrefixedId(
21582
21598
  input.id ?? input.nodeId ?? input.questionId,
21583
21599
  "que"
@@ -21592,7 +21608,7 @@ async function updateQuestionPriorityFromGatewayAuth(authContext, input) {
21592
21608
  }
21593
21609
  function advanceQuestionToConvictionFromGatewayAuth(authContext, input) {
21594
21610
  return authContext.convex.mutation(
21595
- api.epistemicQuestions.advanceToConviction,
21611
+ api.questions.advanceToConviction,
21596
21612
  {
21597
21613
  questionId: normalizePrefixedId(
21598
21614
  input.questionId ?? input.id ?? input.nodeId,
@@ -21604,7 +21620,7 @@ function advanceQuestionToConvictionFromGatewayAuth(authContext, input) {
21604
21620
  );
21605
21621
  }
21606
21622
  function updateQuestionConvictionFromGatewayAuth(authContext, input) {
21607
- return authContext.convex.mutation(api.epistemicQuestions.updateConviction, {
21623
+ return authContext.convex.mutation(api.questions.updateConviction, {
21608
21624
  questionId: normalizePrefixedId(
21609
21625
  input.questionId ?? input.id ?? input.nodeId,
21610
21626
  "que"
@@ -21617,7 +21633,7 @@ function updateQuestionConvictionFromGatewayAuth(authContext, input) {
21617
21633
  }
21618
21634
  function finalizeQuestionConvictionFromGatewayAuth(authContext, input) {
21619
21635
  return authContext.convex.mutation(
21620
- api.epistemicQuestions.finalizeConviction,
21636
+ api.questions.finalizeConviction,
21621
21637
  {
21622
21638
  questionId: normalizePrefixedId(
21623
21639
  input.questionId ?? input.id ?? input.nodeId,
@@ -21634,7 +21650,7 @@ function finalizeQuestionConvictionFromGatewayAuth(authContext, input) {
21634
21650
  }
21635
21651
  async function updateQuestionFromGatewayAuth(authContext, input) {
21636
21652
  const questionId = normalizePrefixedId(input.questionId ?? input.id ?? input.nodeId, "que") ?? "";
21637
- await authContext.convex.mutation(api.epistemicQuestions.updateQuestion, {
21653
+ await authContext.convex.mutation(api.questions.updateQuestion, {
21638
21654
  questionId,
21639
21655
  question: input.question ?? input.text,
21640
21656
  category: input.category,
@@ -21643,7 +21659,7 @@ async function updateQuestionFromGatewayAuth(authContext, input) {
21643
21659
  return getQuestionFromGatewayAuth(authContext, questionId);
21644
21660
  }
21645
21661
  function deleteQuestionFromGatewayAuth(authContext, input) {
21646
- return authContext.convex.mutation(api.epistemicQuestions.deleteQuestion, {
21662
+ return authContext.convex.mutation(api.questions.deleteQuestion, {
21647
21663
  questionId: normalizePrefixedId(
21648
21664
  input.questionId ?? input.id ?? input.nodeId,
21649
21665
  "que"
@@ -21712,13 +21728,13 @@ function normalizeGraphEdge(row) {
21712
21728
  }
21713
21729
  async function fetchGraphNodeByIdentifier(authContext, input) {
21714
21730
  if (input.nodeId) {
21715
- const node = await authContext.convex.query(api.epistemicNodes.get, {
21731
+ const node = await authContext.convex.query(api.nodes.get, {
21716
21732
  nodeId: input.nodeId
21717
21733
  });
21718
21734
  return node ? normalizeGraphNode(node) : null;
21719
21735
  }
21720
21736
  if (input.globalId) {
21721
- const node = await authContext.convex.query(api.epistemicNodes.getByGlobalId, {
21737
+ const node = await authContext.convex.query(api.nodes.getByGlobalId, {
21722
21738
  globalId: input.globalId
21723
21739
  });
21724
21740
  return node ? normalizeGraphNode(node) : null;
@@ -21896,7 +21912,7 @@ function createGatewayGraphPort(authContext) {
21896
21912
  return page.beliefs;
21897
21913
  },
21898
21914
  async fetchBelief(input) {
21899
- const belief = await authContext.convex.query(api.epistemicBeliefs.getById, {
21915
+ const belief = await authContext.convex.query(api.beliefs.getById, {
21900
21916
  beliefId: input.beliefId,
21901
21917
  nodeId: input.beliefId
21902
21918
  });
@@ -21910,7 +21926,7 @@ function createGatewayGraphPort(authContext) {
21910
21926
  return page.questions;
21911
21927
  },
21912
21928
  async listTestingEdges(input) {
21913
- const rows = await authContext.convex.query(api.epistemicEdges.getByTopicAndType, {
21929
+ const rows = await authContext.convex.query(api.edges.getByTopicAndType, {
21914
21930
  topicId: input.topicId,
21915
21931
  edgeType: "tests"
21916
21932
  });
@@ -21954,7 +21970,7 @@ async function listGraphNodesFromGatewayAuth(authContext, input) {
21954
21970
  if (!topicId) {
21955
21971
  throw new Error("[graph] topicId is required to list graph nodes.");
21956
21972
  }
21957
- const rows = await authContext.convex.query(api.epistemicNodes.getByTopic, {
21973
+ const rows = await authContext.convex.query(api.nodes.getByTopic, {
21958
21974
  topicId,
21959
21975
  userId: authContext.userId,
21960
21976
  limit: normalizeLimit(input.limit, 250, 1e3)
@@ -21967,7 +21983,7 @@ async function listGraphEdgesFromGatewayAuth(authContext, input) {
21967
21983
  if (!topicId) {
21968
21984
  throw new Error("[graph] topicId is required to list graph edges.");
21969
21985
  }
21970
- const rows = await authContext.convex.query(api.epistemicEdges.getByTopic, {
21986
+ const rows = await authContext.convex.query(api.edges.getByTopic, {
21971
21987
  topicId,
21972
21988
  userId: authContext.userId,
21973
21989
  limit: normalizeLimit(input.limit, 500, 2e3)
@@ -23799,21 +23815,21 @@ function createGatewayTopicsPort(authContext) {
23799
23815
  });
23800
23816
  },
23801
23817
  listBeliefsByTopic(args) {
23802
- return authContext.convex.query(api.epistemicBeliefs.getByTopic, {
23818
+ return authContext.convex.query(api.beliefs.getByTopic, {
23803
23819
  topicId: args.topicId,
23804
23820
  userId: authContext.userId,
23805
23821
  limit: args.limit
23806
23822
  });
23807
23823
  },
23808
23824
  listQuestionsByTopic(args) {
23809
- return authContext.convex.query(api.epistemicQuestions.getByTopic, {
23825
+ return authContext.convex.query(api.questions.getByTopic, {
23810
23826
  topicId: args.topicId,
23811
23827
  userId: authContext.userId,
23812
23828
  limit: args.limit
23813
23829
  });
23814
23830
  },
23815
23831
  listEvidenceByTopic(args) {
23816
- return authContext.convex.query(api.epistemicEvidence.getByTopic, {
23832
+ return authContext.convex.query(api.evidence.getByTopic, {
23817
23833
  topicId: args.topicId,
23818
23834
  userId: authContext.userId,
23819
23835
  limit: args.limit
@@ -24731,7 +24747,7 @@ function createGatewayWorktreesPort(authContext) {
24731
24747
  scoreBeliefOutcome(args) {
24732
24748
  const opinion = toSubjectiveLogicOpinion(args.confidence);
24733
24749
  return authContext.convex.mutation(
24734
- api.epistemicBeliefs.modulateConfidence,
24750
+ api.beliefs.modulateConfidence,
24735
24751
  {
24736
24752
  nodeId: args.beliefRawId,
24737
24753
  trigger: "worktree_outcome",
@@ -27406,6 +27422,16 @@ var PERMIT_MEMBERSHIP_ROLES = /* @__PURE__ */ new Set([
27406
27422
  "platform_admin",
27407
27423
  "workspace_admin"
27408
27424
  ]);
27425
+ var PERMIT_WORKSPACE_ROLES = /* @__PURE__ */ new Set([
27426
+ "workspace_owner",
27427
+ "workspace_admin",
27428
+ "workspace_member",
27429
+ "workspace_viewer"
27430
+ ]);
27431
+ var PERMIT_DEPLOYMENT_ROLES = /* @__PURE__ */ new Set([
27432
+ "deployment_admin",
27433
+ "deployment_operator"
27434
+ ]);
27409
27435
  var CLERK_WEBHOOK_SECRETS = [
27410
27436
  "LUCERN_CLERK_WEBHOOK_SECRET",
27411
27437
  "CLERK_WEBHOOK_SECRET",
@@ -27427,8 +27453,7 @@ function readNumber18(value) {
27427
27453
  }
27428
27454
  return void 0;
27429
27455
  }
27430
- var PERMIT_USER_KEY_PATTERN = /^[A-Za-z0-9|@+\-._]+$/;
27431
- var PERMIT_USER_KEY_ESCAPE_SENTINEL = "|";
27456
+ var CLERK_USER_ID_PATTERN = /^user_[A-Za-z0-9]+$/;
27432
27457
  function asRecord26(value) {
27433
27458
  return isRecord8(value) ? value : {};
27434
27459
  }
@@ -27443,14 +27468,14 @@ function encodeBase64(bytes) {
27443
27468
  }
27444
27469
  return btoa(binary);
27445
27470
  }
27446
- function permitUserKeyForPrincipalId(principalId) {
27447
- const trimmed = principalId.trim();
27448
- if (PERMIT_USER_KEY_PATTERN.test(trimmed) && !trimmed.includes(PERMIT_USER_KEY_ESCAPE_SENTINEL)) {
27449
- return trimmed;
27471
+ function permitUserKeyForClerkUserId(userId) {
27472
+ const trimmed = userId.trim();
27473
+ if (!CLERK_USER_ID_PATTERN.test(trimmed)) {
27474
+ throw new Error(
27475
+ `Clerk webhook user id must be a canonical Clerk user ID. Received "${userId}".`
27476
+ );
27450
27477
  }
27451
- return Array.from(trimmed).map(
27452
- (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}`
27453
- ).join("");
27478
+ return trimmed;
27454
27479
  }
27455
27480
  function compactRecord5(value) {
27456
27481
  return Object.fromEntries(
@@ -27539,9 +27564,12 @@ async function upsertPermitTenant(args) {
27539
27564
  const tenantPayload = {
27540
27565
  name: args.tenantName ?? args.tenantKey,
27541
27566
  attributes: compactRecord5({
27567
+ canonicalTenantId: args.clerkOrganizationId,
27568
+ canonicalTenantProvider: "clerk",
27542
27569
  clerkOrganizationId: args.clerkOrganizationId,
27543
27570
  clerkOrganizationSlug: args.clerkOrganizationSlug,
27544
- mcTenantKey: args.tenantKey,
27571
+ mcTenantId: args.mcTenantId,
27572
+ mcTenantSlug: args.mcTenantSlug,
27545
27573
  sourceType: "organization",
27546
27574
  sourceEvent: args.eventType,
27547
27575
  eventAt: args.eventAt,
@@ -27560,16 +27588,192 @@ async function upsertPermitTenant(args) {
27560
27588
  ...tenantPayload
27561
27589
  });
27562
27590
  }
27591
+ async function upsertPermitResourceInstance(args) {
27592
+ const permit = getPermitClient();
27593
+ const resourceInstance = `${args.resource}:${args.key}`;
27594
+ const payload = {
27595
+ attributes: compactRecord5(args.attributes)
27596
+ };
27597
+ try {
27598
+ return await permit.api.resourceInstances.update(resourceInstance, payload);
27599
+ } catch (error) {
27600
+ if (!isNotFound(error)) {
27601
+ throw error;
27602
+ }
27603
+ }
27604
+ try {
27605
+ return await permit.api.resourceInstances.create({
27606
+ key: args.key,
27607
+ tenant: args.tenantKey,
27608
+ resource: args.resource,
27609
+ attributes: payload.attributes
27610
+ });
27611
+ } catch (error) {
27612
+ if (!isConflict(error)) {
27613
+ throw error;
27614
+ }
27615
+ }
27616
+ return await permit.api.resourceInstances.update(resourceInstance, payload);
27617
+ }
27618
+ async function createPermitRelationshipTuple(args) {
27619
+ const permit = getPermitClient();
27620
+ const relationshipTuples = permit.api.relationshipTuples;
27621
+ if (!relationshipTuples || typeof relationshipTuples.create !== "function") {
27622
+ throw new Error("Permit SDK does not expose relationship tuple creation");
27623
+ }
27624
+ try {
27625
+ return await relationshipTuples.create({
27626
+ subject: args.subject,
27627
+ relation: args.relation,
27628
+ object: args.object,
27629
+ tenant: args.tenant
27630
+ });
27631
+ } catch (error) {
27632
+ if (isConflict(error)) {
27633
+ return { alreadyCreated: true };
27634
+ }
27635
+ throw error;
27636
+ }
27637
+ }
27638
+ async function upsertPermitWorkspaceProjection(args) {
27639
+ const workspaceKey = workspacePermitKey({
27640
+ tenantKey: args.tenantKey,
27641
+ workspace: args.workspace
27642
+ });
27643
+ if (!workspaceKey) {
27644
+ return void 0;
27645
+ }
27646
+ return await upsertPermitResourceInstance({
27647
+ resource: "workspace",
27648
+ key: workspaceKey,
27649
+ tenantKey: args.tenantKey,
27650
+ attributes: {
27651
+ canonicalTenantId: args.tenantKey,
27652
+ canonicalTenantProvider: "clerk",
27653
+ clerkOrganizationId: args.tenantKey,
27654
+ mcTenantId: args.mcTenantId,
27655
+ mcTenantSlug: args.mcTenantSlug,
27656
+ mcWorkspaceId: readString28(args.workspace._id),
27657
+ workspaceSlug: readString28(args.workspace.slug),
27658
+ workspaceKey: readString28(args.workspace.key),
27659
+ name: readString28(args.workspace.name),
27660
+ status: readString28(args.workspace.status),
27661
+ sourceType: "clerk_webhook_workspace_projection",
27662
+ sourceEvent: args.eventType,
27663
+ eventAt: args.eventAt,
27664
+ actorId: args.actorId
27665
+ }
27666
+ });
27667
+ }
27668
+ async function upsertPermitWorkspaceRelationship(args) {
27669
+ return await createPermitRelationshipTuple({
27670
+ subject: `workspace:${args.workspaceKey}`,
27671
+ relation: "belongs_to",
27672
+ object: `tenant:${args.tenantKey}`,
27673
+ tenant: args.tenantKey
27674
+ });
27675
+ }
27676
+ function deploymentPermitKey(args) {
27677
+ const workspaceKey = workspacePermitKey({
27678
+ tenantKey: args.tenantKey,
27679
+ workspace: args.workspace
27680
+ });
27681
+ const environment = slugForPermitKey(args.environment);
27682
+ if (!workspaceKey || !environment) {
27683
+ return void 0;
27684
+ }
27685
+ return `${workspaceKey}--${environment}`;
27686
+ }
27687
+ async function upsertPermitDeploymentProjection(args) {
27688
+ const deploymentKey = deploymentPermitKey({
27689
+ tenantKey: args.tenantKey,
27690
+ workspace: args.workspace,
27691
+ environment: args.environment
27692
+ });
27693
+ if (!deploymentKey) {
27694
+ return void 0;
27695
+ }
27696
+ await upsertPermitResourceInstance({
27697
+ resource: "deployment",
27698
+ key: deploymentKey,
27699
+ tenantKey: args.tenantKey,
27700
+ attributes: {
27701
+ canonicalTenantId: args.tenantKey,
27702
+ canonicalTenantProvider: "clerk",
27703
+ clerkOrganizationId: args.tenantKey,
27704
+ mcTenantId: args.mcTenantId,
27705
+ mcTenantSlug: args.mcTenantSlug,
27706
+ mcWorkspaceId: readString28(args.workspace._id),
27707
+ workspaceKey: args.workspaceKey,
27708
+ workspaceSlug: readString28(args.workspace.slug),
27709
+ environment: args.environment,
27710
+ target: readString28(args.deployment.target) ?? "appDeployment",
27711
+ url: readString28(args.deployment.url),
27712
+ credentialRef: readString28(args.deployment.credentialRef),
27713
+ hasCredentialRef: Boolean(readString28(args.deployment.credentialRef)),
27714
+ sourceType: "clerk_webhook_deployment_projection",
27715
+ sourceEvent: args.eventType,
27716
+ eventAt: args.eventAt,
27717
+ actorId: args.actorId
27718
+ }
27719
+ });
27720
+ await createPermitRelationshipTuple({
27721
+ subject: `deployment:${deploymentKey}`,
27722
+ relation: "belongs_to",
27723
+ object: `workspace:${args.workspaceKey}`,
27724
+ tenant: args.tenantKey
27725
+ });
27726
+ return { deploymentKey };
27727
+ }
27728
+ async function upsertPermitDeploymentProjectionsForWorkspace(args) {
27729
+ const deployments = asRecord26(args.workspace.deployments);
27730
+ const deploymentKeys = [];
27731
+ for (const [environment, deployment] of Object.entries(deployments)) {
27732
+ if (!isRecord8(deployment)) {
27733
+ continue;
27734
+ }
27735
+ const projected = await upsertPermitDeploymentProjection({
27736
+ tenantKey: args.tenantKey,
27737
+ mcTenantId: args.mcTenantId,
27738
+ mcTenantSlug: args.mcTenantSlug,
27739
+ workspace: args.workspace,
27740
+ workspaceKey: args.workspaceKey,
27741
+ environment,
27742
+ deployment,
27743
+ eventType: args.eventType,
27744
+ eventAt: args.eventAt,
27745
+ actorId: args.actorId
27746
+ });
27747
+ if (projected?.deploymentKey) {
27748
+ deploymentKeys.push(projected.deploymentKey);
27749
+ }
27750
+ }
27751
+ return deploymentKeys;
27752
+ }
27563
27753
  async function syncPermitUser(args) {
27564
27754
  const permit = getPermitClient();
27565
27755
  return await permit.api.users.sync({
27566
- key: permitUserKeyForPrincipalId(args.userId),
27756
+ key: permitUserKeyForClerkUserId(args.userId),
27567
27757
  email: args.email,
27568
27758
  attributes: compactRecord5({
27569
27759
  sourceType: "clerk_webhook_user",
27570
27760
  sourceEvent: args.eventType,
27571
27761
  clerkStatus: args.eventType,
27572
27762
  clerkDisplayName: args.displayName,
27763
+ clerkAliases: [
27764
+ compactRecord5({
27765
+ provider: "clerk",
27766
+ externalSubjectId: args.userId,
27767
+ email: args.email
27768
+ })
27769
+ ],
27770
+ aliases: [
27771
+ compactRecord5({
27772
+ provider: "clerk",
27773
+ externalSubjectId: args.userId,
27774
+ email: args.email
27775
+ })
27776
+ ],
27573
27777
  eventAt: args.eventAt,
27574
27778
  actorId: args.actorId
27575
27779
  })
@@ -27577,7 +27781,7 @@ async function syncPermitUser(args) {
27577
27781
  }
27578
27782
  async function upsertPermitTenantMembershipRole(args) {
27579
27783
  const permit = getPermitClient();
27580
- const permitUserId = permitUserKeyForPrincipalId(args.userId);
27784
+ const permitUserId = permitUserKeyForClerkUserId(args.userId);
27581
27785
  const existing = readRoleAssignments(
27582
27786
  await permit.api.roleAssignments.list({
27583
27787
  user: permitUserId,
@@ -27619,6 +27823,127 @@ async function upsertPermitTenantMembershipRole(args) {
27619
27823
  throw error;
27620
27824
  }
27621
27825
  }
27826
+ function workspaceRoleForTenantMembership(role) {
27827
+ if (role === "platform_admin" || role === "tenant_admin") {
27828
+ return "workspace_owner";
27829
+ }
27830
+ if (role === "workspace_admin") {
27831
+ return "workspace_admin";
27832
+ }
27833
+ if (role === "editor" || role === "service_agent") {
27834
+ return "workspace_member";
27835
+ }
27836
+ return "workspace_viewer";
27837
+ }
27838
+ function deploymentRoleForTenantMembership(role) {
27839
+ const workspaceRole = workspaceRoleForTenantMembership(role);
27840
+ if (workspaceRole === "workspace_owner") {
27841
+ return "deployment_admin";
27842
+ }
27843
+ if (workspaceRole === "workspace_admin") {
27844
+ return "deployment_operator";
27845
+ }
27846
+ return null;
27847
+ }
27848
+ async function upsertPermitWorkspaceMembershipRole(args) {
27849
+ const permit = getPermitClient();
27850
+ const permitUserId = permitUserKeyForClerkUserId(args.userId);
27851
+ const workspaceRole = workspaceRoleForTenantMembership(args.role);
27852
+ const existing = readRoleAssignments(
27853
+ await permit.api.roleAssignments.list({
27854
+ user: permitUserId,
27855
+ tenant: args.tenantKey,
27856
+ resourceInstance: args.resourceInstance,
27857
+ perPage: 100
27858
+ })
27859
+ );
27860
+ await Promise.all(
27861
+ existing.map((assignment2) => {
27862
+ const role = readString28(assignment2.role);
27863
+ if (!role || !PERMIT_WORKSPACE_ROLES.has(role)) {
27864
+ return Promise.resolve();
27865
+ }
27866
+ if (roleAssignmentResourceInstance(assignment2) !== args.resourceInstance) {
27867
+ return Promise.resolve();
27868
+ }
27869
+ if (role === workspaceRole) {
27870
+ return Promise.resolve();
27871
+ }
27872
+ return unassignPermitTenantMembershipRole({
27873
+ permit,
27874
+ permitUserId,
27875
+ tenant: args.tenantKey,
27876
+ role,
27877
+ resourceInstance: args.resourceInstance
27878
+ });
27879
+ })
27880
+ );
27881
+ const assignment = {
27882
+ user: permitUserId,
27883
+ role: workspaceRole,
27884
+ tenant: args.tenantKey,
27885
+ resource_instance: args.resourceInstance
27886
+ };
27887
+ try {
27888
+ return await permit.api.roleAssignments.assign(assignment);
27889
+ } catch (error) {
27890
+ if (isConflict(error)) {
27891
+ return { alreadyAssigned: true };
27892
+ }
27893
+ throw error;
27894
+ }
27895
+ }
27896
+ async function upsertPermitDeploymentMembershipRole(args) {
27897
+ const permit = getPermitClient();
27898
+ const permitUserId = permitUserKeyForClerkUserId(args.userId);
27899
+ const deploymentRole = deploymentRoleForTenantMembership(args.role);
27900
+ const existing = readRoleAssignments(
27901
+ await permit.api.roleAssignments.list({
27902
+ user: permitUserId,
27903
+ tenant: args.tenantKey,
27904
+ resourceInstance: args.resourceInstance,
27905
+ perPage: 100
27906
+ })
27907
+ );
27908
+ await Promise.all(
27909
+ existing.map((assignment2) => {
27910
+ const role = readString28(assignment2.role);
27911
+ if (!role || !PERMIT_DEPLOYMENT_ROLES.has(role)) {
27912
+ return Promise.resolve();
27913
+ }
27914
+ if (roleAssignmentResourceInstance(assignment2) !== args.resourceInstance) {
27915
+ return Promise.resolve();
27916
+ }
27917
+ if (role === deploymentRole) {
27918
+ return Promise.resolve();
27919
+ }
27920
+ return unassignPermitTenantMembershipRole({
27921
+ permit,
27922
+ permitUserId,
27923
+ tenant: args.tenantKey,
27924
+ role,
27925
+ resourceInstance: args.resourceInstance
27926
+ });
27927
+ })
27928
+ );
27929
+ if (!deploymentRole) {
27930
+ return { skipped: "membership_role_has_no_deployment_role" };
27931
+ }
27932
+ const assignment = {
27933
+ user: permitUserId,
27934
+ role: deploymentRole,
27935
+ tenant: args.tenantKey,
27936
+ resource_instance: args.resourceInstance
27937
+ };
27938
+ try {
27939
+ return await permit.api.roleAssignments.assign(assignment);
27940
+ } catch (error) {
27941
+ if (isConflict(error)) {
27942
+ return { alreadyAssigned: true };
27943
+ }
27944
+ throw error;
27945
+ }
27946
+ }
27622
27947
  async function unassignPermitTenantMembershipRole(args) {
27623
27948
  const api2 = args.permit.api;
27624
27949
  const assignment = {
@@ -27644,7 +27969,7 @@ async function unassignPermitTenantMembershipRole(args) {
27644
27969
  }
27645
27970
  async function revokePermitTenantMembershipRoles(args) {
27646
27971
  const permit = getPermitClient();
27647
- const permitUserId = permitUserKeyForPrincipalId(args.userId);
27972
+ const permitUserId = permitUserKeyForClerkUserId(args.userId);
27648
27973
  const assignments = readRoleAssignments(
27649
27974
  await permit.api.roleAssignments.list({
27650
27975
  user: permitUserId,
@@ -27670,6 +27995,88 @@ async function revokePermitTenantMembershipRoles(args) {
27670
27995
  })
27671
27996
  );
27672
27997
  }
27998
+ async function revokePermitWorkspaceMembershipRoles(args) {
27999
+ const permit = getPermitClient();
28000
+ const permitUserId = permitUserKeyForClerkUserId(args.userId);
28001
+ const assignments = readRoleAssignments(
28002
+ await permit.api.roleAssignments.list({
28003
+ user: permitUserId,
28004
+ tenant: args.tenantKey,
28005
+ resourceInstance: args.resourceInstance,
28006
+ perPage: 100
28007
+ })
28008
+ );
28009
+ const workspaceRoles = assignments.filter(
28010
+ (assignment) => roleAssignmentResourceInstance(assignment) === args.resourceInstance && PERMIT_WORKSPACE_ROLES.has(readString28(assignment.role) ?? "")
28011
+ );
28012
+ await Promise.all(
28013
+ workspaceRoles.map((assignment) => {
28014
+ const role = readString28(assignment.role);
28015
+ if (!role) {
28016
+ return Promise.resolve();
28017
+ }
28018
+ return unassignPermitTenantMembershipRole({
28019
+ permit,
28020
+ permitUserId,
28021
+ tenant: args.tenantKey,
28022
+ role,
28023
+ resourceInstance: args.resourceInstance
28024
+ });
28025
+ })
28026
+ );
28027
+ }
28028
+ async function revokePermitDeploymentMembershipRoles(args) {
28029
+ const permit = getPermitClient();
28030
+ const permitUserId = permitUserKeyForClerkUserId(args.userId);
28031
+ const assignments = readRoleAssignments(
28032
+ await permit.api.roleAssignments.list({
28033
+ user: permitUserId,
28034
+ tenant: args.tenantKey,
28035
+ resourceInstance: args.resourceInstance,
28036
+ perPage: 100
28037
+ })
28038
+ );
28039
+ const deploymentRoles = assignments.filter(
28040
+ (assignment) => roleAssignmentResourceInstance(assignment) === args.resourceInstance && PERMIT_DEPLOYMENT_ROLES.has(readString28(assignment.role) ?? "")
28041
+ );
28042
+ await Promise.all(
28043
+ deploymentRoles.map((assignment) => {
28044
+ const role = readString28(assignment.role);
28045
+ if (!role) {
28046
+ return Promise.resolve();
28047
+ }
28048
+ return unassignPermitTenantMembershipRole({
28049
+ permit,
28050
+ permitUserId,
28051
+ tenant: args.tenantKey,
28052
+ role,
28053
+ resourceInstance: args.resourceInstance
28054
+ });
28055
+ })
28056
+ );
28057
+ }
28058
+ function tenantPermitKey(args) {
28059
+ return readString28(args.organizationId);
28060
+ }
28061
+ function workspacePermitKey(args) {
28062
+ const tenantKey = readString28(args.tenantKey);
28063
+ const workspaceKey = slugForPermitKey(
28064
+ readString28(args.workspace.slug) ?? readString28(args.workspace.key),
28065
+ readString28(args.workspace._id)
28066
+ );
28067
+ if (!tenantKey || !workspaceKey) {
28068
+ return void 0;
28069
+ }
28070
+ return `${tenantKey}--${workspaceKey}`;
28071
+ }
28072
+ function slugForPermitKey(value, fallback) {
28073
+ const raw = readString28(value) ?? readString28(fallback);
28074
+ if (!raw) {
28075
+ return void 0;
28076
+ }
28077
+ const slug = raw.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
28078
+ return slug || void 0;
28079
+ }
27673
28080
  function normalizeBase64(value) {
27674
28081
  return value.replace(/-/g, "+").replace(/_/g, "/");
27675
28082
  }
@@ -27856,12 +28263,12 @@ async function getMasterControlConvexClient2() {
27856
28263
  mcClientCache2.value = client;
27857
28264
  return client;
27858
28265
  }
27859
- async function resolveTenantByOrgSlug(args) {
27860
- if (!args.organizationSlug) {
28266
+ async function resolveTenantByClerkOrganization(args) {
28267
+ if (!args.organizationId) {
27861
28268
  return void 0;
27862
28269
  }
27863
- const tenant = await args.client.query(mcApi2.tenants.getBySlug, {
27864
- slug: args.organizationSlug
28270
+ const tenant = await args.client.query(mcApi2.tenants.getByCanonicalOrgId, {
28271
+ clerkOrganizationId: args.organizationId
27865
28272
  });
27866
28273
  if (!tenant || !isRecord8(tenant)) {
27867
28274
  return void 0;
@@ -27873,6 +28280,90 @@ async function resolveTenantByOrgSlug(args) {
27873
28280
  }
27874
28281
  return { tenantId, tenantSlug };
27875
28282
  }
28283
+ async function resolveOrProvisionTenantByClerkOrganization(args) {
28284
+ const existing = await resolveTenantByClerkOrganization({
28285
+ client: args.client,
28286
+ organizationId: args.organizationId
28287
+ });
28288
+ if (existing) {
28289
+ return { ...existing, provisioned: false };
28290
+ }
28291
+ if (args.eventType !== "organization.created") {
28292
+ return void 0;
28293
+ }
28294
+ const result = await args.client.mutation(
28295
+ mcApi2.tenants.provisionFromClerkOrganization,
28296
+ {
28297
+ clerkOrganizationId: args.organizationId,
28298
+ organizationName: args.organizationName,
28299
+ organizationSlug: args.organizationSlug,
28300
+ ownerClerkId: CLERK_USER_ID_PATTERN.test(args.actorId) ? args.actorId : void 0,
28301
+ actorClerkId: args.actorId
28302
+ }
28303
+ );
28304
+ const record = asRecord26(result);
28305
+ const tenantId = readString28(record.tenantId);
28306
+ const tenantSlug = readString28(record.slug) ?? args.organizationId;
28307
+ if (!tenantId) {
28308
+ return void 0;
28309
+ }
28310
+ return {
28311
+ tenantId,
28312
+ tenantSlug,
28313
+ provisioned: Boolean(record.created)
28314
+ };
28315
+ }
28316
+ async function listActiveTenantWorkspaces(args) {
28317
+ const workspaces2 = await args.client.query(mcApi2.workspaces.listByTenant, {
28318
+ tenantId: args.tenantId,
28319
+ status: "active"
28320
+ });
28321
+ return asArray(workspaces2).filter(isRecord8);
28322
+ }
28323
+ async function upsertPermitWorkspaceProjectionsForTenant(args) {
28324
+ const workspaces2 = await listActiveTenantWorkspaces({
28325
+ client: args.client,
28326
+ tenantId: args.tenant.tenantId
28327
+ });
28328
+ const projected = [];
28329
+ for (const workspace of workspaces2) {
28330
+ await upsertPermitWorkspaceProjection({
28331
+ tenantKey: args.tenantKey,
28332
+ mcTenantId: args.tenant.tenantId,
28333
+ mcTenantSlug: args.tenant.tenantSlug,
28334
+ workspace,
28335
+ eventType: args.eventType,
28336
+ eventAt: args.eventAt,
28337
+ actorId: args.actorId
28338
+ });
28339
+ const workspaceKey = workspacePermitKey({
28340
+ tenantKey: args.tenantKey,
28341
+ workspace
28342
+ });
28343
+ const deploymentKeys = workspaceKey ? await upsertPermitDeploymentProjectionsForWorkspace({
28344
+ tenantKey: args.tenantKey,
28345
+ mcTenantId: args.tenant.tenantId,
28346
+ mcTenantSlug: args.tenant.tenantSlug,
28347
+ workspace,
28348
+ workspaceKey,
28349
+ eventType: args.eventType,
28350
+ eventAt: args.eventAt,
28351
+ actorId: args.actorId
28352
+ }) : [];
28353
+ if (workspaceKey) {
28354
+ await upsertPermitWorkspaceRelationship({
28355
+ tenantKey: args.tenantKey,
28356
+ workspaceKey
28357
+ });
28358
+ }
28359
+ projected.push({
28360
+ workspaceId: readString28(workspace._id),
28361
+ workspaceKey,
28362
+ deploymentKeys
28363
+ });
28364
+ }
28365
+ return projected;
28366
+ }
27876
28367
  function webhookError(code, status, message, correlationId, policyTraceId, details) {
27877
28368
  return errorResponse({
27878
28369
  code,
@@ -27968,9 +28459,13 @@ async function handleClerkWebhook(args) {
27968
28459
  );
27969
28460
  }
27970
28461
  const client = await getClient();
27971
- const tenant = await resolveTenantByOrgSlug({
28462
+ const tenant = await resolveOrProvisionTenantByClerkOrganization({
27972
28463
  client,
27973
- organizationSlug: organizationIds.organizationSlug
28464
+ organizationId,
28465
+ organizationSlug: organizationIds.organizationSlug,
28466
+ organizationName: extractOrganizationName(organizationRecord),
28467
+ eventType,
28468
+ actorId
27974
28469
  });
27975
28470
  if (!tenant) {
27976
28471
  return webhookError(
@@ -27989,12 +28484,58 @@ async function handleClerkWebhook(args) {
27989
28484
  await upsertPermitTenant({
27990
28485
  clerkOrganizationId: organizationId,
27991
28486
  clerkOrganizationSlug: organizationIds.organizationSlug,
27992
- tenantKey: tenant.tenantSlug,
28487
+ mcTenantId: tenant.tenantId,
28488
+ mcTenantSlug: tenant.tenantSlug,
28489
+ tenantKey: organizationId,
27993
28490
  tenantName: extractOrganizationName(organizationRecord),
27994
28491
  eventType,
27995
28492
  eventAt: eventTimestamp,
27996
28493
  actorId
27997
28494
  });
28495
+ const workspaces2 = await upsertPermitWorkspaceProjectionsForTenant({
28496
+ client,
28497
+ tenant,
28498
+ tenantKey: organizationId,
28499
+ eventType,
28500
+ eventAt: eventTimestamp,
28501
+ actorId
28502
+ });
28503
+ if (eventType === "organization.created" && CLERK_USER_ID_PATTERN.test(actorId)) {
28504
+ await syncPermitUser({
28505
+ userId: actorId,
28506
+ email: void 0,
28507
+ displayName: void 0,
28508
+ eventType,
28509
+ eventAt: eventTimestamp,
28510
+ actorId
28511
+ });
28512
+ await Promise.all(
28513
+ workspaces2.flatMap((workspace) => {
28514
+ const assignments = [];
28515
+ if (workspace.workspaceKey) {
28516
+ assignments.push(
28517
+ upsertPermitWorkspaceMembershipRole({
28518
+ userId: actorId,
28519
+ tenantKey: organizationId,
28520
+ role: "tenant_admin",
28521
+ resourceInstance: `workspace:${workspace.workspaceKey}`
28522
+ })
28523
+ );
28524
+ }
28525
+ assignments.push(
28526
+ ...workspace.deploymentKeys.map(
28527
+ (deploymentKey) => upsertPermitDeploymentMembershipRole({
28528
+ userId: actorId,
28529
+ tenantKey: organizationId,
28530
+ role: "tenant_admin",
28531
+ resourceInstance: `deployment:${deploymentKey}`
28532
+ })
28533
+ )
28534
+ );
28535
+ return assignments;
28536
+ })
28537
+ );
28538
+ }
27998
28539
  const principal = await client.mutation(mcApi2.identity.upsertPrincipal, {
27999
28540
  principalId: organizationId,
28000
28541
  principalType: "group",
@@ -28045,6 +28586,8 @@ async function handleClerkWebhook(args) {
28045
28586
  acknowledged: true,
28046
28587
  eventType,
28047
28588
  tenantId: tenant.tenantId,
28589
+ provisioned: tenant.provisioned,
28590
+ workspaceCount: workspaces2.length,
28048
28591
  principalId: organizationId,
28049
28592
  principal,
28050
28593
  alias
@@ -28139,9 +28682,9 @@ async function handleClerkWebhook(args) {
28139
28682
  if (isMembershipEvent || isInvitationEvent) {
28140
28683
  const client = await getClient();
28141
28684
  const org = extractOrganizationIds(data);
28142
- const tenant = await resolveTenantByOrgSlug({
28685
+ const tenant = await resolveTenantByClerkOrganization({
28143
28686
  client,
28144
- organizationSlug: org.organizationSlug
28687
+ organizationId: org.organizationId
28145
28688
  });
28146
28689
  if (!tenant) {
28147
28690
  return webhookError(
@@ -28160,16 +28703,26 @@ async function handleClerkWebhook(args) {
28160
28703
  const userId = readString28(data.user_id) || readString28(asRecord26(data.public_user_data).user_id) || readString28(asRecord26(data.user).id);
28161
28704
  const rawRole = readString28(data.role);
28162
28705
  const role = normalizeRole(rawRole);
28163
- const permitTenantKey = tenant.tenantSlug;
28706
+ const permitTenantKey = tenantPermitKey({
28707
+ organizationId: org.organizationId
28708
+ });
28164
28709
  if (!permitTenantKey) {
28165
28710
  return webhookError(
28166
28711
  "INVALID_REQUEST",
28167
28712
  400,
28168
- "Clerk organization webhook payload missing organization tenant key.",
28713
+ "Clerk organization webhook payload missing canonical organization id.",
28169
28714
  args.correlationId,
28170
28715
  args.policyTraceId
28171
28716
  );
28172
28717
  }
28718
+ const workspaceProjections = await upsertPermitWorkspaceProjectionsForTenant({
28719
+ client,
28720
+ tenant,
28721
+ tenantKey: permitTenantKey,
28722
+ eventType,
28723
+ eventAt: eventTimestamp,
28724
+ actorId
28725
+ });
28173
28726
  if (INVITATION_EVENTS.has(eventType)) {
28174
28727
  const invitationId = readString28(data.id);
28175
28728
  const invitationAccepted = eventType === "organizationInvitation.accepted";
@@ -28232,6 +28785,32 @@ async function handleClerkWebhook(args) {
28232
28785
  tenantKey: permitTenantKey,
28233
28786
  role
28234
28787
  });
28788
+ await Promise.all(
28789
+ workspaceProjections.flatMap((workspace) => {
28790
+ const assignments = [];
28791
+ if (workspace.workspaceKey) {
28792
+ assignments.push(
28793
+ upsertPermitWorkspaceMembershipRole({
28794
+ userId,
28795
+ tenantKey: permitTenantKey,
28796
+ role,
28797
+ resourceInstance: `workspace:${workspace.workspaceKey}`
28798
+ })
28799
+ );
28800
+ }
28801
+ assignments.push(
28802
+ ...workspace.deploymentKeys.map(
28803
+ (deploymentKey) => upsertPermitDeploymentMembershipRole({
28804
+ userId,
28805
+ tenantKey: permitTenantKey,
28806
+ role,
28807
+ resourceInstance: `deployment:${deploymentKey}`
28808
+ })
28809
+ )
28810
+ );
28811
+ return assignments;
28812
+ })
28813
+ );
28235
28814
  await client.mutation(mcApi2.identity.upsertMembership, {
28236
28815
  principalId: userId,
28237
28816
  principalRefId: void 0,
@@ -28272,6 +28851,30 @@ async function handleClerkWebhook(args) {
28272
28851
  userId,
28273
28852
  tenantKey: permitTenantKey
28274
28853
  });
28854
+ await Promise.all(
28855
+ workspaceProjections.flatMap((workspace) => {
28856
+ const revocations = [];
28857
+ if (workspace.workspaceKey) {
28858
+ revocations.push(
28859
+ revokePermitWorkspaceMembershipRoles({
28860
+ userId,
28861
+ tenantKey: permitTenantKey,
28862
+ resourceInstance: `workspace:${workspace.workspaceKey}`
28863
+ })
28864
+ );
28865
+ }
28866
+ revocations.push(
28867
+ ...workspace.deploymentKeys.map(
28868
+ (deploymentKey) => revokePermitDeploymentMembershipRoles({
28869
+ userId,
28870
+ tenantKey: permitTenantKey,
28871
+ resourceInstance: `deployment:${deploymentKey}`
28872
+ })
28873
+ )
28874
+ );
28875
+ return revocations;
28876
+ })
28877
+ );
28275
28878
  const existing = await client.query(mcApi2.identity.getMembershipForPrincipal, {
28276
28879
  principalId: userId,
28277
28880
  tenantId: tenant.tenantId,
@@ -28369,6 +28972,30 @@ async function handleClerkWebhook(args) {
28369
28972
  userId,
28370
28973
  tenantKey: permitTenantKey
28371
28974
  });
28975
+ await Promise.all(
28976
+ workspaceProjections.flatMap((workspace) => {
28977
+ const revocations = [];
28978
+ if (workspace.workspaceKey) {
28979
+ revocations.push(
28980
+ revokePermitWorkspaceMembershipRoles({
28981
+ userId,
28982
+ tenantKey: permitTenantKey,
28983
+ resourceInstance: `workspace:${workspace.workspaceKey}`
28984
+ })
28985
+ );
28986
+ }
28987
+ revocations.push(
28988
+ ...workspace.deploymentKeys.map(
28989
+ (deploymentKey) => revokePermitDeploymentMembershipRoles({
28990
+ userId,
28991
+ tenantKey: permitTenantKey,
28992
+ resourceInstance: `deployment:${deploymentKey}`
28993
+ })
28994
+ )
28995
+ );
28996
+ return revocations;
28997
+ })
28998
+ );
28372
28999
  const existing = await client.query(mcApi2.identity.getMembershipForPrincipal, {
28373
29000
  principalId: userId,
28374
29001
  tenantId: tenant.tenantId,
@@ -28420,6 +29047,32 @@ async function handleClerkWebhook(args) {
28420
29047
  tenantKey: permitTenantKey,
28421
29048
  role
28422
29049
  });
29050
+ await Promise.all(
29051
+ workspaceProjections.flatMap((workspace) => {
29052
+ const assignments = [];
29053
+ if (workspace.workspaceKey) {
29054
+ assignments.push(
29055
+ upsertPermitWorkspaceMembershipRole({
29056
+ userId,
29057
+ tenantKey: permitTenantKey,
29058
+ role,
29059
+ resourceInstance: `workspace:${workspace.workspaceKey}`
29060
+ })
29061
+ );
29062
+ }
29063
+ assignments.push(
29064
+ ...workspace.deploymentKeys.map(
29065
+ (deploymentKey) => upsertPermitDeploymentMembershipRole({
29066
+ userId,
29067
+ tenantKey: permitTenantKey,
29068
+ role,
29069
+ resourceInstance: `deployment:${deploymentKey}`
29070
+ })
29071
+ )
29072
+ );
29073
+ return assignments;
29074
+ })
29075
+ );
28423
29076
  return successResponse(
28424
29077
  {
28425
29078
  acknowledged: true,