@lucern/mcp 0.3.0-alpha.11 → 0.3.0-alpha.13
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/cli.js +432 -54
- package/dist/cli.js.map +1 -1
- package/dist/gateway.d.ts +30 -1
- package/dist/gateway.js +1799 -379
- package/dist/gateway.js.map +1 -1
- package/dist/hosted-route.js +432 -54
- package/dist/hosted-route.js.map +1 -1
- package/dist/index.js +432 -54
- package/dist/index.js.map +1 -1
- package/dist/runtime.js +125 -5
- package/dist/runtime.js.map +1 -1
- package/package.json +6 -6
package/dist/gateway.js
CHANGED
|
@@ -2,6 +2,9 @@ import { z } from 'zod';
|
|
|
2
2
|
import { v } from 'convex/values';
|
|
3
3
|
import { basename, extname } from 'path';
|
|
4
4
|
import { randomUUID } from 'crypto';
|
|
5
|
+
import { anyApi } from 'convex/server';
|
|
6
|
+
import { ConvexHttpClient } from 'convex/browser';
|
|
7
|
+
import { Permit } from 'permitio';
|
|
5
8
|
|
|
6
9
|
// ../contracts/src/types/reasoning-method.ts
|
|
7
10
|
var REASONING_METHODS = [
|
|
@@ -1030,6 +1033,35 @@ defineTable({
|
|
|
1030
1033
|
{ kind: "index", name: "by_source", columns: ["source"] }
|
|
1031
1034
|
]
|
|
1032
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
|
+
});
|
|
1033
1065
|
defineTable({
|
|
1034
1066
|
name: "beliefConfidence",
|
|
1035
1067
|
component: "kernel",
|
|
@@ -4328,7 +4360,9 @@ var permitObjectType = z.enum([
|
|
|
4328
4360
|
"group",
|
|
4329
4361
|
"resource_instance",
|
|
4330
4362
|
"relationship_tuple",
|
|
4331
|
-
"role_assignment"
|
|
4363
|
+
"role_assignment",
|
|
4364
|
+
"attribute_binding",
|
|
4365
|
+
"policy_bundle"
|
|
4332
4366
|
]);
|
|
4333
4367
|
var permitOutboxOperation = z.enum([
|
|
4334
4368
|
"upsert",
|
|
@@ -4434,7 +4468,10 @@ defineTable({
|
|
|
4434
4468
|
}),
|
|
4435
4469
|
indices: [
|
|
4436
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"] },
|
|
4437
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"] },
|
|
4438
4475
|
{
|
|
4439
4476
|
kind: "index",
|
|
4440
4477
|
name: "by_tenant_provider_alias",
|
|
@@ -9407,7 +9444,7 @@ var IDENTITY_WHOAMI = {
|
|
|
9407
9444
|
description: "Canonical identity summary for the current session",
|
|
9408
9445
|
fields: {
|
|
9409
9446
|
principalId: "string \u2014 canonical federated principal identifier",
|
|
9410
|
-
principalType: "string \u2014 human, service, or
|
|
9447
|
+
principalType: "string \u2014 human, service, agent, group, or external_viewer",
|
|
9411
9448
|
tenantId: "string | undefined \u2014 resolved tenant scope",
|
|
9412
9449
|
workspaceId: "string | undefined \u2014 resolved workspace scope",
|
|
9413
9450
|
scopes: "string[] | undefined \u2014 granted scopes for this session",
|
|
@@ -9418,6 +9455,49 @@ var IDENTITY_WHOAMI = {
|
|
|
9418
9455
|
ontologyPrimitive: "identity",
|
|
9419
9456
|
tier: "workhorse"
|
|
9420
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
|
+
};
|
|
9421
9501
|
var COMPILE_CONTEXT = {
|
|
9422
9502
|
name: "compile_context",
|
|
9423
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.",
|
|
@@ -11320,6 +11400,7 @@ var MCP_TOOL_CONTRACTS = {
|
|
|
11320
11400
|
update_worktree_targets: UPDATE_WORKTREE_TARGETS,
|
|
11321
11401
|
update_worktree_metadata: UPDATE_WORKTREE_METADATA,
|
|
11322
11402
|
identity_whoami: IDENTITY_WHOAMI,
|
|
11403
|
+
resolve_interactive_principal: RESOLVE_INTERACTIVE_PRINCIPAL,
|
|
11323
11404
|
compile_context: COMPILE_CONTEXT,
|
|
11324
11405
|
record_scope_learning: RECORD_SCOPE_LEARNING,
|
|
11325
11406
|
pipeline_snapshot: PIPELINE_SNAPSHOT,
|
|
@@ -11437,6 +11518,7 @@ function entries(names, surfaceClass, surfaceIntent, surfaces, rationale) {
|
|
|
11437
11518
|
var MCP_CORE_OPERATION_NAMES = [
|
|
11438
11519
|
"compile_context",
|
|
11439
11520
|
"identity_whoami",
|
|
11521
|
+
"resolve_interactive_principal",
|
|
11440
11522
|
"check_permission",
|
|
11441
11523
|
"filter_by_permission",
|
|
11442
11524
|
"create_belief",
|
|
@@ -11990,7 +12072,13 @@ function surfaceContract(args) {
|
|
|
11990
12072
|
scopes: args.scopes ?? [
|
|
11991
12073
|
args.kind === "query" ? `${args.domain}.read` : `${args.domain}.write`
|
|
11992
12074
|
],
|
|
11993
|
-
allowedPrincipalTypes: [
|
|
12075
|
+
allowedPrincipalTypes: [
|
|
12076
|
+
"user",
|
|
12077
|
+
"service",
|
|
12078
|
+
"agent",
|
|
12079
|
+
"group",
|
|
12080
|
+
"external_viewer"
|
|
12081
|
+
]
|
|
11994
12082
|
},
|
|
11995
12083
|
convex: args.convex,
|
|
11996
12084
|
gateway: args.gateway,
|
|
@@ -12132,8 +12220,6 @@ var contextContracts = [
|
|
|
12132
12220
|
args: observationContextArgs
|
|
12133
12221
|
})
|
|
12134
12222
|
];
|
|
12135
|
-
|
|
12136
|
-
// ../contracts/src/function-registry/identity.ts
|
|
12137
12223
|
var withPrincipal = (input, context) => ({
|
|
12138
12224
|
...input,
|
|
12139
12225
|
tenantId: input.tenantId ?? context.tenantId,
|
|
@@ -12159,6 +12245,28 @@ var identityContracts = [
|
|
|
12159
12245
|
inputProjection: withPrincipal
|
|
12160
12246
|
}
|
|
12161
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
|
+
}),
|
|
12162
12270
|
surfaceContract({
|
|
12163
12271
|
name: "check_permission",
|
|
12164
12272
|
kind: "query",
|
|
@@ -16251,6 +16359,13 @@ var TENANT_BOOTSTRAP_TABLE_REQUIREMENTS = [
|
|
|
16251
16359
|
copyMode: "none",
|
|
16252
16360
|
description: "Deliberation sessions are created by tenant workflows."
|
|
16253
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
|
+
},
|
|
16254
16369
|
{
|
|
16255
16370
|
component: "kernel",
|
|
16256
16371
|
table: "epistemicAudit",
|
|
@@ -23080,23 +23195,31 @@ async function resolveTaskEventTopicId(authContext, task, operation) {
|
|
|
23080
23195
|
});
|
|
23081
23196
|
}
|
|
23082
23197
|
async function emitTaskEventFromGatewayAuth(authContext, args) {
|
|
23083
|
-
return
|
|
23084
|
-
|
|
23085
|
-
|
|
23086
|
-
|
|
23087
|
-
|
|
23088
|
-
|
|
23089
|
-
|
|
23090
|
-
|
|
23091
|
-
|
|
23092
|
-
|
|
23093
|
-
|
|
23094
|
-
|
|
23095
|
-
|
|
23096
|
-
|
|
23097
|
-
|
|
23098
|
-
|
|
23099
|
-
|
|
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
|
+
}
|
|
23100
23223
|
}
|
|
23101
23224
|
function gatewayIdempotencyArgs(authContext, options) {
|
|
23102
23225
|
{
|
|
@@ -23193,7 +23316,7 @@ async function createTaskFromGatewayAuth(authContext, input, options) {
|
|
|
23193
23316
|
...input,
|
|
23194
23317
|
topicId: resolvedTopic.topicId
|
|
23195
23318
|
});
|
|
23196
|
-
await
|
|
23319
|
+
await emitTaskEventBestEffortFromGatewayAuth(authContext, {
|
|
23197
23320
|
topicId: payload.topicId ?? resolvedTopic.topicId,
|
|
23198
23321
|
type: "task.created",
|
|
23199
23322
|
resourceId: payload.id,
|
|
@@ -23221,7 +23344,7 @@ async function updateTaskFromGatewayAuth(authContext, input, options) {
|
|
|
23221
23344
|
payload,
|
|
23222
23345
|
"update"
|
|
23223
23346
|
);
|
|
23224
|
-
await
|
|
23347
|
+
await emitTaskEventBestEffortFromGatewayAuth(authContext, {
|
|
23225
23348
|
topicId,
|
|
23226
23349
|
type: "task.updated",
|
|
23227
23350
|
resourceId: payload.id,
|
|
@@ -23248,7 +23371,7 @@ async function completeTaskFromGatewayAuth(authContext, input, options) {
|
|
|
23248
23371
|
payload,
|
|
23249
23372
|
"complete"
|
|
23250
23373
|
);
|
|
23251
|
-
await
|
|
23374
|
+
await emitTaskEventBestEffortFromGatewayAuth(authContext, {
|
|
23252
23375
|
topicId,
|
|
23253
23376
|
type: "task.completed",
|
|
23254
23377
|
resourceId: payload.id,
|
|
@@ -25728,7 +25851,7 @@ function handleEventsError(error, fallbackMessage, correlationId, policyTraceId)
|
|
|
25728
25851
|
}
|
|
25729
25852
|
async function handleEventsList(args) {
|
|
25730
25853
|
try {
|
|
25731
|
-
const payload = await args.authContext.convex.query(
|
|
25854
|
+
const payload = await args.authContext.convex.query(api.events.listEvents, {
|
|
25732
25855
|
tenantId: args.authContext.tenantId,
|
|
25733
25856
|
workspaceId: args.authContext.workspaceId,
|
|
25734
25857
|
topicId: args.query.topicId,
|
|
@@ -25754,7 +25877,7 @@ async function handleEventsList(args) {
|
|
|
25754
25877
|
async function handleEventsReplay(args) {
|
|
25755
25878
|
try {
|
|
25756
25879
|
const payload = await args.authContext.convex.mutation(
|
|
25757
|
-
|
|
25880
|
+
api.events.replayEvents,
|
|
25758
25881
|
{
|
|
25759
25882
|
tenantId: args.authContext.tenantId,
|
|
25760
25883
|
workspaceId: args.authContext.workspaceId,
|
|
@@ -27032,155 +27155,1452 @@ async function handleOntologyMatch(args) {
|
|
|
27032
27155
|
}
|
|
27033
27156
|
}
|
|
27034
27157
|
|
|
27035
|
-
//
|
|
27158
|
+
// ../server-core/src/auth/credentials.ts
|
|
27159
|
+
function parseAuthorizationBearer(value) {
|
|
27160
|
+
if (!value) return null;
|
|
27161
|
+
const [scheme, token] = value.trim().split(/\s+/, 2);
|
|
27162
|
+
if (!scheme || !token) return null;
|
|
27163
|
+
if (scheme.toLowerCase() !== "bearer") return null;
|
|
27164
|
+
return token.trim() || null;
|
|
27165
|
+
}
|
|
27166
|
+
|
|
27167
|
+
// ../../apps/gateway/src/routes/permit-webhook.ts
|
|
27168
|
+
var mcApi = anyApi;
|
|
27169
|
+
var mcClientCache = {
|
|
27170
|
+
value: null
|
|
27171
|
+
};
|
|
27172
|
+
function readString27(value) {
|
|
27173
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
27174
|
+
}
|
|
27036
27175
|
function asRecord25(value) {
|
|
27037
27176
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
27038
27177
|
}
|
|
27039
|
-
function
|
|
27040
|
-
|
|
27041
|
-
return void 0;
|
|
27042
|
-
}
|
|
27043
|
-
const normalized = value.trim();
|
|
27044
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
27178
|
+
function readSecret(env = process.env) {
|
|
27179
|
+
return readString27(env.LUCERN_PERMIT_WEBHOOK_SECRET) ?? readString27(env.PERMIT_WEBHOOK_SECRET);
|
|
27045
27180
|
}
|
|
27046
|
-
function
|
|
27047
|
-
|
|
27181
|
+
function isPermitWebhookAuthorized(args) {
|
|
27182
|
+
const expected = readSecret(args.env);
|
|
27183
|
+
if (!expected) {
|
|
27184
|
+
return false;
|
|
27185
|
+
}
|
|
27186
|
+
const bearer = parseAuthorizationBearer(args.headers.get("authorization"));
|
|
27187
|
+
const headerSecret = readString27(
|
|
27188
|
+
args.headers.get("x-lucern-permit-webhook-secret")
|
|
27189
|
+
);
|
|
27190
|
+
return bearer === expected || headerSecret === expected;
|
|
27048
27191
|
}
|
|
27049
|
-
function
|
|
27050
|
-
if (
|
|
27051
|
-
return
|
|
27192
|
+
function readTenantKeyFromValue(value) {
|
|
27193
|
+
if (typeof value === "string" && value.trim()) {
|
|
27194
|
+
return value.trim();
|
|
27052
27195
|
}
|
|
27053
|
-
const
|
|
27054
|
-
return
|
|
27196
|
+
const record = asRecord25(value);
|
|
27197
|
+
return readString27(record.key) ?? readString27(record.tenant) ?? readString27(record.tenantKey) ?? readString27(record.tenant_id);
|
|
27055
27198
|
}
|
|
27056
|
-
|
|
27057
|
-
|
|
27058
|
-
|
|
27059
|
-
const payload = await createQuestionFromGatewayAuth(args.authContext, {
|
|
27060
|
-
topicId: readString27(body.topicId),
|
|
27061
|
-
text: readString27(body.text) ?? "",
|
|
27062
|
-
priority: readString27(body.priority),
|
|
27063
|
-
linkedBeliefId: readString27(body.linkedBeliefId),
|
|
27064
|
-
metadata: asRecord25(body.metadata)
|
|
27065
|
-
});
|
|
27066
|
-
return successResponse(payload, {
|
|
27067
|
-
status: 201,
|
|
27068
|
-
correlationId: args.correlationId,
|
|
27069
|
-
policyTraceId: args.policyTraceId
|
|
27070
|
-
});
|
|
27071
|
-
} catch (error) {
|
|
27072
|
-
const resolved = resolveServerCoreError(error, "Failed to create question.");
|
|
27073
|
-
return errorResponse({
|
|
27074
|
-
code: resolved.code,
|
|
27075
|
-
message: resolved.message,
|
|
27076
|
-
status: resolved.status,
|
|
27077
|
-
correlationId: args.correlationId,
|
|
27078
|
-
policyTraceId: args.policyTraceId,
|
|
27079
|
-
invariant: resolved.invariant,
|
|
27080
|
-
suggestion: resolved.suggestion,
|
|
27081
|
-
details: resolved.details
|
|
27082
|
-
});
|
|
27199
|
+
function hasTenantIdentifier(value) {
|
|
27200
|
+
if (typeof value === "string" && value.trim()) {
|
|
27201
|
+
return true;
|
|
27083
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
|
+
);
|
|
27084
27207
|
}
|
|
27085
|
-
|
|
27086
|
-
|
|
27087
|
-
|
|
27088
|
-
|
|
27089
|
-
|
|
27208
|
+
function extractPermitWebhookTenantKeys(body) {
|
|
27209
|
+
const record = asRecord25(body);
|
|
27210
|
+
const candidates = [
|
|
27211
|
+
record.tenant,
|
|
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,
|
|
27239
|
+
record.tenant_id,
|
|
27240
|
+
asRecord25(record.data).tenant,
|
|
27241
|
+
asRecord25(record.data).tenantKey,
|
|
27242
|
+
asRecord25(record.data).tenant_key,
|
|
27243
|
+
asRecord25(record.data).tenant_id,
|
|
27244
|
+
asRecord25(record.object).tenant,
|
|
27245
|
+
asRecord25(record.object).tenantKey,
|
|
27246
|
+
asRecord25(record.object).tenant_key,
|
|
27247
|
+
asRecord25(record.object).tenant_id,
|
|
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
|
|
27260
|
+
];
|
|
27261
|
+
return candidates.some(hasTenantIdentifier);
|
|
27262
|
+
}
|
|
27263
|
+
function summarizePermitWebhookEvent(body) {
|
|
27264
|
+
const record = asRecord25(body);
|
|
27265
|
+
return {
|
|
27266
|
+
type: readString27(record.type) ?? readString27(record.event) ?? "permit.webhook",
|
|
27267
|
+
id: readString27(record.id) ?? readString27(record.event_id),
|
|
27268
|
+
tenantKeys: extractPermitWebhookTenantKeys(record)
|
|
27269
|
+
};
|
|
27270
|
+
}
|
|
27271
|
+
function getMasterControlConvexClient() {
|
|
27272
|
+
if (mcClientCache.value) {
|
|
27273
|
+
return mcClientCache.value;
|
|
27274
|
+
}
|
|
27275
|
+
const convexUrl = readString27(process.env.CONVEX_MC_URL);
|
|
27276
|
+
const deployKey = readString27(process.env.CONVEX_MC_DEPLOY_KEY);
|
|
27277
|
+
if (!convexUrl || !deployKey) {
|
|
27278
|
+
throw new GatewayAuthError(
|
|
27279
|
+
503,
|
|
27280
|
+
"UPSTREAM_ERROR",
|
|
27281
|
+
"Master Control is not configured. Set CONVEX_MC_URL and CONVEX_MC_DEPLOY_KEY."
|
|
27090
27282
|
);
|
|
27091
|
-
return successResponse(payload, {
|
|
27092
|
-
correlationId: args.correlationId,
|
|
27093
|
-
policyTraceId: args.policyTraceId
|
|
27094
|
-
});
|
|
27095
|
-
} catch (error) {
|
|
27096
|
-
const resolved = resolveServerCoreError(error, "Failed to read question.");
|
|
27097
|
-
return errorResponse({
|
|
27098
|
-
code: resolved.code,
|
|
27099
|
-
message: resolved.message,
|
|
27100
|
-
status: resolved.status,
|
|
27101
|
-
correlationId: args.correlationId,
|
|
27102
|
-
policyTraceId: args.policyTraceId,
|
|
27103
|
-
invariant: resolved.invariant,
|
|
27104
|
-
suggestion: resolved.suggestion,
|
|
27105
|
-
details: resolved.details
|
|
27106
|
-
});
|
|
27107
27283
|
}
|
|
27284
|
+
const client = new ConvexHttpClient(convexUrl);
|
|
27285
|
+
client.setAdminAuth(
|
|
27286
|
+
deployKey
|
|
27287
|
+
);
|
|
27288
|
+
mcClientCache.value = client;
|
|
27289
|
+
return client;
|
|
27108
27290
|
}
|
|
27109
|
-
|
|
27110
|
-
|
|
27111
|
-
|
|
27112
|
-
|
|
27113
|
-
|
|
27114
|
-
|
|
27115
|
-
|
|
27116
|
-
|
|
27291
|
+
function handlePermitWebhookError(error, correlationId, policyTraceId) {
|
|
27292
|
+
const resolved = resolveServerCoreError(
|
|
27293
|
+
error,
|
|
27294
|
+
"Failed to reconcile Permit projection."
|
|
27295
|
+
);
|
|
27296
|
+
return errorResponse({
|
|
27297
|
+
code: resolved.code,
|
|
27298
|
+
message: resolved.message,
|
|
27299
|
+
status: resolved.status,
|
|
27300
|
+
correlationId,
|
|
27301
|
+
policyTraceId,
|
|
27302
|
+
invariant: resolved.invariant,
|
|
27303
|
+
suggestion: resolved.suggestion,
|
|
27304
|
+
details: resolved.details
|
|
27305
|
+
});
|
|
27306
|
+
}
|
|
27307
|
+
async function handlePermitProjectionWebhook(args) {
|
|
27308
|
+
if (!readSecret()) {
|
|
27309
|
+
return errorResponse({
|
|
27310
|
+
status: 503,
|
|
27311
|
+
code: "INTERNAL_ERROR",
|
|
27312
|
+
message: "Permit webhook secret is not configured.",
|
|
27117
27313
|
correlationId: args.correlationId,
|
|
27118
27314
|
policyTraceId: args.policyTraceId
|
|
27119
27315
|
});
|
|
27120
|
-
}
|
|
27121
|
-
|
|
27316
|
+
}
|
|
27317
|
+
if (!isPermitWebhookAuthorized({ headers: args.request.headers })) {
|
|
27122
27318
|
return errorResponse({
|
|
27123
|
-
|
|
27124
|
-
|
|
27125
|
-
|
|
27319
|
+
status: 401,
|
|
27320
|
+
code: "AUTH_REQUIRED",
|
|
27321
|
+
message: "Permit webhook secret did not match.",
|
|
27126
27322
|
correlationId: args.correlationId,
|
|
27127
|
-
policyTraceId: args.policyTraceId
|
|
27128
|
-
invariant: resolved.invariant,
|
|
27129
|
-
suggestion: resolved.suggestion,
|
|
27130
|
-
details: resolved.details
|
|
27323
|
+
policyTraceId: args.policyTraceId
|
|
27131
27324
|
});
|
|
27132
27325
|
}
|
|
27133
|
-
}
|
|
27134
|
-
async function handleQuestionList(args) {
|
|
27135
27326
|
try {
|
|
27136
|
-
const
|
|
27137
|
-
|
|
27138
|
-
|
|
27139
|
-
|
|
27140
|
-
|
|
27327
|
+
const event = summarizePermitWebhookEvent(args.body);
|
|
27328
|
+
const tenantKeys = extractPermitWebhookTenantKeys(args.body);
|
|
27329
|
+
const hasTenantScope = hasPermitWebhookTenantScope(args.body);
|
|
27330
|
+
if (tenantKeys.length === 0 && !hasTenantScope) {
|
|
27331
|
+
return successResponse(
|
|
27332
|
+
{
|
|
27333
|
+
acknowledged: true,
|
|
27334
|
+
reconciled: false,
|
|
27335
|
+
reason: "No tenant key found; skipping tenant-scoped reconcile.",
|
|
27336
|
+
tenantKeys: []
|
|
27337
|
+
},
|
|
27338
|
+
{
|
|
27339
|
+
correlationId: args.correlationId,
|
|
27340
|
+
policyTraceId: args.policyTraceId
|
|
27341
|
+
}
|
|
27342
|
+
);
|
|
27343
|
+
}
|
|
27344
|
+
const client = args.convexClient ?? getMasterControlConvexClient();
|
|
27345
|
+
const receipt = await client.action(mcApi.permitProjectionActions.reconcile, {
|
|
27346
|
+
mode: "apply",
|
|
27347
|
+
trigger: "permit_webhook",
|
|
27348
|
+
tenantKeys: tenantKeys.length > 0 ? tenantKeys : void 0,
|
|
27349
|
+
environments: ["dev", "staging", "prod"],
|
|
27350
|
+
componentPath: "controlPlane",
|
|
27351
|
+
webhookSecret: readSecret(),
|
|
27352
|
+
event
|
|
27353
|
+
});
|
|
27354
|
+
return successResponse(
|
|
27355
|
+
{
|
|
27356
|
+
reconciled: true,
|
|
27357
|
+
receipt
|
|
27358
|
+
},
|
|
27359
|
+
{
|
|
27360
|
+
correlationId: args.correlationId,
|
|
27361
|
+
policyTraceId: args.policyTraceId
|
|
27362
|
+
}
|
|
27363
|
+
);
|
|
27141
27364
|
} catch (error) {
|
|
27142
|
-
|
|
27143
|
-
|
|
27144
|
-
|
|
27145
|
-
|
|
27146
|
-
|
|
27147
|
-
correlationId: args.correlationId,
|
|
27148
|
-
policyTraceId: args.policyTraceId,
|
|
27149
|
-
invariant: resolved.invariant,
|
|
27150
|
-
suggestion: resolved.suggestion,
|
|
27151
|
-
details: resolved.details
|
|
27152
|
-
});
|
|
27365
|
+
return handlePermitWebhookError(
|
|
27366
|
+
error,
|
|
27367
|
+
args.correlationId,
|
|
27368
|
+
args.policyTraceId
|
|
27369
|
+
);
|
|
27153
27370
|
}
|
|
27154
27371
|
}
|
|
27155
|
-
|
|
27156
|
-
|
|
27157
|
-
|
|
27158
|
-
|
|
27159
|
-
|
|
27160
|
-
|
|
27161
|
-
|
|
27162
|
-
|
|
27163
|
-
|
|
27164
|
-
|
|
27165
|
-
|
|
27166
|
-
|
|
27167
|
-
|
|
27168
|
-
|
|
27169
|
-
|
|
27170
|
-
|
|
27171
|
-
|
|
27172
|
-
|
|
27173
|
-
|
|
27174
|
-
|
|
27175
|
-
|
|
27176
|
-
|
|
27177
|
-
|
|
27178
|
-
|
|
27179
|
-
|
|
27180
|
-
|
|
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;
|
|
27181
27429
|
}
|
|
27430
|
+
return void 0;
|
|
27182
27431
|
}
|
|
27183
|
-
|
|
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
|
+
}
|
|
28454
|
+
|
|
28455
|
+
// ../../apps/gateway/src/routes/questions.ts
|
|
28456
|
+
function asRecord27(value) {
|
|
28457
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
28458
|
+
}
|
|
28459
|
+
function readString29(value) {
|
|
28460
|
+
if (typeof value !== "string") {
|
|
28461
|
+
return void 0;
|
|
28462
|
+
}
|
|
28463
|
+
const normalized = value.trim();
|
|
28464
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
28465
|
+
}
|
|
28466
|
+
function readNumber19(value) {
|
|
28467
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
28468
|
+
}
|
|
28469
|
+
function readStringArray14(value) {
|
|
28470
|
+
if (!Array.isArray(value)) {
|
|
28471
|
+
return void 0;
|
|
28472
|
+
}
|
|
28473
|
+
const items = value.map((entry) => readString29(entry)).filter((entry) => Boolean(entry));
|
|
28474
|
+
return items.length > 0 ? items : void 0;
|
|
28475
|
+
}
|
|
28476
|
+
async function handleQuestionCreate(args) {
|
|
28477
|
+
try {
|
|
28478
|
+
const body = asRecord27(args.body);
|
|
28479
|
+
const payload = await createQuestionFromGatewayAuth(args.authContext, {
|
|
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)
|
|
28485
|
+
});
|
|
28486
|
+
return successResponse(payload, {
|
|
28487
|
+
status: 201,
|
|
28488
|
+
correlationId: args.correlationId,
|
|
28489
|
+
policyTraceId: args.policyTraceId
|
|
28490
|
+
});
|
|
28491
|
+
} catch (error) {
|
|
28492
|
+
const resolved = resolveServerCoreError(error, "Failed to create question.");
|
|
28493
|
+
return errorResponse({
|
|
28494
|
+
code: resolved.code,
|
|
28495
|
+
message: resolved.message,
|
|
28496
|
+
status: resolved.status,
|
|
28497
|
+
correlationId: args.correlationId,
|
|
28498
|
+
policyTraceId: args.policyTraceId,
|
|
28499
|
+
invariant: resolved.invariant,
|
|
28500
|
+
suggestion: resolved.suggestion,
|
|
28501
|
+
details: resolved.details
|
|
28502
|
+
});
|
|
28503
|
+
}
|
|
28504
|
+
}
|
|
28505
|
+
async function handleQuestionGet(args) {
|
|
28506
|
+
try {
|
|
28507
|
+
const payload = await getQuestionFromGatewayAuth(
|
|
28508
|
+
args.authContext,
|
|
28509
|
+
args.questionId
|
|
28510
|
+
);
|
|
28511
|
+
return successResponse(payload, {
|
|
28512
|
+
correlationId: args.correlationId,
|
|
28513
|
+
policyTraceId: args.policyTraceId
|
|
28514
|
+
});
|
|
28515
|
+
} catch (error) {
|
|
28516
|
+
const resolved = resolveServerCoreError(error, "Failed to read question.");
|
|
28517
|
+
return errorResponse({
|
|
28518
|
+
code: resolved.code,
|
|
28519
|
+
message: resolved.message,
|
|
28520
|
+
status: resolved.status,
|
|
28521
|
+
correlationId: args.correlationId,
|
|
28522
|
+
policyTraceId: args.policyTraceId,
|
|
28523
|
+
invariant: resolved.invariant,
|
|
28524
|
+
suggestion: resolved.suggestion,
|
|
28525
|
+
details: resolved.details
|
|
28526
|
+
});
|
|
28527
|
+
}
|
|
28528
|
+
}
|
|
28529
|
+
async function handleQuestionArchive(args) {
|
|
28530
|
+
try {
|
|
28531
|
+
const body = asRecord27(args.body);
|
|
28532
|
+
const payload = await archiveQuestionFromGatewayAuth(args.authContext, {
|
|
28533
|
+
id: args.questionId,
|
|
28534
|
+
rationale: readString29(body.reason) ?? readString29(body.rationale)
|
|
28535
|
+
});
|
|
28536
|
+
return successResponse(payload, {
|
|
28537
|
+
correlationId: args.correlationId,
|
|
28538
|
+
policyTraceId: args.policyTraceId
|
|
28539
|
+
});
|
|
28540
|
+
} catch (error) {
|
|
28541
|
+
const resolved = resolveServerCoreError(error, "Failed to archive question.");
|
|
28542
|
+
return errorResponse({
|
|
28543
|
+
code: resolved.code,
|
|
28544
|
+
message: resolved.message,
|
|
28545
|
+
status: resolved.status,
|
|
28546
|
+
correlationId: args.correlationId,
|
|
28547
|
+
policyTraceId: args.policyTraceId,
|
|
28548
|
+
invariant: resolved.invariant,
|
|
28549
|
+
suggestion: resolved.suggestion,
|
|
28550
|
+
details: resolved.details
|
|
28551
|
+
});
|
|
28552
|
+
}
|
|
28553
|
+
}
|
|
28554
|
+
async function handleQuestionList(args) {
|
|
28555
|
+
try {
|
|
28556
|
+
const payload = await listQuestionsFromGatewayAuth(args.authContext, args.query);
|
|
28557
|
+
return successResponse(payload, {
|
|
28558
|
+
correlationId: args.correlationId,
|
|
28559
|
+
policyTraceId: args.policyTraceId
|
|
28560
|
+
});
|
|
28561
|
+
} catch (error) {
|
|
28562
|
+
const resolved = resolveServerCoreError(error, "Failed to list questions.");
|
|
28563
|
+
return errorResponse({
|
|
28564
|
+
code: resolved.code,
|
|
28565
|
+
message: resolved.message,
|
|
28566
|
+
status: resolved.status,
|
|
28567
|
+
correlationId: args.correlationId,
|
|
28568
|
+
policyTraceId: args.policyTraceId,
|
|
28569
|
+
invariant: resolved.invariant,
|
|
28570
|
+
suggestion: resolved.suggestion,
|
|
28571
|
+
details: resolved.details
|
|
28572
|
+
});
|
|
28573
|
+
}
|
|
28574
|
+
}
|
|
28575
|
+
async function handleQuestionAnswer(args) {
|
|
28576
|
+
try {
|
|
28577
|
+
const body = asRecord27(args.body);
|
|
28578
|
+
const payload = await answerQuestionFromGatewayAuth(args.authContext, {
|
|
28579
|
+
id: args.questionId,
|
|
28580
|
+
text: readString29(body.text) ?? "",
|
|
28581
|
+
confidence: readString29(body.confidence),
|
|
28582
|
+
evidenceIds: readStringArray14(body.evidenceIds),
|
|
28583
|
+
rationale: readString29(body.rationale)
|
|
28584
|
+
});
|
|
28585
|
+
return successResponse(payload, {
|
|
28586
|
+
correlationId: args.correlationId,
|
|
28587
|
+
policyTraceId: args.policyTraceId
|
|
28588
|
+
});
|
|
28589
|
+
} catch (error) {
|
|
28590
|
+
const resolved = resolveServerCoreError(error, "Failed to answer question.");
|
|
28591
|
+
return errorResponse({
|
|
28592
|
+
code: resolved.code,
|
|
28593
|
+
message: resolved.message,
|
|
28594
|
+
status: resolved.status,
|
|
28595
|
+
correlationId: args.correlationId,
|
|
28596
|
+
policyTraceId: args.policyTraceId,
|
|
28597
|
+
invariant: resolved.invariant,
|
|
28598
|
+
suggestion: resolved.suggestion,
|
|
28599
|
+
details: resolved.details
|
|
28600
|
+
});
|
|
28601
|
+
}
|
|
28602
|
+
}
|
|
28603
|
+
async function handleQuestionGetAnswer(args) {
|
|
27184
28604
|
try {
|
|
27185
28605
|
const payload = await getQuestionAnswerFromGatewayAuth(
|
|
27186
28606
|
args.authContext,
|
|
@@ -27206,11 +28626,11 @@ async function handleQuestionGetAnswer(args) {
|
|
|
27206
28626
|
}
|
|
27207
28627
|
async function handleQuestionRefine(args) {
|
|
27208
28628
|
try {
|
|
27209
|
-
const body =
|
|
28629
|
+
const body = asRecord27(args.body);
|
|
27210
28630
|
const payload = await refineQuestionFromGatewayAuth(args.authContext, {
|
|
27211
28631
|
id: args.questionId,
|
|
27212
|
-
text:
|
|
27213
|
-
rationale:
|
|
28632
|
+
text: readString29(body.text) ?? "",
|
|
28633
|
+
rationale: readString29(body.rationale)
|
|
27214
28634
|
});
|
|
27215
28635
|
return successResponse(payload, {
|
|
27216
28636
|
correlationId: args.correlationId,
|
|
@@ -27232,11 +28652,11 @@ async function handleQuestionRefine(args) {
|
|
|
27232
28652
|
}
|
|
27233
28653
|
async function handleQuestionUpdateStatus(args) {
|
|
27234
28654
|
try {
|
|
27235
|
-
const body =
|
|
28655
|
+
const body = asRecord27(args.body);
|
|
27236
28656
|
const payload = await updateQuestionStatusFromGatewayAuth(args.authContext, {
|
|
27237
28657
|
id: args.questionId,
|
|
27238
|
-
status:
|
|
27239
|
-
rationale:
|
|
28658
|
+
status: readString29(body.status) ?? "",
|
|
28659
|
+
rationale: readString29(body.rationale)
|
|
27240
28660
|
});
|
|
27241
28661
|
return successResponse(payload, {
|
|
27242
28662
|
correlationId: args.correlationId,
|
|
@@ -27261,19 +28681,19 @@ async function handleQuestionUpdateStatus(args) {
|
|
|
27261
28681
|
}
|
|
27262
28682
|
async function handleQuestionBatchCreate(args) {
|
|
27263
28683
|
try {
|
|
27264
|
-
const body =
|
|
27265
|
-
const questions = Array.isArray(body.questions) ? body.questions.map((entry) =>
|
|
27266
|
-
question:
|
|
27267
|
-
category:
|
|
27268
|
-
priority:
|
|
27269
|
-
linkedBeliefNodeId:
|
|
27270
|
-
linkedWorktreeId:
|
|
27271
|
-
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)
|
|
27272
28692
|
})) : [];
|
|
27273
28693
|
const payload = await createQuestionsBatchFromGatewayAuth(args.authContext, {
|
|
27274
|
-
topicId:
|
|
28694
|
+
topicId: readString29(body.topicId),
|
|
27275
28695
|
questions,
|
|
27276
|
-
source:
|
|
28696
|
+
source: readString29(body.source)
|
|
27277
28697
|
});
|
|
27278
28698
|
return successResponse(payload, {
|
|
27279
28699
|
status: 201,
|
|
@@ -27299,20 +28719,20 @@ async function handleQuestionBatchCreate(args) {
|
|
|
27299
28719
|
}
|
|
27300
28720
|
async function handleQuestionAdd(args) {
|
|
27301
28721
|
try {
|
|
27302
|
-
const body =
|
|
28722
|
+
const body = asRecord27(args.body);
|
|
27303
28723
|
const payload = await addQuestionFromGatewayAuth(args.authContext, {
|
|
27304
|
-
topicId:
|
|
27305
|
-
question:
|
|
27306
|
-
category:
|
|
27307
|
-
priority:
|
|
27308
|
-
source:
|
|
27309
|
-
beliefId:
|
|
27310
|
-
linkedWorktreeId:
|
|
27311
|
-
chatId:
|
|
27312
|
-
importance:
|
|
27313
|
-
epistemicUnlock:
|
|
27314
|
-
metadata:
|
|
27315
|
-
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)
|
|
27316
28736
|
});
|
|
27317
28737
|
return successResponse(payload, {
|
|
27318
28738
|
status: 201,
|
|
@@ -27335,12 +28755,12 @@ async function handleQuestionAdd(args) {
|
|
|
27335
28755
|
}
|
|
27336
28756
|
async function handleQuestionUpdatePriority(args) {
|
|
27337
28757
|
try {
|
|
27338
|
-
const body =
|
|
28758
|
+
const body = asRecord27(args.body);
|
|
27339
28759
|
const payload = await updateQuestionPriorityFromGatewayAuth(
|
|
27340
28760
|
args.authContext,
|
|
27341
28761
|
{
|
|
27342
|
-
id:
|
|
27343
|
-
priority:
|
|
28762
|
+
id: readString29(body.id) ?? readString29(body.nodeId) ?? readString29(body.questionId),
|
|
28763
|
+
priority: readString29(body.priority) ?? "medium"
|
|
27344
28764
|
}
|
|
27345
28765
|
);
|
|
27346
28766
|
return successResponse(payload, {
|
|
@@ -27366,12 +28786,12 @@ async function handleQuestionUpdatePriority(args) {
|
|
|
27366
28786
|
}
|
|
27367
28787
|
async function handleQuestionAdvanceToConviction(args) {
|
|
27368
28788
|
try {
|
|
27369
|
-
const body =
|
|
28789
|
+
const body = asRecord27(args.body);
|
|
27370
28790
|
const payload = await advanceQuestionToConvictionFromGatewayAuth(
|
|
27371
28791
|
args.authContext,
|
|
27372
28792
|
{
|
|
27373
|
-
questionId:
|
|
27374
|
-
worktreeId:
|
|
28793
|
+
questionId: readString29(body.questionId) ?? readString29(body.id) ?? readString29(body.nodeId),
|
|
28794
|
+
worktreeId: readString29(body.worktreeId)
|
|
27375
28795
|
}
|
|
27376
28796
|
);
|
|
27377
28797
|
return successResponse(payload, {
|
|
@@ -27397,14 +28817,14 @@ async function handleQuestionAdvanceToConviction(args) {
|
|
|
27397
28817
|
}
|
|
27398
28818
|
async function handleQuestionUpdateConviction(args) {
|
|
27399
28819
|
try {
|
|
27400
|
-
const body =
|
|
28820
|
+
const body = asRecord27(args.body);
|
|
27401
28821
|
const payload = await updateQuestionConvictionFromGatewayAuth(
|
|
27402
28822
|
args.authContext,
|
|
27403
28823
|
{
|
|
27404
|
-
questionId:
|
|
27405
|
-
conviction:
|
|
27406
|
-
answerCompleteness:
|
|
27407
|
-
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)
|
|
27408
28828
|
}
|
|
27409
28829
|
);
|
|
27410
28830
|
return successResponse(payload, {
|
|
@@ -27430,16 +28850,16 @@ async function handleQuestionUpdateConviction(args) {
|
|
|
27430
28850
|
}
|
|
27431
28851
|
async function handleQuestionFinalizeConviction(args) {
|
|
27432
28852
|
try {
|
|
27433
|
-
const body =
|
|
28853
|
+
const body = asRecord27(args.body);
|
|
27434
28854
|
const payload = await finalizeQuestionConvictionFromGatewayAuth(
|
|
27435
28855
|
args.authContext,
|
|
27436
28856
|
{
|
|
27437
|
-
questionId:
|
|
27438
|
-
conviction:
|
|
27439
|
-
answer:
|
|
27440
|
-
convictionRationale:
|
|
27441
|
-
answerCompleteness:
|
|
27442
|
-
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)
|
|
27443
28863
|
}
|
|
27444
28864
|
);
|
|
27445
28865
|
return successResponse(payload, {
|
|
@@ -27465,12 +28885,12 @@ async function handleQuestionFinalizeConviction(args) {
|
|
|
27465
28885
|
}
|
|
27466
28886
|
async function handleQuestionUpdate(args) {
|
|
27467
28887
|
try {
|
|
27468
|
-
const body =
|
|
28888
|
+
const body = asRecord27(args.body);
|
|
27469
28889
|
const payload = await updateQuestionFromGatewayAuth(args.authContext, {
|
|
27470
|
-
questionId:
|
|
27471
|
-
question:
|
|
27472
|
-
category:
|
|
27473
|
-
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)
|
|
27474
28894
|
});
|
|
27475
28895
|
return successResponse(payload, {
|
|
27476
28896
|
correlationId: args.correlationId,
|
|
@@ -27492,9 +28912,9 @@ async function handleQuestionUpdate(args) {
|
|
|
27492
28912
|
}
|
|
27493
28913
|
async function handleQuestionDelete(args) {
|
|
27494
28914
|
try {
|
|
27495
|
-
const body =
|
|
28915
|
+
const body = asRecord27(args.body);
|
|
27496
28916
|
const payload = await deleteQuestionFromGatewayAuth(args.authContext, {
|
|
27497
|
-
questionId:
|
|
28917
|
+
questionId: readString29(body.questionId) ?? readString29(body.id) ?? readString29(body.nodeId)
|
|
27498
28918
|
});
|
|
27499
28919
|
return successResponse(payload, {
|
|
27500
28920
|
correlationId: args.correlationId,
|
|
@@ -27516,30 +28936,30 @@ async function handleQuestionDelete(args) {
|
|
|
27516
28936
|
}
|
|
27517
28937
|
|
|
27518
28938
|
// ../../apps/gateway/src/routes/search.ts
|
|
27519
|
-
function
|
|
28939
|
+
function asRecord28(value) {
|
|
27520
28940
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
27521
28941
|
}
|
|
27522
|
-
function
|
|
28942
|
+
function readString30(value) {
|
|
27523
28943
|
if (typeof value !== "string") {
|
|
27524
28944
|
return void 0;
|
|
27525
28945
|
}
|
|
27526
28946
|
const normalized = value.trim();
|
|
27527
28947
|
return normalized.length > 0 ? normalized : void 0;
|
|
27528
28948
|
}
|
|
27529
|
-
function
|
|
28949
|
+
function readNumber20(value) {
|
|
27530
28950
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
27531
28951
|
}
|
|
27532
28952
|
function readStringArray15(value) {
|
|
27533
28953
|
if (!Array.isArray(value)) {
|
|
27534
28954
|
return void 0;
|
|
27535
28955
|
}
|
|
27536
|
-
const items = value.map((entry) =>
|
|
28956
|
+
const items = value.map((entry) => readString30(entry)).filter((entry) => Boolean(entry));
|
|
27537
28957
|
return items.length > 0 ? items : void 0;
|
|
27538
28958
|
}
|
|
27539
28959
|
async function handleSearchResources(args) {
|
|
27540
|
-
const body =
|
|
27541
|
-
const q =
|
|
27542
|
-
const topicId =
|
|
28960
|
+
const body = asRecord28(args.body);
|
|
28961
|
+
const q = readString30(body.q) ?? readString30(body.query);
|
|
28962
|
+
const topicId = readString30(body.topicId) ?? readString30(body.projectId);
|
|
27543
28963
|
if (!q) {
|
|
27544
28964
|
return errorResponse({
|
|
27545
28965
|
code: "INVALID_REQUEST",
|
|
@@ -27563,10 +28983,10 @@ async function handleSearchResources(args) {
|
|
|
27563
28983
|
q,
|
|
27564
28984
|
topicId,
|
|
27565
28985
|
types: readStringArray15(body.types),
|
|
27566
|
-
status:
|
|
27567
|
-
minConfidence:
|
|
27568
|
-
limit:
|
|
27569
|
-
cursor:
|
|
28986
|
+
status: readString30(body.status),
|
|
28987
|
+
minConfidence: readNumber20(body.minConfidence),
|
|
28988
|
+
limit: readNumber20(body.limit),
|
|
28989
|
+
cursor: readString30(body.cursor)
|
|
27570
28990
|
});
|
|
27571
28991
|
return successResponse(payload, {
|
|
27572
28992
|
correlationId: args.correlationId,
|
|
@@ -27588,17 +29008,17 @@ async function handleSearchResources(args) {
|
|
|
27588
29008
|
}
|
|
27589
29009
|
|
|
27590
29010
|
// ../../apps/gateway/src/routes/sources.ts
|
|
27591
|
-
function
|
|
29011
|
+
function asRecord29(value) {
|
|
27592
29012
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
27593
29013
|
}
|
|
27594
|
-
function
|
|
29014
|
+
function readString31(value) {
|
|
27595
29015
|
if (typeof value !== "string") {
|
|
27596
29016
|
return void 0;
|
|
27597
29017
|
}
|
|
27598
29018
|
const normalized = value.trim();
|
|
27599
29019
|
return normalized.length > 0 ? normalized : void 0;
|
|
27600
29020
|
}
|
|
27601
|
-
function
|
|
29021
|
+
function readNumber21(value) {
|
|
27602
29022
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
27603
29023
|
}
|
|
27604
29024
|
function handleSourcesError(error, fallbackMessage, correlationId, policyTraceId) {
|
|
@@ -27616,15 +29036,15 @@ function handleSourcesError(error, fallbackMessage, correlationId, policyTraceId
|
|
|
27616
29036
|
}
|
|
27617
29037
|
async function handleSourceUpsert(args) {
|
|
27618
29038
|
try {
|
|
27619
|
-
const body =
|
|
29039
|
+
const body = asRecord29(args.body);
|
|
27620
29040
|
const payload = await upsertSourceFromGatewayAuth(args.authContext, {
|
|
27621
|
-
url:
|
|
27622
|
-
sha:
|
|
27623
|
-
kind:
|
|
27624
|
-
title:
|
|
27625
|
-
capturedAt:
|
|
27626
|
-
topicId:
|
|
27627
|
-
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)
|
|
27628
29048
|
});
|
|
27629
29049
|
return successResponse(payload, {
|
|
27630
29050
|
status: 201,
|
|
@@ -27658,10 +29078,10 @@ async function handleSourceGet(args) {
|
|
|
27658
29078
|
}
|
|
27659
29079
|
|
|
27660
29080
|
// ../../apps/gateway/src/routes/tasks.ts
|
|
27661
|
-
function
|
|
29081
|
+
function asRecord30(value) {
|
|
27662
29082
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
27663
29083
|
}
|
|
27664
|
-
function
|
|
29084
|
+
function readString32(value) {
|
|
27665
29085
|
if (typeof value !== "string") {
|
|
27666
29086
|
return void 0;
|
|
27667
29087
|
}
|
|
@@ -27683,18 +29103,18 @@ function handleTasksError(error, fallbackMessage, correlationId, policyTraceId)
|
|
|
27683
29103
|
}
|
|
27684
29104
|
async function handleTaskCreate(args) {
|
|
27685
29105
|
try {
|
|
27686
|
-
const body =
|
|
29106
|
+
const body = asRecord30(args.body);
|
|
27687
29107
|
const payload = await createTaskFromGatewayAuth(args.authContext, {
|
|
27688
|
-
topicId:
|
|
27689
|
-
title:
|
|
27690
|
-
description:
|
|
27691
|
-
taskType:
|
|
27692
|
-
priority:
|
|
27693
|
-
status:
|
|
27694
|
-
linkedBeliefId:
|
|
27695
|
-
linkedQuestionId:
|
|
27696
|
-
linkedWorktreeId:
|
|
27697
|
-
tags: Array.isArray(body.tags) ? body.tags.map((entry) =>
|
|
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,
|
|
27698
29118
|
metadata: body.metadata && typeof body.metadata === "object" && !Array.isArray(body.metadata) ? body.metadata : void 0
|
|
27699
29119
|
});
|
|
27700
29120
|
return successResponse(payload, {
|
|
@@ -27729,16 +29149,16 @@ async function handleTaskList(args) {
|
|
|
27729
29149
|
}
|
|
27730
29150
|
async function handleTaskUpdate(args) {
|
|
27731
29151
|
try {
|
|
27732
|
-
const body =
|
|
29152
|
+
const body = asRecord30(args.body);
|
|
27733
29153
|
const payload = await updateTaskFromGatewayAuth(args.authContext, {
|
|
27734
29154
|
id: args.taskId,
|
|
27735
|
-
title:
|
|
27736
|
-
description:
|
|
27737
|
-
priority:
|
|
27738
|
-
status:
|
|
27739
|
-
linkedBeliefId:
|
|
27740
|
-
linkedQuestionId:
|
|
27741
|
-
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),
|
|
27742
29162
|
metadata: body.metadata && typeof body.metadata === "object" && !Array.isArray(body.metadata) ? body.metadata : void 0
|
|
27743
29163
|
});
|
|
27744
29164
|
return successResponse(payload, {
|
|
@@ -27756,10 +29176,10 @@ async function handleTaskUpdate(args) {
|
|
|
27756
29176
|
}
|
|
27757
29177
|
async function handleTaskComplete(args) {
|
|
27758
29178
|
try {
|
|
27759
|
-
const body =
|
|
29179
|
+
const body = asRecord30(args.body);
|
|
27760
29180
|
const payload = await completeTaskFromGatewayAuth(args.authContext, {
|
|
27761
29181
|
id: args.taskId,
|
|
27762
|
-
outputSummary:
|
|
29182
|
+
outputSummary: readString32(body.outputSummary)
|
|
27763
29183
|
});
|
|
27764
29184
|
return successResponse(payload, {
|
|
27765
29185
|
correlationId: args.correlationId,
|
|
@@ -27776,10 +29196,10 @@ async function handleTaskComplete(args) {
|
|
|
27776
29196
|
}
|
|
27777
29197
|
|
|
27778
29198
|
// ../../apps/gateway/src/routes/topics.ts
|
|
27779
|
-
function
|
|
29199
|
+
function asRecord31(value) {
|
|
27780
29200
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
27781
29201
|
}
|
|
27782
|
-
function
|
|
29202
|
+
function readString33(value) {
|
|
27783
29203
|
if (typeof value !== "string") {
|
|
27784
29204
|
return void 0;
|
|
27785
29205
|
}
|
|
@@ -27789,14 +29209,14 @@ function readString31(value) {
|
|
|
27789
29209
|
function readBoolean(value) {
|
|
27790
29210
|
return typeof value === "boolean" ? value : void 0;
|
|
27791
29211
|
}
|
|
27792
|
-
function
|
|
29212
|
+
function readNumber22(value) {
|
|
27793
29213
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
27794
29214
|
}
|
|
27795
29215
|
function readStringArray16(value) {
|
|
27796
29216
|
if (!Array.isArray(value)) {
|
|
27797
29217
|
return void 0;
|
|
27798
29218
|
}
|
|
27799
|
-
const items = value.map((entry) =>
|
|
29219
|
+
const items = value.map((entry) => readString33(entry)).filter((entry) => Boolean(entry));
|
|
27800
29220
|
return items.length > 0 ? items : void 0;
|
|
27801
29221
|
}
|
|
27802
29222
|
function handleTopicsError(error, fallbackMessage, correlationId, policyTraceId) {
|
|
@@ -27814,17 +29234,17 @@ function handleTopicsError(error, fallbackMessage, correlationId, policyTraceId)
|
|
|
27814
29234
|
}
|
|
27815
29235
|
async function handleTopicCreate(args) {
|
|
27816
29236
|
try {
|
|
27817
|
-
const body =
|
|
29237
|
+
const body = asRecord31(args.body);
|
|
27818
29238
|
const payload = await createTopicFromGatewayAuth(args.authContext, {
|
|
27819
|
-
name:
|
|
27820
|
-
description:
|
|
27821
|
-
type:
|
|
27822
|
-
parentTopicId:
|
|
27823
|
-
ontologyId:
|
|
27824
|
-
tenantId:
|
|
27825
|
-
workspaceId:
|
|
27826
|
-
visibility:
|
|
27827
|
-
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)
|
|
27828
29248
|
});
|
|
27829
29249
|
return successResponse(payload, {
|
|
27830
29250
|
status: 201,
|
|
@@ -27842,16 +29262,16 @@ async function handleTopicCreate(args) {
|
|
|
27842
29262
|
}
|
|
27843
29263
|
async function handleTopicUpdate(args) {
|
|
27844
29264
|
try {
|
|
27845
|
-
const body =
|
|
29265
|
+
const body = asRecord31(args.body);
|
|
27846
29266
|
const payload = await updateTopicFromGatewayAuth(args.authContext, {
|
|
27847
29267
|
id: args.topicId,
|
|
27848
|
-
name:
|
|
27849
|
-
description:
|
|
27850
|
-
type:
|
|
27851
|
-
ontologyId:
|
|
29268
|
+
name: readString33(body.name),
|
|
29269
|
+
description: readString33(body.description),
|
|
29270
|
+
type: readString33(body.type),
|
|
29271
|
+
ontologyId: readString33(body.ontologyId),
|
|
27852
29272
|
clearOntologyId: readBoolean(body.clearOntologyId),
|
|
27853
|
-
status:
|
|
27854
|
-
visibility:
|
|
29273
|
+
status: readString33(body.status),
|
|
29274
|
+
visibility: readString33(body.visibility)
|
|
27855
29275
|
});
|
|
27856
29276
|
return successResponse(payload, {
|
|
27857
29277
|
correlationId: args.correlationId,
|
|
@@ -27902,7 +29322,7 @@ async function handleTopicTree(args) {
|
|
|
27902
29322
|
try {
|
|
27903
29323
|
const payload = await getTopicTreeFromGatewayAuth(args.authContext, {
|
|
27904
29324
|
id: args.topicId,
|
|
27905
|
-
maxDepth:
|
|
29325
|
+
maxDepth: readNumber22(args.query.maxDepth)
|
|
27906
29326
|
});
|
|
27907
29327
|
return successResponse(payload, {
|
|
27908
29328
|
correlationId: args.correlationId,
|
|
@@ -27922,7 +29342,7 @@ async function handleTopicCoverage(args) {
|
|
|
27922
29342
|
const payload = await getTopicCoverageFromGatewayAuth(args.authContext, {
|
|
27923
29343
|
id: args.topicId,
|
|
27924
29344
|
includeDescendants: typeof args.query.includeDescendants === "boolean" ? args.query.includeDescendants : void 0,
|
|
27925
|
-
maxDepth:
|
|
29345
|
+
maxDepth: readNumber22(args.query.maxDepth)
|
|
27926
29346
|
});
|
|
27927
29347
|
return successResponse(payload, {
|
|
27928
29348
|
correlationId: args.correlationId,
|
|
@@ -27939,9 +29359,9 @@ async function handleTopicCoverage(args) {
|
|
|
27939
29359
|
}
|
|
27940
29360
|
async function handleTopicRemove(args) {
|
|
27941
29361
|
try {
|
|
27942
|
-
const body =
|
|
29362
|
+
const body = asRecord31(args.body);
|
|
27943
29363
|
const payload = await removeTopicFromGatewayAuth(args.authContext, {
|
|
27944
|
-
id:
|
|
29364
|
+
id: readString33(body.id) ?? readString33(body.topicId) ?? ""
|
|
27945
29365
|
});
|
|
27946
29366
|
return successResponse(payload, {
|
|
27947
29367
|
correlationId: args.correlationId,
|
|
@@ -27958,22 +29378,22 @@ async function handleTopicRemove(args) {
|
|
|
27958
29378
|
}
|
|
27959
29379
|
async function handleTopicBulkCreate(args) {
|
|
27960
29380
|
try {
|
|
27961
|
-
const body =
|
|
27962
|
-
const topics2 = Array.isArray(body.topics) ? body.topics.map((entry) =>
|
|
27963
|
-
globalId:
|
|
27964
|
-
name:
|
|
27965
|
-
description:
|
|
27966
|
-
type:
|
|
27967
|
-
parentTopicId:
|
|
27968
|
-
depth:
|
|
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,
|
|
27969
29389
|
path: readStringArray16(entry.path) ?? [],
|
|
27970
|
-
tenantId:
|
|
27971
|
-
workspaceId:
|
|
27972
|
-
graphScopeProjectId:
|
|
27973
|
-
status:
|
|
27974
|
-
visibility:
|
|
27975
|
-
metadata:
|
|
27976
|
-
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)
|
|
27977
29397
|
})) : [];
|
|
27978
29398
|
const payload = await bulkCreateTopicsFromGatewayAuth(args.authContext, {
|
|
27979
29399
|
topics: topics2
|
|
@@ -27994,10 +29414,10 @@ async function handleTopicBulkCreate(args) {
|
|
|
27994
29414
|
}
|
|
27995
29415
|
|
|
27996
29416
|
// ../../apps/gateway/src/routes/webhooks.ts
|
|
27997
|
-
function
|
|
29417
|
+
function asRecord32(value) {
|
|
27998
29418
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
27999
29419
|
}
|
|
28000
|
-
function
|
|
29420
|
+
function readString34(value) {
|
|
28001
29421
|
if (typeof value !== "string") {
|
|
28002
29422
|
return void 0;
|
|
28003
29423
|
}
|
|
@@ -28011,7 +29431,7 @@ function readStringArray17(value) {
|
|
|
28011
29431
|
if (!Array.isArray(value)) {
|
|
28012
29432
|
return void 0;
|
|
28013
29433
|
}
|
|
28014
|
-
const normalized = value.map((entry) =>
|
|
29434
|
+
const normalized = value.map((entry) => readString34(entry)).filter((entry) => Boolean(entry));
|
|
28015
29435
|
return normalized.length > 0 ? normalized : void 0;
|
|
28016
29436
|
}
|
|
28017
29437
|
function handleWebhooksError(error, fallbackMessage, correlationId, policyTraceId) {
|
|
@@ -28029,16 +29449,16 @@ function handleWebhooksError(error, fallbackMessage, correlationId, policyTraceI
|
|
|
28029
29449
|
}
|
|
28030
29450
|
async function handleWebhookCreate(args) {
|
|
28031
29451
|
try {
|
|
28032
|
-
const body =
|
|
29452
|
+
const body = asRecord32(args.body);
|
|
28033
29453
|
const payload = await args.authContext.convex.mutation(
|
|
28034
29454
|
"events:createWebhook",
|
|
28035
29455
|
{
|
|
28036
29456
|
tenantId: args.authContext.tenantId,
|
|
28037
29457
|
workspaceId: args.authContext.workspaceId,
|
|
28038
|
-
topicId:
|
|
28039
|
-
url:
|
|
29458
|
+
topicId: readString34(body.topicId),
|
|
29459
|
+
url: readString34(body.url) ?? "",
|
|
28040
29460
|
events: readStringArray17(body.events) ?? [],
|
|
28041
|
-
secret:
|
|
29461
|
+
secret: readString34(body.secret) ?? "",
|
|
28042
29462
|
active: readBoolean2(body.active),
|
|
28043
29463
|
createdBy: args.authContext.principalId ?? args.authContext.userId
|
|
28044
29464
|
}
|
|
@@ -28099,17 +29519,17 @@ async function handleWebhookGet(args) {
|
|
|
28099
29519
|
}
|
|
28100
29520
|
async function handleWebhookUpdate(args) {
|
|
28101
29521
|
try {
|
|
28102
|
-
const body =
|
|
29522
|
+
const body = asRecord32(args.body);
|
|
28103
29523
|
const payload = await args.authContext.convex.mutation(
|
|
28104
29524
|
"events:updateWebhook",
|
|
28105
29525
|
{
|
|
28106
29526
|
webhookId: args.webhookId,
|
|
28107
29527
|
tenantId: args.authContext.tenantId,
|
|
28108
29528
|
workspaceId: args.authContext.workspaceId,
|
|
28109
|
-
url:
|
|
29529
|
+
url: readString34(body.url),
|
|
28110
29530
|
events: readStringArray17(body.events),
|
|
28111
|
-
secret:
|
|
28112
|
-
topicId:
|
|
29531
|
+
secret: readString34(body.secret),
|
|
29532
|
+
topicId: readString34(body.topicId),
|
|
28113
29533
|
clearTopicId: body.topicId === null ? true : readBoolean2(body.clearTopicId),
|
|
28114
29534
|
active: readBoolean2(body.active),
|
|
28115
29535
|
updatedBy: args.authContext.principalId ?? args.authContext.userId
|
|
@@ -28153,12 +29573,12 @@ async function handleWebhookDelete(args) {
|
|
|
28153
29573
|
}
|
|
28154
29574
|
async function handleWebhookTest(args) {
|
|
28155
29575
|
try {
|
|
28156
|
-
const body =
|
|
29576
|
+
const body = asRecord32(args.body);
|
|
28157
29577
|
const payload = await args.authContext.convex.action("events:testWebhook", {
|
|
28158
29578
|
webhookId: args.webhookId,
|
|
28159
29579
|
tenantId: args.authContext.tenantId,
|
|
28160
29580
|
workspaceId: args.authContext.workspaceId,
|
|
28161
|
-
topicId:
|
|
29581
|
+
topicId: readString34(body.topicId),
|
|
28162
29582
|
actorId: args.authContext.principalId ?? args.authContext.userId,
|
|
28163
29583
|
actorType: inferActorType({
|
|
28164
29584
|
authMode: args.authContext.authMode,
|
|
@@ -28228,31 +29648,31 @@ async function handleWebhookHealth(args) {
|
|
|
28228
29648
|
}
|
|
28229
29649
|
|
|
28230
29650
|
// ../../apps/gateway/src/routes/worktrees.ts
|
|
28231
|
-
function
|
|
29651
|
+
function asRecord33(value) {
|
|
28232
29652
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
28233
29653
|
}
|
|
28234
|
-
function
|
|
29654
|
+
function readString35(value) {
|
|
28235
29655
|
if (typeof value !== "string") {
|
|
28236
29656
|
return void 0;
|
|
28237
29657
|
}
|
|
28238
29658
|
const normalized = value.trim();
|
|
28239
29659
|
return normalized.length > 0 ? normalized : void 0;
|
|
28240
29660
|
}
|
|
28241
|
-
function
|
|
29661
|
+
function readNumber23(value) {
|
|
28242
29662
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
28243
29663
|
}
|
|
28244
29664
|
function readStringArray18(value) {
|
|
28245
29665
|
if (!Array.isArray(value)) {
|
|
28246
29666
|
return void 0;
|
|
28247
29667
|
}
|
|
28248
|
-
const normalized = value.map((entry) =>
|
|
29668
|
+
const normalized = value.map((entry) => readString35(entry)).filter((entry) => Boolean(entry));
|
|
28249
29669
|
return normalized.length > 0 ? normalized : void 0;
|
|
28250
29670
|
}
|
|
28251
29671
|
function readObjectArray(value) {
|
|
28252
29672
|
if (!Array.isArray(value)) {
|
|
28253
29673
|
return void 0;
|
|
28254
29674
|
}
|
|
28255
|
-
const normalized = value.map((entry) =>
|
|
29675
|
+
const normalized = value.map((entry) => asRecord33(entry)).filter((entry) => Object.keys(entry).length > 0);
|
|
28256
29676
|
return normalized.length > 0 ? normalized : void 0;
|
|
28257
29677
|
}
|
|
28258
29678
|
function readConfidenceImpact(value) {
|
|
@@ -28263,18 +29683,18 @@ function normalizeMergeOutcomes2(value) {
|
|
|
28263
29683
|
return [];
|
|
28264
29684
|
}
|
|
28265
29685
|
return value.map((entry) => {
|
|
28266
|
-
const finding =
|
|
29686
|
+
const finding = readString35(entry);
|
|
28267
29687
|
if (finding) {
|
|
28268
29688
|
return finding;
|
|
28269
29689
|
}
|
|
28270
|
-
const row =
|
|
29690
|
+
const row = asRecord33(entry);
|
|
28271
29691
|
if (!Object.keys(row).length) {
|
|
28272
29692
|
return null;
|
|
28273
29693
|
}
|
|
28274
29694
|
return {
|
|
28275
|
-
beliefId:
|
|
28276
|
-
confidence:
|
|
28277
|
-
rationale:
|
|
29695
|
+
beliefId: readString35(row.beliefId) ?? "",
|
|
29696
|
+
confidence: readNumber23(row.confidence) ?? Number.NaN,
|
|
29697
|
+
rationale: readString35(row.rationale) ?? ""
|
|
28278
29698
|
};
|
|
28279
29699
|
}).filter((entry) => entry !== null);
|
|
28280
29700
|
}
|
|
@@ -28293,22 +29713,22 @@ function handleWorktreesError(error, fallbackMessage, correlationId, policyTrace
|
|
|
28293
29713
|
}
|
|
28294
29714
|
async function handleWorktreeCreate(args) {
|
|
28295
29715
|
try {
|
|
28296
|
-
const body =
|
|
29716
|
+
const body = asRecord33(args.body);
|
|
28297
29717
|
const goCriteria = readStringArray18(body.goCriteria);
|
|
28298
29718
|
const noGoSignals = readStringArray18(body.noGoSignals);
|
|
28299
29719
|
const payload = await createWorktreeFromGatewayAuth(args.authContext, {
|
|
28300
|
-
title:
|
|
28301
|
-
topicId:
|
|
28302
|
-
topicHint:
|
|
28303
|
-
objective:
|
|
28304
|
-
hypothesis:
|
|
28305
|
-
rationale:
|
|
28306
|
-
worktreeType:
|
|
28307
|
-
startDate:
|
|
28308
|
-
endDate:
|
|
28309
|
-
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),
|
|
28310
29730
|
confidenceImpact: readConfidenceImpact(body.confidenceImpact),
|
|
28311
|
-
beliefFocus:
|
|
29731
|
+
beliefFocus: readString35(body.beliefFocus),
|
|
28312
29732
|
beliefIds: readStringArray18(body.targetBeliefIds) ?? readStringArray18(body.beliefIds) ?? readStringArray18(body.beliefs),
|
|
28313
29733
|
targetBeliefIds: readStringArray18(body.targetBeliefIds),
|
|
28314
29734
|
targetQuestionIds: readStringArray18(body.targetQuestionIds),
|
|
@@ -28319,23 +29739,23 @@ async function handleWorktreeCreate(args) {
|
|
|
28319
29739
|
noGoSignals: noGoSignals ?? []
|
|
28320
29740
|
} : void 0,
|
|
28321
29741
|
autoShape: typeof body.autoShape === "boolean" ? body.autoShape : void 0,
|
|
28322
|
-
domainPackId:
|
|
29742
|
+
domainPackId: readString35(body.domainPackId),
|
|
28323
29743
|
tags: readStringArray18(body.tags),
|
|
28324
29744
|
touchedPaths: readStringArray18(body.touchedPaths),
|
|
28325
|
-
sourceRef:
|
|
28326
|
-
sourceKind:
|
|
28327
|
-
campaign:
|
|
28328
|
-
lane:
|
|
28329
|
-
laneOrderInCampaign:
|
|
28330
|
-
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),
|
|
28331
29751
|
dependsOn: readStringArray18(body.dependsOn),
|
|
28332
29752
|
blocks: readStringArray18(body.blocks),
|
|
28333
|
-
gate:
|
|
29753
|
+
gate: readString35(body.gate),
|
|
28334
29754
|
proofArtifacts: Array.isArray(body.proofArtifacts) ? body.proofArtifacts : void 0,
|
|
28335
|
-
staffingHint:
|
|
28336
|
-
lastReconciledAt:
|
|
29755
|
+
staffingHint: readString35(body.staffingHint),
|
|
29756
|
+
lastReconciledAt: readNumber23(body.lastReconciledAt),
|
|
28337
29757
|
autoFixPolicy: body.autoFixPolicy && typeof body.autoFixPolicy === "object" && !Array.isArray(body.autoFixPolicy) ? body.autoFixPolicy : void 0,
|
|
28338
|
-
lensId:
|
|
29758
|
+
lensId: readString35(body.lensId)
|
|
28339
29759
|
});
|
|
28340
29760
|
return successResponse(payload, {
|
|
28341
29761
|
status: 201,
|
|
@@ -28354,12 +29774,12 @@ async function handleWorktreeCreate(args) {
|
|
|
28354
29774
|
async function handleWorktreeList(args) {
|
|
28355
29775
|
try {
|
|
28356
29776
|
const payload = await listWorktreesFromGatewayAuth(args.authContext, {
|
|
28357
|
-
topicId:
|
|
28358
|
-
status:
|
|
28359
|
-
groupBy:
|
|
28360
|
-
lane:
|
|
28361
|
-
campaign:
|
|
28362
|
-
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)
|
|
28363
29783
|
});
|
|
28364
29784
|
return successResponse(payload, {
|
|
28365
29785
|
correlationId: args.correlationId,
|
|
@@ -28377,11 +29797,11 @@ async function handleWorktreeList(args) {
|
|
|
28377
29797
|
async function handleWorktreeListAll(args) {
|
|
28378
29798
|
try {
|
|
28379
29799
|
const payload = await listAllWorktreesFromGatewayAuth(args.authContext, {
|
|
28380
|
-
status:
|
|
28381
|
-
lane:
|
|
28382
|
-
campaign:
|
|
28383
|
-
groupBy:
|
|
28384
|
-
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)
|
|
28385
29805
|
});
|
|
28386
29806
|
return successResponse(payload, {
|
|
28387
29807
|
correlationId: args.correlationId,
|
|
@@ -28399,9 +29819,9 @@ async function handleWorktreeListAll(args) {
|
|
|
28399
29819
|
async function handleWorktreeListCampaigns(args) {
|
|
28400
29820
|
try {
|
|
28401
29821
|
const payload = await listCampaignsFromGatewayAuth(args.authContext, {
|
|
28402
|
-
topicId:
|
|
28403
|
-
status:
|
|
28404
|
-
limit:
|
|
29822
|
+
topicId: readString35(args.query.topicId),
|
|
29823
|
+
status: readString35(args.query.status),
|
|
29824
|
+
limit: readNumber23(args.query.limit)
|
|
28405
29825
|
});
|
|
28406
29826
|
return successResponse(payload, {
|
|
28407
29827
|
correlationId: args.correlationId,
|
|
@@ -28436,27 +29856,27 @@ async function handleWorktreeActivate(args) {
|
|
|
28436
29856
|
}
|
|
28437
29857
|
async function handleWorktreeUpdate(args) {
|
|
28438
29858
|
try {
|
|
28439
|
-
const body =
|
|
29859
|
+
const body = asRecord33(args.body);
|
|
28440
29860
|
const payload = await updateWorktreeFromGatewayAuth(args.authContext, {
|
|
28441
29861
|
id: args.worktreeId,
|
|
28442
|
-
objective:
|
|
28443
|
-
hypothesis:
|
|
28444
|
-
rationale:
|
|
28445
|
-
campaign:
|
|
28446
|
-
lane:
|
|
28447
|
-
laneOrderInCampaign:
|
|
28448
|
-
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),
|
|
28449
29869
|
dependsOn: readStringArray18(body.dependsOn),
|
|
28450
29870
|
blocks: readStringArray18(body.blocks),
|
|
28451
|
-
gate:
|
|
28452
|
-
status:
|
|
28453
|
-
topicId:
|
|
29871
|
+
gate: readString35(body.gate),
|
|
29872
|
+
status: readString35(body.status),
|
|
29873
|
+
topicId: readString35(body.topicId),
|
|
28454
29874
|
additionalTopicIds: readStringArray18(body.additionalTopicIds),
|
|
28455
29875
|
proofArtifacts: Array.isArray(body.proofArtifacts) ? body.proofArtifacts : void 0,
|
|
28456
|
-
staffingHint:
|
|
28457
|
-
lastReconciledAt:
|
|
29876
|
+
staffingHint: readString35(body.staffingHint),
|
|
29877
|
+
lastReconciledAt: readNumber23(body.lastReconciledAt),
|
|
28458
29878
|
autoFixPolicy: body.autoFixPolicy && typeof body.autoFixPolicy === "object" ? body.autoFixPolicy : void 0,
|
|
28459
|
-
lensId:
|
|
29879
|
+
lensId: readString35(body.lensId)
|
|
28460
29880
|
});
|
|
28461
29881
|
return successResponse(payload, {
|
|
28462
29882
|
correlationId: args.correlationId,
|
|
@@ -28473,11 +29893,11 @@ async function handleWorktreeUpdate(args) {
|
|
|
28473
29893
|
}
|
|
28474
29894
|
async function handleWorktreeMerge(args) {
|
|
28475
29895
|
try {
|
|
28476
|
-
const body =
|
|
29896
|
+
const body = asRecord33(args.body);
|
|
28477
29897
|
const outcomes = normalizeMergeOutcomes2(body.outcomes);
|
|
28478
29898
|
const payload = await mergeWorktreeFromGatewayAuth(args.authContext, {
|
|
28479
29899
|
id: args.worktreeId,
|
|
28480
|
-
summary:
|
|
29900
|
+
summary: readString35(body.summary),
|
|
28481
29901
|
outcomes
|
|
28482
29902
|
});
|
|
28483
29903
|
return successResponse(payload, {
|
|
@@ -28495,7 +29915,7 @@ async function handleWorktreeMerge(args) {
|
|
|
28495
29915
|
}
|
|
28496
29916
|
async function handleWorktreeUpdateTargets(args) {
|
|
28497
29917
|
try {
|
|
28498
|
-
const body =
|
|
29918
|
+
const body = asRecord33(args.body);
|
|
28499
29919
|
const payload = await updateWorktreeTargetsFromGatewayAuth(
|
|
28500
29920
|
args.authContext,
|
|
28501
29921
|
{
|
|
@@ -28521,11 +29941,11 @@ async function handleWorktreeUpdateTargets(args) {
|
|
|
28521
29941
|
}
|
|
28522
29942
|
async function handleWorktreeComplete(args) {
|
|
28523
29943
|
try {
|
|
28524
|
-
const body =
|
|
29944
|
+
const body = asRecord33(args.body);
|
|
28525
29945
|
const payload = await completeWorktreeRecordFromGatewayAuth(
|
|
28526
29946
|
args.authContext,
|
|
28527
29947
|
{
|
|
28528
|
-
worktreeId:
|
|
29948
|
+
worktreeId: readString35(body.worktreeId) ?? "",
|
|
28529
29949
|
keyFindings: readStringArray18(body.keyFindings),
|
|
28530
29950
|
decisionsReached: readStringArray18(body.decisionsReached),
|
|
28531
29951
|
nextSteps: readStringArray18(body.nextSteps)
|
|
@@ -28546,9 +29966,9 @@ async function handleWorktreeComplete(args) {
|
|
|
28546
29966
|
}
|
|
28547
29967
|
async function handleWorktreeAdvancePhase(args) {
|
|
28548
29968
|
try {
|
|
28549
|
-
const body =
|
|
29969
|
+
const body = asRecord33(args.body);
|
|
28550
29970
|
const payload = await advanceWorktreePhaseFromGatewayAuth(args.authContext, {
|
|
28551
|
-
worktreeId:
|
|
29971
|
+
worktreeId: readString35(body.worktreeId) ?? ""
|
|
28552
29972
|
});
|
|
28553
29973
|
return successResponse(payload, {
|
|
28554
29974
|
correlationId: args.correlationId,
|
|
@@ -28565,10 +29985,10 @@ async function handleWorktreeAdvancePhase(args) {
|
|
|
28565
29985
|
}
|
|
28566
29986
|
async function handleWorktreeSetPhase(args) {
|
|
28567
29987
|
try {
|
|
28568
|
-
const body =
|
|
29988
|
+
const body = asRecord33(args.body);
|
|
28569
29989
|
const payload = await setWorktreePhaseFromGatewayAuth(args.authContext, {
|
|
28570
|
-
worktreeId:
|
|
28571
|
-
phase:
|
|
29990
|
+
worktreeId: readString35(body.worktreeId) ?? "",
|
|
29991
|
+
phase: readString35(body.phase) ?? ""
|
|
28572
29992
|
});
|
|
28573
29993
|
return successResponse(payload, {
|
|
28574
29994
|
correlationId: args.correlationId,
|
|
@@ -28585,12 +30005,12 @@ async function handleWorktreeSetPhase(args) {
|
|
|
28585
30005
|
}
|
|
28586
30006
|
async function handleWorktreePatchState(args) {
|
|
28587
30007
|
try {
|
|
28588
|
-
const body =
|
|
30008
|
+
const body = asRecord33(args.body);
|
|
28589
30009
|
const payload = await patchWorktreeStateFromGatewayAuth(
|
|
28590
30010
|
args.authContext,
|
|
28591
30011
|
{
|
|
28592
|
-
worktreeId:
|
|
28593
|
-
patch:
|
|
30012
|
+
worktreeId: readString35(body.worktreeId) ?? "",
|
|
30013
|
+
patch: asRecord33(body.patch)
|
|
28594
30014
|
}
|
|
28595
30015
|
);
|
|
28596
30016
|
return successResponse(payload, {
|
|
@@ -28608,7 +30028,7 @@ async function handleWorktreePatchState(args) {
|
|
|
28608
30028
|
}
|
|
28609
30029
|
async function handleWorktreeBulkCreate(args) {
|
|
28610
30030
|
try {
|
|
28611
|
-
const body =
|
|
30031
|
+
const body = asRecord33(args.body);
|
|
28612
30032
|
const payload = await bulkCreateWorktreesFromGatewayAuth(args.authContext, {
|
|
28613
30033
|
worktrees: Array.isArray(body.worktrees) ? body.worktrees : []
|
|
28614
30034
|
});
|
|
@@ -28627,6 +30047,6 @@ async function handleWorktreeBulkCreate(args) {
|
|
|
28627
30047
|
}
|
|
28628
30048
|
}
|
|
28629
30049
|
|
|
28630
|
-
export { 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, 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 };
|
|
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 };
|
|
28631
30051
|
//# sourceMappingURL=gateway.js.map
|
|
28632
30052
|
//# sourceMappingURL=gateway.js.map
|