@tailor-platform/sdk 1.25.4 → 1.27.0
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/CHANGELOG.md +28 -0
- package/dist/application-CBJFUKrU.mjs +4701 -0
- package/dist/application-CBJFUKrU.mjs.map +1 -0
- package/dist/application-WyZetOky.mjs +11 -0
- package/dist/cli/index.mjs +290 -32
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +350 -8
- package/dist/cli/lib.mjs +10 -8
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/client-C2_wgujH.mjs +6 -0
- package/dist/{application-91Th6tm6.mjs → client-bTbnbQbB.mjs} +24 -4795
- package/dist/client-bTbnbQbB.mjs.map +1 -0
- package/dist/configure/index.d.mts +5 -5
- package/dist/configure/index.mjs.map +1 -1
- package/dist/crash-report-Cot_9Esm.mjs +6 -0
- package/dist/crash-report-Ju8cQF-l.mjs +414 -0
- package/dist/crash-report-Ju8cQF-l.mjs.map +1 -0
- package/dist/{enum-constants-6uK0VI_s.mjs → enum-constants-D1nfn0qD.mjs} +1 -1
- package/dist/{enum-constants-6uK0VI_s.mjs.map → enum-constants-D1nfn0qD.mjs.map} +1 -1
- package/dist/{env-uBeVwE9B.d.mts → env-BuMbIknz.d.mts} +2 -2
- package/dist/{file-utils-2T9w20FP.mjs → file-utils-Bctuzn3x.mjs} +1 -1
- package/dist/{file-utils-2T9w20FP.mjs.map → file-utils-Bctuzn3x.mjs.map} +1 -1
- package/dist/{index-BD-K97-C.d.mts → index-B0Lrzywd.d.mts} +2 -2
- package/dist/{index-cZilKprY.d.mts → index-CbnLNm14.d.mts} +2 -2
- package/dist/{index-D1J5SfyK.d.mts → index-CyapgSFI.d.mts} +2 -2
- package/dist/{index-CT53egux.d.mts → index-D1AM_02Y.d.mts} +2 -2
- package/dist/{index-Bu12qy3m.d.mts → index-cD9sQLTh.d.mts} +15 -15
- package/dist/{interceptor-BPiIBTk_.mjs → interceptor-B0d_GrI5.mjs} +1 -1
- package/dist/{interceptor-BPiIBTk_.mjs.map → interceptor-B0d_GrI5.mjs.map} +1 -1
- package/dist/{kysely-type-cMNbsQ6k.mjs → kysely-type-B_IecdK9.mjs} +1 -1
- package/dist/{kysely-type-cMNbsQ6k.mjs.map → kysely-type-B_IecdK9.mjs.map} +1 -1
- package/dist/logger-CqezTedh.mjs +181 -0
- package/dist/logger-CqezTedh.mjs.map +1 -0
- package/dist/{package-json-CVUv8Y9T.mjs → package-json-D3x2nBPB.mjs} +1 -1
- package/dist/{package-json-CVUv8Y9T.mjs.map → package-json-D3x2nBPB.mjs.map} +1 -1
- package/dist/package-json-DHfTiUCS.mjs +4 -0
- package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
- package/dist/plugin/builtin/enum-constants/index.mjs +1 -1
- package/dist/plugin/builtin/file-utils/index.d.mts +1 -1
- package/dist/plugin/builtin/file-utils/index.mjs +1 -1
- package/dist/plugin/builtin/kysely-type/index.d.mts +1 -1
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
- package/dist/plugin/builtin/seed/index.d.mts +1 -1
- package/dist/plugin/builtin/seed/index.mjs +1 -1
- package/dist/plugin/index.d.mts +2 -2
- package/dist/{plugin-zY5wvV82.d.mts → plugin-D3a0-qe0.d.mts} +20 -4
- package/dist/{query-kb_4EQp4.mjs → query-CgGbAmUg.mjs} +460 -361
- package/dist/query-CgGbAmUg.mjs.map +1 -0
- package/dist/{seed-CCVRLibh.mjs → seed-CWkIDWMb.mjs} +1 -1
- package/dist/{seed-CCVRLibh.mjs.map → seed-CWkIDWMb.mjs.map} +1 -1
- package/dist/{telemetry-DDQZRqHK.mjs → telemetry-BevrwWwF.mjs} +1 -1
- package/dist/{telemetry-0w8OupuQ.mjs → telemetry-VvNfsyEE.mjs} +2 -2
- package/dist/{telemetry-0w8OupuQ.mjs.map → telemetry-VvNfsyEE.mjs.map} +1 -1
- package/dist/utils/test/index.d.mts +2 -2
- package/dist/{workflow.generated-v1LXRuB6.d.mts → workflow.generated-BsgIlrH-.d.mts} +2 -2
- package/docs/cli/crash-report.md +107 -0
- package/docs/cli/setup.md +82 -0
- package/docs/cli-reference.md +19 -0
- package/docs/services/auth.md +33 -0
- package/docs/services/resolver.md +32 -0
- package/package.json +4 -4
- package/dist/application-91Th6tm6.mjs.map +0 -1
- package/dist/application-DegTCDd8.mjs +0 -9
- package/dist/package-json-Bj76LPsV.mjs +0 -4
- package/dist/query-kb_4EQp4.mjs.map +0 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { t as db } from "./schema-BePzTFBV.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { i as symbols, n as logger, r as styles, t as CIPromptError } from "./logger-CqezTedh.mjs";
|
|
3
|
+
import { A as AuthInvokerSchema, B as GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus, C as FunctionExecution_Status, D as ExecutorTriggerType, E as ExecutorTargetType, F as AuthSCIMAttribute_Uniqueness, G as ApplicationSchemaUpdateAttemptStatus, H as Condition_Operator, I as AuthSCIMConfig_AuthorizationType, K as Subgraph_ServiceType, M as AuthOAuth2Client_GrantType, N as AuthSCIMAttribute_Mutability, O as AuthHookPoint, P as AuthSCIMAttribute_Type, R as TenantProviderConfig_TenantProviderType, S as IdPLang, T as ExecutorJobStatus, U as FilterSchema, V as ConditionSchema, W as PageDirection, _ as TailorDBGQLPermission_Permit, b as TailorDBType_PermitAction, d as userAgent, f as WorkspacePlatformUserRole, g as TailorDBGQLPermission_Operator, h as TailorDBGQLPermission_Action, j as AuthOAuth2Client_ClientType, k as AuthIDPConfig_AuthType, l as platformBaseUrl, m as WorkflowJobExecution_Status, n as fetchAll, p as WorkflowExecution_Status, r as fetchMachineUserToken, s as initOperatorClient, u as resolveStaticWebsiteUrls, v as TailorDBType_Permission_Operator, x as PipelineResolver_OperationType, y as TailorDBType_Permission_Permit, z as UserProfileProviderConfig_UserProfileProviderType } from "./client-bTbnbQbB.mjs";
|
|
4
|
+
import { t as readPackageJson } from "./package-json-D3x2nBPB.mjs";
|
|
5
|
+
import { S as writePlatformConfig, _ as hashFile, a as loadConfig, b as loadWorkspaceId, d as TailorDBTypeSchema, f as stringifyFunction, g as getDistDir, h as createBundleCache, l as OAuth2ClientSchema, m as loadFilesWithIgnores, n as generatePluginFilesIfNeeded, p as tailorUserMap, r as loadApplication, s as createExecutorService, t as defineApplication, x as readPlatformConfig, y as loadAccessToken } from "./application-CBJFUKrU.mjs";
|
|
6
|
+
import { r as withSpan } from "./telemetry-VvNfsyEE.mjs";
|
|
5
7
|
import { arg, createDefineCommand, defineCommand, runCommand } from "politty";
|
|
6
8
|
import { z } from "zod";
|
|
7
9
|
import * as fs$1 from "node:fs";
|
|
@@ -19,11 +21,11 @@ import { findUpSync } from "find-up-simple";
|
|
|
19
21
|
import ml from "multiline-ts";
|
|
20
22
|
import * as crypto from "node:crypto";
|
|
21
23
|
import { createHash } from "node:crypto";
|
|
22
|
-
import { pathToFileURL } from "node:url";
|
|
23
|
-
import * as inflection from "inflection";
|
|
24
24
|
import * as rolldown from "rolldown";
|
|
25
25
|
import * as fs from "node:fs/promises";
|
|
26
26
|
import { glob } from "node:fs/promises";
|
|
27
|
+
import { pathToFileURL } from "node:url";
|
|
28
|
+
import * as inflection from "inflection";
|
|
27
29
|
import { create, fromJson, toJson } from "@bufbuild/protobuf";
|
|
28
30
|
import { ExitPromptError } from "@inquirer/core";
|
|
29
31
|
import { confirm, input } from "@inquirer/prompts";
|
|
@@ -1073,6 +1075,273 @@ function protoSubgraph(subgraph) {
|
|
|
1073
1075
|
};
|
|
1074
1076
|
}
|
|
1075
1077
|
|
|
1078
|
+
//#endregion
|
|
1079
|
+
//#region src/cli/commands/apply/function-registry.ts
|
|
1080
|
+
const CHUNK_SIZE = 64 * 1024;
|
|
1081
|
+
/**
|
|
1082
|
+
* Compute SHA-256 content hash for a script string.
|
|
1083
|
+
* @param content - Script content to hash
|
|
1084
|
+
* @returns Hex-encoded SHA-256 hash
|
|
1085
|
+
*/
|
|
1086
|
+
function computeContentHash(content) {
|
|
1087
|
+
return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
|
|
1088
|
+
}
|
|
1089
|
+
function functionRegistryTrn(workspaceId, name) {
|
|
1090
|
+
return `trn:v1:workspace:${workspaceId}:function_registry:${name}`;
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Build a function registry name for a resolver.
|
|
1094
|
+
* @param namespace - Resolver namespace
|
|
1095
|
+
* @param resolverName - Resolver name
|
|
1096
|
+
* @returns Function registry name
|
|
1097
|
+
*/
|
|
1098
|
+
function resolverFunctionName(namespace, resolverName) {
|
|
1099
|
+
return `resolver--${namespace}--${resolverName}`;
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Build a function registry name for an executor.
|
|
1103
|
+
* @param executorName - Executor name
|
|
1104
|
+
* @returns Function registry name
|
|
1105
|
+
*/
|
|
1106
|
+
function executorFunctionName(executorName) {
|
|
1107
|
+
return `executor--${executorName}`;
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Build a function registry name for a workflow job.
|
|
1111
|
+
* @param jobName - Workflow job name
|
|
1112
|
+
* @returns Function registry name
|
|
1113
|
+
*/
|
|
1114
|
+
function workflowJobFunctionName(jobName) {
|
|
1115
|
+
return `workflow--${jobName}`;
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Build a function registry name for an auth hook.
|
|
1119
|
+
* @param authName - Auth namespace name
|
|
1120
|
+
* @param hookPoint - Hook point identifier (e.g. "before-login")
|
|
1121
|
+
* @returns Function registry name
|
|
1122
|
+
*/
|
|
1123
|
+
function authHookFunctionName(authName, hookPoint) {
|
|
1124
|
+
return `auth-hook--${authName}--${hookPoint}`;
|
|
1125
|
+
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Collect all function entries from bundled scripts for all services.
|
|
1128
|
+
* @param application - Application definition
|
|
1129
|
+
* @param workflowJobs - Collected workflow jobs from config
|
|
1130
|
+
* @returns Array of function entries to register
|
|
1131
|
+
*/
|
|
1132
|
+
function collectFunctionEntries(application, workflowJobs) {
|
|
1133
|
+
const entries = [];
|
|
1134
|
+
const distDir = getDistDir();
|
|
1135
|
+
for (const app of application.applications) for (const pipeline of app.resolverServices) for (const resolver of Object.values(pipeline.resolvers)) {
|
|
1136
|
+
const scriptPath = path.join(distDir, "resolvers", `${resolver.name}.js`);
|
|
1137
|
+
try {
|
|
1138
|
+
const content = fs$1.readFileSync(scriptPath, "utf-8");
|
|
1139
|
+
entries.push({
|
|
1140
|
+
name: resolverFunctionName(pipeline.namespace, resolver.name),
|
|
1141
|
+
scriptContent: content,
|
|
1142
|
+
contentHash: computeContentHash(content),
|
|
1143
|
+
description: `Resolver: ${pipeline.namespace}/${resolver.name}`
|
|
1144
|
+
});
|
|
1145
|
+
} catch {
|
|
1146
|
+
logger.warn(`Function file not found: ${scriptPath}`);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (application.executorService) {
|
|
1150
|
+
const executors = application.executorService.executors;
|
|
1151
|
+
for (const executor of Object.values(executors)) if (executor.operation.kind === "function" || executor.operation.kind === "jobFunction") {
|
|
1152
|
+
const scriptPath = path.join(distDir, "executors", `${executor.name}.js`);
|
|
1153
|
+
try {
|
|
1154
|
+
const content = fs$1.readFileSync(scriptPath, "utf-8");
|
|
1155
|
+
entries.push({
|
|
1156
|
+
name: executorFunctionName(executor.name),
|
|
1157
|
+
scriptContent: content,
|
|
1158
|
+
contentHash: computeContentHash(content),
|
|
1159
|
+
description: `Executor: ${executor.name}`
|
|
1160
|
+
});
|
|
1161
|
+
} catch {
|
|
1162
|
+
logger.warn(`Function file not found: ${scriptPath}`);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
for (const job of workflowJobs) {
|
|
1167
|
+
const scriptPath = path.join(distDir, "workflow-jobs", `${job.name}.js`);
|
|
1168
|
+
try {
|
|
1169
|
+
const content = fs$1.readFileSync(scriptPath, "utf-8");
|
|
1170
|
+
entries.push({
|
|
1171
|
+
name: workflowJobFunctionName(job.name),
|
|
1172
|
+
scriptContent: content,
|
|
1173
|
+
contentHash: computeContentHash(content),
|
|
1174
|
+
description: `Workflow job: ${job.name}`
|
|
1175
|
+
});
|
|
1176
|
+
} catch {
|
|
1177
|
+
logger.warn(`Function file not found: ${scriptPath}`);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
for (const app of application.applications) if (app.authService?.config.hooks?.beforeLogin) {
|
|
1181
|
+
const authName = app.authService.config.name;
|
|
1182
|
+
const funcName = authHookFunctionName(authName, "before-login");
|
|
1183
|
+
const scriptPath = path.join(distDir, "auth-hooks", `${funcName}.js`);
|
|
1184
|
+
try {
|
|
1185
|
+
const content = fs$1.readFileSync(scriptPath, "utf-8");
|
|
1186
|
+
entries.push({
|
|
1187
|
+
name: funcName,
|
|
1188
|
+
scriptContent: content,
|
|
1189
|
+
contentHash: computeContentHash(content),
|
|
1190
|
+
description: `Auth hook: ${authName}/before-login`
|
|
1191
|
+
});
|
|
1192
|
+
} catch {
|
|
1193
|
+
logger.warn(`Function file not found: ${scriptPath}`);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
return entries;
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* Plan function registry changes based on current and desired state.
|
|
1200
|
+
* @param client - Operator client instance
|
|
1201
|
+
* @param workspaceId - Workspace ID
|
|
1202
|
+
* @param appName - Application name
|
|
1203
|
+
* @param entries - Desired function entries
|
|
1204
|
+
* @returns Planned changes
|
|
1205
|
+
*/
|
|
1206
|
+
async function planFunctionRegistry(client, workspaceId, appName, entries) {
|
|
1207
|
+
const changeSet = createChangeSet("Function registry");
|
|
1208
|
+
const conflicts = [];
|
|
1209
|
+
const unmanaged = [];
|
|
1210
|
+
const resourceOwners = /* @__PURE__ */ new Set();
|
|
1211
|
+
const existingFunctions = await fetchAll(async (pageToken, maxPageSize) => {
|
|
1212
|
+
try {
|
|
1213
|
+
const response = await client.listFunctionRegistries({
|
|
1214
|
+
workspaceId,
|
|
1215
|
+
pageToken,
|
|
1216
|
+
pageSize: maxPageSize
|
|
1217
|
+
});
|
|
1218
|
+
return [response.functions.map((f) => ({
|
|
1219
|
+
name: f.name,
|
|
1220
|
+
contentHash: f.contentHash
|
|
1221
|
+
})), response.nextPageToken];
|
|
1222
|
+
} catch (error) {
|
|
1223
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) return [[], ""];
|
|
1224
|
+
throw error;
|
|
1225
|
+
}
|
|
1226
|
+
});
|
|
1227
|
+
const existingMap = {};
|
|
1228
|
+
await Promise.all(existingFunctions.map(async (func) => {
|
|
1229
|
+
const { metadata } = await client.getMetadata({ trn: functionRegistryTrn(workspaceId, func.name) });
|
|
1230
|
+
existingMap[func.name] = {
|
|
1231
|
+
resource: func,
|
|
1232
|
+
label: metadata?.labels[sdkNameLabelKey]
|
|
1233
|
+
};
|
|
1234
|
+
}));
|
|
1235
|
+
for (const entry of entries) {
|
|
1236
|
+
const existing = existingMap[entry.name];
|
|
1237
|
+
const metaRequest = await buildMetaRequest(functionRegistryTrn(workspaceId, entry.name), appName);
|
|
1238
|
+
if (existing) {
|
|
1239
|
+
if (!existing.label) unmanaged.push({
|
|
1240
|
+
resourceType: "Function registry",
|
|
1241
|
+
resourceName: entry.name
|
|
1242
|
+
});
|
|
1243
|
+
else if (existing.label !== appName) conflicts.push({
|
|
1244
|
+
resourceType: "Function registry",
|
|
1245
|
+
resourceName: entry.name,
|
|
1246
|
+
currentOwner: existing.label
|
|
1247
|
+
});
|
|
1248
|
+
changeSet.updates.push({
|
|
1249
|
+
name: entry.name,
|
|
1250
|
+
entry,
|
|
1251
|
+
metaRequest
|
|
1252
|
+
});
|
|
1253
|
+
delete existingMap[entry.name];
|
|
1254
|
+
} else changeSet.creates.push({
|
|
1255
|
+
name: entry.name,
|
|
1256
|
+
entry,
|
|
1257
|
+
metaRequest
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1260
|
+
for (const [name, existing] of Object.entries(existingMap)) {
|
|
1261
|
+
if (!existing) continue;
|
|
1262
|
+
const label = existing.label;
|
|
1263
|
+
if (label && label !== appName) resourceOwners.add(label);
|
|
1264
|
+
if (label === appName) changeSet.deletes.push({
|
|
1265
|
+
name,
|
|
1266
|
+
workspaceId
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1269
|
+
changeSet.print();
|
|
1270
|
+
return {
|
|
1271
|
+
changeSet,
|
|
1272
|
+
conflicts,
|
|
1273
|
+
unmanaged,
|
|
1274
|
+
resourceOwners
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Upload a function script to the function registry using client streaming.
|
|
1279
|
+
* @param client - Operator client instance
|
|
1280
|
+
* @param workspaceId - Workspace ID
|
|
1281
|
+
* @param entry - Function entry to upload
|
|
1282
|
+
* @param isCreate - Whether this is a create (true) or update (false)
|
|
1283
|
+
*/
|
|
1284
|
+
async function uploadFunctionScript(client, workspaceId, entry, isCreate) {
|
|
1285
|
+
const buffer = Buffer.from(entry.scriptContent, "utf-8");
|
|
1286
|
+
const info = {
|
|
1287
|
+
workspaceId,
|
|
1288
|
+
name: entry.name,
|
|
1289
|
+
description: entry.description,
|
|
1290
|
+
sizeBytes: BigInt(buffer.length),
|
|
1291
|
+
contentHash: entry.contentHash
|
|
1292
|
+
};
|
|
1293
|
+
if (isCreate) {
|
|
1294
|
+
/** @yields {MessageInitShape<typeof CreateFunctionRegistryRequestSchema>} Create request messages (info header followed by content chunks) */
|
|
1295
|
+
async function* createStream() {
|
|
1296
|
+
yield { payload: {
|
|
1297
|
+
case: "info",
|
|
1298
|
+
value: info
|
|
1299
|
+
} };
|
|
1300
|
+
for (let i = 0; i < buffer.length; i += CHUNK_SIZE) yield { payload: {
|
|
1301
|
+
case: "chunk",
|
|
1302
|
+
value: buffer.subarray(i, Math.min(i + CHUNK_SIZE, buffer.length))
|
|
1303
|
+
} };
|
|
1304
|
+
}
|
|
1305
|
+
await client.createFunctionRegistry(createStream());
|
|
1306
|
+
} else {
|
|
1307
|
+
/** @yields {MessageInitShape<typeof UpdateFunctionRegistryRequestSchema>} Update request messages (info header followed by content chunks) */
|
|
1308
|
+
async function* updateStream() {
|
|
1309
|
+
yield { payload: {
|
|
1310
|
+
case: "info",
|
|
1311
|
+
value: info
|
|
1312
|
+
} };
|
|
1313
|
+
for (let i = 0; i < buffer.length; i += CHUNK_SIZE) yield { payload: {
|
|
1314
|
+
case: "chunk",
|
|
1315
|
+
value: buffer.subarray(i, Math.min(i + CHUNK_SIZE, buffer.length))
|
|
1316
|
+
} };
|
|
1317
|
+
}
|
|
1318
|
+
await client.updateFunctionRegistry(updateStream());
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Apply function registry changes for the given phase.
|
|
1323
|
+
* @param client - Operator client instance
|
|
1324
|
+
* @param workspaceId - Workspace ID
|
|
1325
|
+
* @param result - Planned function registry changes
|
|
1326
|
+
* @param phase - Apply phase
|
|
1327
|
+
*/
|
|
1328
|
+
async function applyFunctionRegistry(client, workspaceId, result, phase = "create-update") {
|
|
1329
|
+
const { changeSet } = result;
|
|
1330
|
+
if (phase === "create-update") {
|
|
1331
|
+
for (const create of changeSet.creates) {
|
|
1332
|
+
await uploadFunctionScript(client, workspaceId, create.entry, true);
|
|
1333
|
+
await client.setMetadata(create.metaRequest);
|
|
1334
|
+
}
|
|
1335
|
+
for (const update of changeSet.updates) {
|
|
1336
|
+
await uploadFunctionScript(client, workspaceId, update.entry, false);
|
|
1337
|
+
await client.setMetadata(update.metaRequest);
|
|
1338
|
+
}
|
|
1339
|
+
} else if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteFunctionRegistry({
|
|
1340
|
+
workspaceId: del.workspaceId,
|
|
1341
|
+
name: del.name
|
|
1342
|
+
})));
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1076
1345
|
//#endregion
|
|
1077
1346
|
//#region src/cli/commands/apply/idp.ts
|
|
1078
1347
|
/**
|
|
@@ -1400,6 +1669,7 @@ async function applyAuth(client, result, phase = "create-update") {
|
|
|
1400
1669
|
await Promise.all([...changeSet.userProfileConfig.creates.map((create) => client.createUserProfileConfig(create.request)), ...changeSet.userProfileConfig.updates.map((update) => client.updateUserProfileConfig(update.request))]);
|
|
1401
1670
|
await Promise.all([...changeSet.tenantConfig.creates.map((create) => client.createTenantConfig(create.request)), ...changeSet.tenantConfig.updates.map((update) => client.updateTenantConfig(update.request))]);
|
|
1402
1671
|
await Promise.all([...changeSet.machineUser.creates.map((create) => client.createAuthMachineUser(create.request)), ...changeSet.machineUser.updates.map((update) => client.updateAuthMachineUser(update.request))]);
|
|
1672
|
+
await Promise.all([...changeSet.authHook.creates.map((create) => client.createAuthHook(create.request)), ...changeSet.authHook.updates.map((update) => client.updateAuthHook(update.request))]);
|
|
1403
1673
|
await Promise.all([...changeSet.oauth2Client.creates.map(async (create) => {
|
|
1404
1674
|
create.request.oauth2Client.redirectUris = await resolveStaticWebsiteUrls(client, create.request.workspaceId, create.request.oauth2Client.redirectUris, "OAuth2 redirect URIs");
|
|
1405
1675
|
return client.createAuthOAuth2Client(create.request);
|
|
@@ -1418,6 +1688,7 @@ async function applyAuth(client, result, phase = "create-update") {
|
|
|
1418
1688
|
await Promise.all(changeSet.scimResource.deletes.map((del) => client.deleteAuthSCIMResource(del.request)));
|
|
1419
1689
|
await Promise.all(changeSet.scim.deletes.map((del) => client.deleteAuthSCIMConfig(del.request)));
|
|
1420
1690
|
await Promise.all(changeSet.oauth2Client.deletes.map((del) => client.deleteAuthOAuth2Client(del.request)));
|
|
1691
|
+
await Promise.all(changeSet.authHook.deletes.map((del) => client.deleteAuthHook(del.request)));
|
|
1421
1692
|
await Promise.all(changeSet.machineUser.deletes.map((del) => client.deleteAuthMachineUser(del.request)));
|
|
1422
1693
|
await Promise.all(changeSet.tenantConfig.deletes.map((del) => client.deleteTenantConfig(del.request)));
|
|
1423
1694
|
await Promise.all(changeSet.userProfileConfig.deletes.map((del) => client.deleteUserProfileConfig(del.request)));
|
|
@@ -1438,11 +1709,12 @@ async function planAuth(context) {
|
|
|
1438
1709
|
}
|
|
1439
1710
|
const { changeSet: serviceChangeSet, conflicts, unmanaged, resourceOwners } = await planServices$2(client, workspaceId, application.name, auths);
|
|
1440
1711
|
const deletedServices = serviceChangeSet.deletes.map((del) => del.name);
|
|
1441
|
-
const [idpConfigChangeSet, userProfileConfigChangeSet, tenantConfigChangeSet, machineUserChangeSet, oauth2ClientChangeSet, scimChangeSet, scimResourceChangeSet] = await Promise.all([
|
|
1712
|
+
const [idpConfigChangeSet, userProfileConfigChangeSet, tenantConfigChangeSet, machineUserChangeSet, authHookChangeSet, oauth2ClientChangeSet, scimChangeSet, scimResourceChangeSet] = await Promise.all([
|
|
1442
1713
|
planIdPConfigs(client, workspaceId, auths, deletedServices),
|
|
1443
1714
|
planUserProfileConfigs(client, workspaceId, auths, deletedServices),
|
|
1444
1715
|
planTenantConfigs(client, workspaceId, auths, deletedServices),
|
|
1445
1716
|
planMachineUsers(client, workspaceId, auths, deletedServices),
|
|
1717
|
+
planAuthHooks(client, workspaceId, auths, deletedServices),
|
|
1446
1718
|
planOAuth2Clients(client, workspaceId, auths, deletedServices),
|
|
1447
1719
|
planSCIMConfigs(client, workspaceId, auths, deletedServices),
|
|
1448
1720
|
planSCIMResources(client, workspaceId, auths, deletedServices)
|
|
@@ -1452,6 +1724,7 @@ async function planAuth(context) {
|
|
|
1452
1724
|
userProfileConfigChangeSet.print();
|
|
1453
1725
|
tenantConfigChangeSet.print();
|
|
1454
1726
|
machineUserChangeSet.print();
|
|
1727
|
+
authHookChangeSet.print();
|
|
1455
1728
|
oauth2ClientChangeSet.print();
|
|
1456
1729
|
scimChangeSet.print();
|
|
1457
1730
|
scimResourceChangeSet.print();
|
|
@@ -1462,6 +1735,7 @@ async function planAuth(context) {
|
|
|
1462
1735
|
userProfileConfig: userProfileConfigChangeSet,
|
|
1463
1736
|
tenantConfig: tenantConfigChangeSet,
|
|
1464
1737
|
machineUser: machineUserChangeSet,
|
|
1738
|
+
authHook: authHookChangeSet,
|
|
1465
1739
|
oauth2Client: oauth2ClientChangeSet,
|
|
1466
1740
|
scim: scimChangeSet,
|
|
1467
1741
|
scimResource: scimResourceChangeSet
|
|
@@ -2261,6 +2535,72 @@ function protoSCIMAttribute(attr) {
|
|
|
2261
2535
|
subAttributes: attr.subAttributes?.map((attr) => protoSCIMAttribute(attr))
|
|
2262
2536
|
};
|
|
2263
2537
|
}
|
|
2538
|
+
async function planAuthHooks(client, workspaceId, auths, deletedServices) {
|
|
2539
|
+
const changeSet = createChangeSet("Auth hooks");
|
|
2540
|
+
for (const auth of auths) {
|
|
2541
|
+
const { parsedConfig: config } = auth;
|
|
2542
|
+
const beforeLogin = config.hooks?.beforeLogin;
|
|
2543
|
+
let existingHook;
|
|
2544
|
+
try {
|
|
2545
|
+
await client.getAuthHook({
|
|
2546
|
+
workspaceId,
|
|
2547
|
+
namespaceName: config.name,
|
|
2548
|
+
hookPoint: AuthHookPoint.BEFORE_LOGIN
|
|
2549
|
+
});
|
|
2550
|
+
existingHook = true;
|
|
2551
|
+
} catch (error) {
|
|
2552
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) existingHook = false;
|
|
2553
|
+
else throw error;
|
|
2554
|
+
}
|
|
2555
|
+
if (beforeLogin) {
|
|
2556
|
+
const hookRequest = {
|
|
2557
|
+
workspaceId,
|
|
2558
|
+
namespaceName: config.name,
|
|
2559
|
+
hook: {
|
|
2560
|
+
hookPoint: AuthHookPoint.BEFORE_LOGIN,
|
|
2561
|
+
scriptRef: authHookFunctionName(config.name, "before-login"),
|
|
2562
|
+
invoker: {
|
|
2563
|
+
namespace: config.name,
|
|
2564
|
+
machineUserName: beforeLogin.invoker
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
};
|
|
2568
|
+
if (existingHook) changeSet.updates.push({
|
|
2569
|
+
name: `${config.name}/before-login`,
|
|
2570
|
+
request: hookRequest
|
|
2571
|
+
});
|
|
2572
|
+
else changeSet.creates.push({
|
|
2573
|
+
name: `${config.name}/before-login`,
|
|
2574
|
+
request: hookRequest
|
|
2575
|
+
});
|
|
2576
|
+
} else if (existingHook) changeSet.deletes.push({
|
|
2577
|
+
name: `${config.name}/before-login`,
|
|
2578
|
+
request: {
|
|
2579
|
+
workspaceId,
|
|
2580
|
+
namespaceName: config.name,
|
|
2581
|
+
hookPoint: AuthHookPoint.BEFORE_LOGIN
|
|
2582
|
+
}
|
|
2583
|
+
});
|
|
2584
|
+
}
|
|
2585
|
+
for (const namespaceName of deletedServices) try {
|
|
2586
|
+
await client.getAuthHook({
|
|
2587
|
+
workspaceId,
|
|
2588
|
+
namespaceName,
|
|
2589
|
+
hookPoint: AuthHookPoint.BEFORE_LOGIN
|
|
2590
|
+
});
|
|
2591
|
+
changeSet.deletes.push({
|
|
2592
|
+
name: `${namespaceName}/before-login`,
|
|
2593
|
+
request: {
|
|
2594
|
+
workspaceId,
|
|
2595
|
+
namespaceName,
|
|
2596
|
+
hookPoint: AuthHookPoint.BEFORE_LOGIN
|
|
2597
|
+
}
|
|
2598
|
+
});
|
|
2599
|
+
} catch (error) {
|
|
2600
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) {} else throw error;
|
|
2601
|
+
}
|
|
2602
|
+
return changeSet;
|
|
2603
|
+
}
|
|
2264
2604
|
|
|
2265
2605
|
//#endregion
|
|
2266
2606
|
//#region src/cli/shared/prompt.ts
|
|
@@ -2325,358 +2665,116 @@ async function confirmOwnerConflict(conflicts, appName, yes) {
|
|
|
2325
2665
|
*/
|
|
2326
2666
|
async function confirmUnmanagedResources(resources, appName, yes) {
|
|
2327
2667
|
if (resources.length === 0) return;
|
|
2328
|
-
logger.warn("Existing resources not tracked by tailor-sdk were found:");
|
|
2329
|
-
logger.log(` ${styles.info("Resources")}:`);
|
|
2330
|
-
for (const r of resources) logger.log(` • ${styles.bold(r.resourceType)} ${styles.info(`"${r.resourceName}"`)}`);
|
|
2331
|
-
logger.newline();
|
|
2332
|
-
logger.log(" These resources may have been created by older SDK versions, Terraform, or CUE.");
|
|
2333
|
-
logger.log(" To continue, confirm that tailor-sdk should manage them.");
|
|
2334
|
-
logger.log(" If they are managed by another tool (e.g., Terraform), cancel and manage them there instead.");
|
|
2335
|
-
if (yes) {
|
|
2336
|
-
logger.success(`Adding to "${appName}" (--yes flag specified)...`, { mode: "plain" });
|
|
2337
|
-
return;
|
|
2338
|
-
}
|
|
2339
|
-
if (!await prompt.confirm({
|
|
2340
|
-
message: `Allow tailor-sdk to manage these resources for "${appName}"?`,
|
|
2341
|
-
default: false
|
|
2342
|
-
})) throw new Error(ml`
|
|
2343
|
-
Apply cancelled. Resources remain unmanaged.
|
|
2344
|
-
To override, run again and confirm, or use --yes flag.
|
|
2345
|
-
`);
|
|
2346
|
-
}
|
|
2347
|
-
/**
|
|
2348
|
-
* Confirm deletion of important resources.
|
|
2349
|
-
* @param resources - Resources scheduled for deletion
|
|
2350
|
-
* @param yes - Whether to auto-confirm without prompting
|
|
2351
|
-
* @returns Promise that resolves when confirmation completes
|
|
2352
|
-
*/
|
|
2353
|
-
async function confirmImportantResourceDeletion(resources, yes) {
|
|
2354
|
-
if (resources.length === 0) return;
|
|
2355
|
-
logger.warn("The following resources will be deleted:");
|
|
2356
|
-
logger.log(` ${styles.info("Resources")}:`);
|
|
2357
|
-
for (const r of resources) logger.log(` • ${styles.bold(r.resourceType)} ${styles.error(`"${r.resourceName}"`)}`);
|
|
2358
|
-
logger.newline();
|
|
2359
|
-
logger.log(styles.warning(" Deleting these resources will permanently remove all associated data."));
|
|
2360
|
-
if (yes) {
|
|
2361
|
-
logger.success("Deleting resources (--yes flag specified)...", { mode: "plain" });
|
|
2362
|
-
return;
|
|
2363
|
-
}
|
|
2364
|
-
if (!await prompt.confirm({
|
|
2365
|
-
message: "Are you sure you want to delete these resources?",
|
|
2366
|
-
default: false
|
|
2367
|
-
})) throw new Error(ml`
|
|
2368
|
-
Apply cancelled. Resources will not be deleted.
|
|
2369
|
-
To override, run again and confirm, or use --yes flag.
|
|
2370
|
-
`);
|
|
2371
|
-
}
|
|
2372
|
-
|
|
2373
|
-
//#endregion
|
|
2374
|
-
//#region src/cli/shared/runtime-args.ts
|
|
2375
|
-
/**
|
|
2376
|
-
* Runtime args transformation for all services.
|
|
2377
|
-
*
|
|
2378
|
-
* Each service transforms server-side args/context into SDK-friendly format:
|
|
2379
|
-
* - Executor: server-side expression evaluated by platform before calling function
|
|
2380
|
-
* - Resolver: operationHook expression evaluated by platform before calling function
|
|
2381
|
-
*
|
|
2382
|
-
* The user field mapping (server → SDK) shared across services is defined in
|
|
2383
|
-
* `@/parser/service/tailordb` as `tailorUserMap`.
|
|
2384
|
-
*/
|
|
2385
|
-
/**
|
|
2386
|
-
* Actor field transformation expression.
|
|
2387
|
-
*
|
|
2388
|
-
* Transforms the server's actor object to match the SDK's TailorActor type:
|
|
2389
|
-
* server `attributeMap` → SDK `attributes`
|
|
2390
|
-
* server `attributes` → SDK `attributeList`
|
|
2391
|
-
* other fields → passed through
|
|
2392
|
-
* null/undefined actor → null
|
|
2393
|
-
*/
|
|
2394
|
-
const ACTOR_TRANSFORM_EXPR = "actor: args.actor ? (({ attributeMap, attributes: attrList, ...rest }) => ({ ...rest, attributes: attributeMap, attributeList: attrList }))(args.actor) : null";
|
|
2395
|
-
/**
|
|
2396
|
-
* Build the JavaScript expression that transforms server-format executor event
|
|
2397
|
-
* args into SDK-format args at runtime.
|
|
2398
|
-
*
|
|
2399
|
-
* The Tailor Platform server delivers event args with server-side field names.
|
|
2400
|
-
* The SDK exposes different field names to user code. This function produces a
|
|
2401
|
-
* JavaScript expression string that performs the mapping when evaluated
|
|
2402
|
-
* server-side.
|
|
2403
|
-
* @param triggerKind - The trigger kind discriminant from the parsed executor
|
|
2404
|
-
* @param env - Application env record to embed in the expression
|
|
2405
|
-
* @returns A JavaScript expression string, e.g. `({ ...args, ... })`
|
|
2406
|
-
*/
|
|
2407
|
-
function buildExecutorArgsExpr(triggerKind, env) {
|
|
2408
|
-
const envExpr = `env: ${JSON.stringify(env)}`;
|
|
2409
|
-
switch (triggerKind) {
|
|
2410
|
-
case "schedule":
|
|
2411
|
-
case "recordCreated":
|
|
2412
|
-
case "recordUpdated":
|
|
2413
|
-
case "recordDeleted":
|
|
2414
|
-
case "idpUserCreated":
|
|
2415
|
-
case "idpUserUpdated":
|
|
2416
|
-
case "idpUserDeleted":
|
|
2417
|
-
case "authAccessTokenIssued":
|
|
2418
|
-
case "authAccessTokenRefreshed":
|
|
2419
|
-
case "authAccessTokenRevoked": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, ${envExpr} })`;
|
|
2420
|
-
case "resolverExecuted": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, success: !!args.succeeded, result: args.succeeded?.result.resolver, error: args.failed?.error, ${envExpr} })`;
|
|
2421
|
-
case "incomingWebhook": return `({ ...args, appNamespace: args.namespaceName, rawBody: args.raw_body, ${envExpr} })`;
|
|
2422
|
-
default: throw new Error(`Unknown trigger kind for args expression: ${triggerKind}`);
|
|
2423
|
-
}
|
|
2424
|
-
}
|
|
2425
|
-
/**
|
|
2426
|
-
* Build the operationHook expression for resolver pipelines.
|
|
2427
|
-
*
|
|
2428
|
-
* Transforms server context to SDK resolver context:
|
|
2429
|
-
* context.args → input
|
|
2430
|
-
* context.pipeline → spread into result
|
|
2431
|
-
* user (global var) → TailorUser (via tailorUserMap: workspace_id→workspaceId, attribute_map→attributes, attributes→attributeList)
|
|
2432
|
-
* env → injected as JSON
|
|
2433
|
-
* @param env - Application env record to embed in the expression
|
|
2434
|
-
* @returns A JavaScript expression string for the operationHook
|
|
2435
|
-
*/
|
|
2436
|
-
function buildResolverOperationHookExpr(env) {
|
|
2437
|
-
return `({ ...context.pipeline, input: context.args, user: ${tailorUserMap}, env: ${JSON.stringify(env)} });`;
|
|
2438
|
-
}
|
|
2439
|
-
|
|
2440
|
-
//#endregion
|
|
2441
|
-
//#region src/cli/commands/apply/function-registry.ts
|
|
2442
|
-
const CHUNK_SIZE = 64 * 1024;
|
|
2443
|
-
/**
|
|
2444
|
-
* Compute SHA-256 content hash for a script string.
|
|
2445
|
-
* @param content - Script content to hash
|
|
2446
|
-
* @returns Hex-encoded SHA-256 hash
|
|
2447
|
-
*/
|
|
2448
|
-
function computeContentHash(content) {
|
|
2449
|
-
return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
|
|
2450
|
-
}
|
|
2451
|
-
function functionRegistryTrn(workspaceId, name) {
|
|
2452
|
-
return `trn:v1:workspace:${workspaceId}:function_registry:${name}`;
|
|
2453
|
-
}
|
|
2454
|
-
/**
|
|
2455
|
-
* Build a function registry name for a resolver.
|
|
2456
|
-
* @param namespace - Resolver namespace
|
|
2457
|
-
* @param resolverName - Resolver name
|
|
2458
|
-
* @returns Function registry name
|
|
2459
|
-
*/
|
|
2460
|
-
function resolverFunctionName(namespace, resolverName) {
|
|
2461
|
-
return `resolver--${namespace}--${resolverName}`;
|
|
2462
|
-
}
|
|
2463
|
-
/**
|
|
2464
|
-
* Build a function registry name for an executor.
|
|
2465
|
-
* @param executorName - Executor name
|
|
2466
|
-
* @returns Function registry name
|
|
2467
|
-
*/
|
|
2468
|
-
function executorFunctionName(executorName) {
|
|
2469
|
-
return `executor--${executorName}`;
|
|
2470
|
-
}
|
|
2471
|
-
/**
|
|
2472
|
-
* Build a function registry name for a workflow job.
|
|
2473
|
-
* @param jobName - Workflow job name
|
|
2474
|
-
* @returns Function registry name
|
|
2475
|
-
*/
|
|
2476
|
-
function workflowJobFunctionName(jobName) {
|
|
2477
|
-
return `workflow--${jobName}`;
|
|
2478
|
-
}
|
|
2479
|
-
/**
|
|
2480
|
-
* Collect all function entries from bundled scripts for all services.
|
|
2481
|
-
* @param application - Application definition
|
|
2482
|
-
* @param workflowJobs - Collected workflow jobs from config
|
|
2483
|
-
* @returns Array of function entries to register
|
|
2484
|
-
*/
|
|
2485
|
-
function collectFunctionEntries(application, workflowJobs) {
|
|
2486
|
-
const entries = [];
|
|
2487
|
-
const distDir = getDistDir();
|
|
2488
|
-
for (const app of application.applications) for (const pipeline of app.resolverServices) for (const resolver of Object.values(pipeline.resolvers)) {
|
|
2489
|
-
const scriptPath = path.join(distDir, "resolvers", `${resolver.name}.js`);
|
|
2490
|
-
try {
|
|
2491
|
-
const content = fs$1.readFileSync(scriptPath, "utf-8");
|
|
2492
|
-
entries.push({
|
|
2493
|
-
name: resolverFunctionName(pipeline.namespace, resolver.name),
|
|
2494
|
-
scriptContent: content,
|
|
2495
|
-
contentHash: computeContentHash(content),
|
|
2496
|
-
description: `Resolver: ${pipeline.namespace}/${resolver.name}`
|
|
2497
|
-
});
|
|
2498
|
-
} catch {
|
|
2499
|
-
logger.warn(`Function file not found: ${scriptPath}`);
|
|
2500
|
-
}
|
|
2501
|
-
}
|
|
2502
|
-
if (application.executorService) {
|
|
2503
|
-
const executors = application.executorService.executors;
|
|
2504
|
-
for (const executor of Object.values(executors)) if (executor.operation.kind === "function" || executor.operation.kind === "jobFunction") {
|
|
2505
|
-
const scriptPath = path.join(distDir, "executors", `${executor.name}.js`);
|
|
2506
|
-
try {
|
|
2507
|
-
const content = fs$1.readFileSync(scriptPath, "utf-8");
|
|
2508
|
-
entries.push({
|
|
2509
|
-
name: executorFunctionName(executor.name),
|
|
2510
|
-
scriptContent: content,
|
|
2511
|
-
contentHash: computeContentHash(content),
|
|
2512
|
-
description: `Executor: ${executor.name}`
|
|
2513
|
-
});
|
|
2514
|
-
} catch {
|
|
2515
|
-
logger.warn(`Function file not found: ${scriptPath}`);
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
}
|
|
2519
|
-
for (const job of workflowJobs) {
|
|
2520
|
-
const scriptPath = path.join(distDir, "workflow-jobs", `${job.name}.js`);
|
|
2521
|
-
try {
|
|
2522
|
-
const content = fs$1.readFileSync(scriptPath, "utf-8");
|
|
2523
|
-
entries.push({
|
|
2524
|
-
name: workflowJobFunctionName(job.name),
|
|
2525
|
-
scriptContent: content,
|
|
2526
|
-
contentHash: computeContentHash(content),
|
|
2527
|
-
description: `Workflow job: ${job.name}`
|
|
2528
|
-
});
|
|
2529
|
-
} catch {
|
|
2530
|
-
logger.warn(`Function file not found: ${scriptPath}`);
|
|
2531
|
-
}
|
|
2668
|
+
logger.warn("Existing resources not tracked by tailor-sdk were found:");
|
|
2669
|
+
logger.log(` ${styles.info("Resources")}:`);
|
|
2670
|
+
for (const r of resources) logger.log(` • ${styles.bold(r.resourceType)} ${styles.info(`"${r.resourceName}"`)}`);
|
|
2671
|
+
logger.newline();
|
|
2672
|
+
logger.log(" These resources may have been created by older SDK versions, Terraform, or CUE.");
|
|
2673
|
+
logger.log(" To continue, confirm that tailor-sdk should manage them.");
|
|
2674
|
+
logger.log(" If they are managed by another tool (e.g., Terraform), cancel and manage them there instead.");
|
|
2675
|
+
if (yes) {
|
|
2676
|
+
logger.success(`Adding to "${appName}" (--yes flag specified)...`, { mode: "plain" });
|
|
2677
|
+
return;
|
|
2532
2678
|
}
|
|
2533
|
-
|
|
2679
|
+
if (!await prompt.confirm({
|
|
2680
|
+
message: `Allow tailor-sdk to manage these resources for "${appName}"?`,
|
|
2681
|
+
default: false
|
|
2682
|
+
})) throw new Error(ml`
|
|
2683
|
+
Apply cancelled. Resources remain unmanaged.
|
|
2684
|
+
To override, run again and confirm, or use --yes flag.
|
|
2685
|
+
`);
|
|
2534
2686
|
}
|
|
2535
2687
|
/**
|
|
2536
|
-
*
|
|
2537
|
-
* @param
|
|
2538
|
-
* @param
|
|
2539
|
-
* @
|
|
2540
|
-
* @param entries - Desired function entries
|
|
2541
|
-
* @returns Planned changes
|
|
2688
|
+
* Confirm deletion of important resources.
|
|
2689
|
+
* @param resources - Resources scheduled for deletion
|
|
2690
|
+
* @param yes - Whether to auto-confirm without prompting
|
|
2691
|
+
* @returns Promise that resolves when confirmation completes
|
|
2542
2692
|
*/
|
|
2543
|
-
async function
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
const
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
pageSize: maxPageSize
|
|
2554
|
-
});
|
|
2555
|
-
return [response.functions.map((f) => ({
|
|
2556
|
-
name: f.name,
|
|
2557
|
-
contentHash: f.contentHash
|
|
2558
|
-
})), response.nextPageToken];
|
|
2559
|
-
} catch (error) {
|
|
2560
|
-
if (error instanceof ConnectError && error.code === Code.NotFound) return [[], ""];
|
|
2561
|
-
throw error;
|
|
2562
|
-
}
|
|
2563
|
-
});
|
|
2564
|
-
const existingMap = {};
|
|
2565
|
-
await Promise.all(existingFunctions.map(async (func) => {
|
|
2566
|
-
const { metadata } = await client.getMetadata({ trn: functionRegistryTrn(workspaceId, func.name) });
|
|
2567
|
-
existingMap[func.name] = {
|
|
2568
|
-
resource: func,
|
|
2569
|
-
label: metadata?.labels[sdkNameLabelKey]
|
|
2570
|
-
};
|
|
2571
|
-
}));
|
|
2572
|
-
for (const entry of entries) {
|
|
2573
|
-
const existing = existingMap[entry.name];
|
|
2574
|
-
const metaRequest = await buildMetaRequest(functionRegistryTrn(workspaceId, entry.name), appName);
|
|
2575
|
-
if (existing) {
|
|
2576
|
-
if (!existing.label) unmanaged.push({
|
|
2577
|
-
resourceType: "Function registry",
|
|
2578
|
-
resourceName: entry.name
|
|
2579
|
-
});
|
|
2580
|
-
else if (existing.label !== appName) conflicts.push({
|
|
2581
|
-
resourceType: "Function registry",
|
|
2582
|
-
resourceName: entry.name,
|
|
2583
|
-
currentOwner: existing.label
|
|
2584
|
-
});
|
|
2585
|
-
changeSet.updates.push({
|
|
2586
|
-
name: entry.name,
|
|
2587
|
-
entry,
|
|
2588
|
-
metaRequest
|
|
2589
|
-
});
|
|
2590
|
-
delete existingMap[entry.name];
|
|
2591
|
-
} else changeSet.creates.push({
|
|
2592
|
-
name: entry.name,
|
|
2593
|
-
entry,
|
|
2594
|
-
metaRequest
|
|
2595
|
-
});
|
|
2596
|
-
}
|
|
2597
|
-
for (const [name, existing] of Object.entries(existingMap)) {
|
|
2598
|
-
if (!existing) continue;
|
|
2599
|
-
const label = existing.label;
|
|
2600
|
-
if (label && label !== appName) resourceOwners.add(label);
|
|
2601
|
-
if (label === appName) changeSet.deletes.push({
|
|
2602
|
-
name,
|
|
2603
|
-
workspaceId
|
|
2604
|
-
});
|
|
2693
|
+
async function confirmImportantResourceDeletion(resources, yes) {
|
|
2694
|
+
if (resources.length === 0) return;
|
|
2695
|
+
logger.warn("The following resources will be deleted:");
|
|
2696
|
+
logger.log(` ${styles.info("Resources")}:`);
|
|
2697
|
+
for (const r of resources) logger.log(` • ${styles.bold(r.resourceType)} ${styles.error(`"${r.resourceName}"`)}`);
|
|
2698
|
+
logger.newline();
|
|
2699
|
+
logger.log(styles.warning(" Deleting these resources will permanently remove all associated data."));
|
|
2700
|
+
if (yes) {
|
|
2701
|
+
logger.success("Deleting resources (--yes flag specified)...", { mode: "plain" });
|
|
2702
|
+
return;
|
|
2605
2703
|
}
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2704
|
+
if (!await prompt.confirm({
|
|
2705
|
+
message: "Are you sure you want to delete these resources?",
|
|
2706
|
+
default: false
|
|
2707
|
+
})) throw new Error(ml`
|
|
2708
|
+
Apply cancelled. Resources will not be deleted.
|
|
2709
|
+
To override, run again and confirm, or use --yes flag.
|
|
2710
|
+
`);
|
|
2613
2711
|
}
|
|
2712
|
+
|
|
2713
|
+
//#endregion
|
|
2714
|
+
//#region src/cli/shared/runtime-args.ts
|
|
2614
2715
|
/**
|
|
2615
|
-
*
|
|
2616
|
-
*
|
|
2617
|
-
*
|
|
2618
|
-
*
|
|
2619
|
-
*
|
|
2716
|
+
* Runtime args transformation for all services.
|
|
2717
|
+
*
|
|
2718
|
+
* Each service transforms server-side args/context into SDK-friendly format:
|
|
2719
|
+
* - Executor: server-side expression evaluated by platform before calling function
|
|
2720
|
+
* - Resolver: operationHook expression evaluated by platform before calling function
|
|
2721
|
+
*
|
|
2722
|
+
* The user field mapping (server → SDK) shared across services is defined in
|
|
2723
|
+
* `@/parser/service/tailordb` as `tailorUserMap`.
|
|
2620
2724
|
*/
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2725
|
+
/**
|
|
2726
|
+
* Actor field transformation expression.
|
|
2727
|
+
*
|
|
2728
|
+
* Transforms the server's actor object to match the SDK's TailorActor type:
|
|
2729
|
+
* server `attributeMap` → SDK `attributes`
|
|
2730
|
+
* server `attributes` → SDK `attributeList`
|
|
2731
|
+
* other fields → passed through
|
|
2732
|
+
* null/undefined actor → null
|
|
2733
|
+
*/
|
|
2734
|
+
const ACTOR_TRANSFORM_EXPR = "actor: args.actor ? (({ attributeMap, attributes: attrList, ...rest }) => ({ ...rest, attributes: attributeMap, attributeList: attrList }))(args.actor) : null";
|
|
2735
|
+
/**
|
|
2736
|
+
* Build the JavaScript expression that transforms server-format executor event
|
|
2737
|
+
* args into SDK-format args at runtime.
|
|
2738
|
+
*
|
|
2739
|
+
* The Tailor Platform server delivers event args with server-side field names.
|
|
2740
|
+
* The SDK exposes different field names to user code. This function produces a
|
|
2741
|
+
* JavaScript expression string that performs the mapping when evaluated
|
|
2742
|
+
* server-side.
|
|
2743
|
+
* @param triggerKind - The trigger kind discriminant from the parsed executor
|
|
2744
|
+
* @param env - Application env record to embed in the expression
|
|
2745
|
+
* @returns A JavaScript expression string, e.g. `({ ...args, ... })`
|
|
2746
|
+
*/
|
|
2747
|
+
function buildExecutorArgsExpr(triggerKind, env) {
|
|
2748
|
+
const envExpr = `env: ${JSON.stringify(env)}`;
|
|
2749
|
+
switch (triggerKind) {
|
|
2750
|
+
case "schedule":
|
|
2751
|
+
case "recordCreated":
|
|
2752
|
+
case "recordUpdated":
|
|
2753
|
+
case "recordDeleted":
|
|
2754
|
+
case "idpUserCreated":
|
|
2755
|
+
case "idpUserUpdated":
|
|
2756
|
+
case "idpUserDeleted":
|
|
2757
|
+
case "authAccessTokenIssued":
|
|
2758
|
+
case "authAccessTokenRefreshed":
|
|
2759
|
+
case "authAccessTokenRevoked": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, ${envExpr} })`;
|
|
2760
|
+
case "resolverExecuted": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, success: !!args.succeeded, result: args.succeeded?.result.resolver, error: args.failed?.error, ${envExpr} })`;
|
|
2761
|
+
case "incomingWebhook": return `({ ...args, appNamespace: args.namespaceName, rawBody: args.raw_body, ${envExpr} })`;
|
|
2762
|
+
default: throw new Error(`Unknown trigger kind for args expression: ${triggerKind}`);
|
|
2656
2763
|
}
|
|
2657
2764
|
}
|
|
2658
2765
|
/**
|
|
2659
|
-
*
|
|
2660
|
-
*
|
|
2661
|
-
*
|
|
2662
|
-
*
|
|
2663
|
-
*
|
|
2766
|
+
* Build the operationHook expression for resolver pipelines.
|
|
2767
|
+
*
|
|
2768
|
+
* Transforms server context to SDK resolver context:
|
|
2769
|
+
* context.args → input
|
|
2770
|
+
* context.pipeline → spread into result
|
|
2771
|
+
* user (global var) → TailorUser (via tailorUserMap: workspace_id→workspaceId, attribute_map→attributes, attributes→attributeList)
|
|
2772
|
+
* env → injected as JSON
|
|
2773
|
+
* @param env - Application env record to embed in the expression
|
|
2774
|
+
* @returns A JavaScript expression string for the operationHook
|
|
2664
2775
|
*/
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
if (phase === "create-update") {
|
|
2668
|
-
for (const create of changeSet.creates) {
|
|
2669
|
-
await uploadFunctionScript(client, workspaceId, create.entry, true);
|
|
2670
|
-
await client.setMetadata(create.metaRequest);
|
|
2671
|
-
}
|
|
2672
|
-
for (const update of changeSet.updates) {
|
|
2673
|
-
await uploadFunctionScript(client, workspaceId, update.entry, false);
|
|
2674
|
-
await client.setMetadata(update.metaRequest);
|
|
2675
|
-
}
|
|
2676
|
-
} else if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteFunctionRegistry({
|
|
2677
|
-
workspaceId: del.workspaceId,
|
|
2678
|
-
name: del.name
|
|
2679
|
-
})));
|
|
2776
|
+
function buildResolverOperationHookExpr(env) {
|
|
2777
|
+
return `({ ...context.pipeline, input: context.args, user: ${tailorUserMap}, env: ${JSON.stringify(env)} });`;
|
|
2680
2778
|
}
|
|
2681
2779
|
|
|
2682
2780
|
//#endregion
|
|
@@ -3181,7 +3279,8 @@ function processResolver(namespace, resolver, executorUsedResolvers, env) {
|
|
|
3181
3279
|
operationType: PipelineResolver_OperationType.FUNCTION,
|
|
3182
3280
|
operationSourceRef: resolverFunctionName(namespace, resolver.name),
|
|
3183
3281
|
operationHook: { expr: buildResolverOperationHookExpr(env) },
|
|
3184
|
-
postScript: `args.body
|
|
3282
|
+
postScript: `args.body`,
|
|
3283
|
+
invoker: resolver.authInvoker
|
|
3185
3284
|
}];
|
|
3186
3285
|
const typeBaseName = inflection.camelize(resolver.name);
|
|
3187
3286
|
const inputs = resolver.input ? protoFields(resolver.input, `${typeBaseName}Input`, true) : [];
|
|
@@ -9685,6 +9784,17 @@ const removeCommand$1 = defineAppCommand({
|
|
|
9685
9784
|
}
|
|
9686
9785
|
});
|
|
9687
9786
|
|
|
9787
|
+
//#endregion
|
|
9788
|
+
//#region src/cli/shared/beta.ts
|
|
9789
|
+
/**
|
|
9790
|
+
* Warn that a feature is in beta.
|
|
9791
|
+
* @param {string} featureName - Name of the beta feature (e.g., "tailordb erd", "tailordb migration")
|
|
9792
|
+
*/
|
|
9793
|
+
function logBetaWarning(featureName) {
|
|
9794
|
+
logger.warn(`The '${featureName}' command is a beta feature and may introduce breaking changes in future releases.`);
|
|
9795
|
+
logger.newline();
|
|
9796
|
+
}
|
|
9797
|
+
|
|
9688
9798
|
//#endregion
|
|
9689
9799
|
//#region src/cli/commands/show.ts
|
|
9690
9800
|
function applicationInfo(app) {
|
|
@@ -9742,17 +9852,6 @@ const showCommand = defineAppCommand({
|
|
|
9742
9852
|
}
|
|
9743
9853
|
});
|
|
9744
9854
|
|
|
9745
|
-
//#endregion
|
|
9746
|
-
//#region src/cli/shared/beta.ts
|
|
9747
|
-
/**
|
|
9748
|
-
* Warn that a feature is in beta.
|
|
9749
|
-
* @param {string} featureName - Name of the beta feature (e.g., "tailordb erd", "tailordb migration")
|
|
9750
|
-
*/
|
|
9751
|
-
function logBetaWarning(featureName) {
|
|
9752
|
-
logger.warn(`The '${featureName}' command is a beta feature and may introduce breaking changes in future releases.`);
|
|
9753
|
-
logger.newline();
|
|
9754
|
-
}
|
|
9755
|
-
|
|
9756
9855
|
//#endregion
|
|
9757
9856
|
//#region src/cli/shared/editor.ts
|
|
9758
9857
|
const DEFAULT_EDITOR = "editor";
|
|
@@ -10326,7 +10425,7 @@ async function generate(options) {
|
|
|
10326
10425
|
if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
|
|
10327
10426
|
let pluginManager;
|
|
10328
10427
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
10329
|
-
const { defineApplication } = await import("./application-
|
|
10428
|
+
const { defineApplication } = await import("./application-WyZetOky.mjs");
|
|
10330
10429
|
const application = defineApplication({
|
|
10331
10430
|
config,
|
|
10332
10431
|
pluginManager
|
|
@@ -12504,5 +12603,5 @@ function printGqlResult(result, options = {}) {
|
|
|
12504
12603
|
}
|
|
12505
12604
|
|
|
12506
12605
|
//#endregion
|
|
12507
|
-
export { listExecutors as $, truncate as A, getLatestMigrationNumber as At, listOAuth2Clients as B, hasChanges as Bt, listCommand$2 as C, INITIAL_SCHEMA_NUMBER as Ct, resumeWorkflow as D, compareSnapshots as Dt, resumeCommand as E, compareLocalTypesWithSnapshot as Et,
|
|
12508
|
-
//# sourceMappingURL=query-
|
|
12606
|
+
export { listExecutors as $, truncate as A, getLatestMigrationNumber as At, listOAuth2Clients as B, hasChanges as Bt, listCommand$2 as C, INITIAL_SCHEMA_NUMBER as Ct, resumeWorkflow as D, compareSnapshots as Dt, resumeCommand as E, compareLocalTypesWithSnapshot as Et, showCommand as F, isValidMigrationNumber as Ft, listCommand$5 as G, apiCall as Gt, getOAuth2Client as H, prompt as Ht, logBetaWarning as I, loadDiff as It, listWebhookExecutors as J, commonArgs as Jt, listMachineUsers as K, apiCommand as Kt, remove as L, reconstructSnapshotFromMigrations as Lt, generate as M, getMigrationFilePath as Mt, generateCommand as N, getMigrationFiles as Nt, listCommand$3 as O, createSnapshotFromLocalTypes as Ot, show as P, getNextMigrationNumber as Pt, listCommand$6 as Q, workspaceArgs as Qt, removeCommand$1 as R, formatDiffSummary as Rt, listApps as S, DIFF_FILE_NAME as St, healthCommand as T, SCHEMA_FILE_NAME as Tt, getMachineUserToken as U, trnPrefix as Ut, getCommand$1 as V, getNamespacesWithMigrations as Vt, tokenCommand as W, generateUserTypes as Wt, triggerCommand as X, deploymentArgs as Xt, webhookCommand as Y, confirmationArgs as Yt, triggerExecutor as Z, isVerbose as Zt, getWorkspace as _, waitForExecution$1 as _t, updateUser as a, startWorkflow as at, createCommand as b, bundleMigrationScript as bt, listCommand as c, executionsCommand as ct, inviteUser as d, functionExecutionStatusToString as dt, getExecutorJob as et, restoreCommand as f, formatKeyValueTable as ft, getCommand as g, executeScript as gt, listWorkspaces as h, apply as ht, updateCommand as i, startCommand as it, truncateCommand as j, getMigrationDirPath as jt, listWorkflows as k, formatMigrationNumber as kt, listUsers as l, getWorkflowExecution as lt, listCommand$1 as m, getExecutor as mt, queryCommand as n, listExecutorJobs as nt, removeCommand as o, getCommand$2 as ot, restoreWorkspace as p, getCommand$3 as pt, generate$1 as q, defineAppCommand as qt, isCLIError as r, watchExecutorJob as rt, removeUser as s, getWorkflow as st, query as t, jobsCommand as tt, inviteCommand as u, listWorkflowExecutions as ut, deleteCommand as v, MIGRATION_LABEL_KEY as vt, getAppHealth as w, MIGRATE_FILE_NAME as wt, createWorkspace as x, DB_TYPES_FILE_NAME as xt, deleteWorkspace as y, parseMigrationLabelNumber as yt, listCommand$4 as z, formatMigrationDiff as zt };
|
|
12607
|
+
//# sourceMappingURL=query-CgGbAmUg.mjs.map
|