@tailor-platform/sdk 1.23.0 → 1.25.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 +79 -0
- package/dist/app-config-QzNOFnEy.d.mts +197 -0
- package/dist/{application-CTQe2HSB.mjs → application-CxDvCZts.mjs} +226 -220
- package/dist/application-CxDvCZts.mjs.map +1 -0
- package/dist/application-EQCsho6Z.mjs +8 -0
- package/dist/{brand-DyPrAzpM.mjs → brand-j6C6_sGq.mjs} +1 -1
- package/dist/{brand-DyPrAzpM.mjs.map → brand-j6C6_sGq.mjs.map} +1 -1
- package/dist/cli/index.mjs +9 -9
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +7 -7
- package/dist/cli/lib.mjs +10 -10
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/configure/index.d.mts +5 -4
- package/dist/configure/index.mjs +30 -4
- package/dist/configure/index.mjs.map +1 -1
- package/dist/{enum-constants-B5Nl-yzx.mjs → enum-constants-BxdLbhsW.mjs} +1 -1
- package/dist/enum-constants-BxdLbhsW.mjs.map +1 -0
- package/dist/env-jndw86T4.d.mts +32 -0
- package/dist/{file-utils-sEOwAdJ4.mjs → file-utils-C2r3AVbI.mjs} +1 -1
- package/dist/{file-utils-sEOwAdJ4.mjs.map → file-utils-C2r3AVbI.mjs.map} +1 -1
- package/dist/{index-CU2kZzKa.d.mts → index-BUnLWUKQ.d.mts} +66 -15
- package/dist/{index-BSXclved.d.mts → index-DZRZdh71.d.mts} +2 -2
- package/dist/{index-lIALNMi_.d.mts → index-Do7zo7z-.d.mts} +2 -2
- package/dist/{index-CO-jsOMb.d.mts → index-DoxGF8-i.d.mts} +2 -2
- package/dist/{index-DQlsfhpg.d.mts → index-VZq4IAEK.d.mts} +2 -2
- package/dist/{interceptor-DiARwPfw.mjs → interceptor-DVy32eIG.mjs} +1 -1
- package/dist/{interceptor-DiARwPfw.mjs.map → interceptor-DVy32eIG.mjs.map} +1 -1
- package/dist/{job-CRavYLLk.mjs → job-CnLRQFrk.mjs} +2 -2
- package/dist/{job-CRavYLLk.mjs.map → job-CnLRQFrk.mjs.map} +1 -1
- package/dist/{kysely-type-CSlcwNFH.mjs → kysely-type-DzLBuVp6.mjs} +1 -1
- package/dist/kysely-type-DzLBuVp6.mjs.map +1 -0
- package/dist/package-json-BKA36WTo.mjs +3 -0
- package/dist/{package-json-iVBhE5Ef.mjs → package-json-DnbGCOkg.mjs} +1 -1
- package/dist/{package-json-iVBhE5Ef.mjs.map → package-json-DnbGCOkg.mjs.map} +1 -1
- package/dist/plugin/builtin/enum-constants/index.d.mts +2 -2
- package/dist/plugin/builtin/enum-constants/index.mjs +1 -1
- package/dist/plugin/builtin/file-utils/index.d.mts +2 -2
- package/dist/plugin/builtin/file-utils/index.mjs +1 -1
- package/dist/plugin/builtin/kysely-type/index.d.mts +2 -2
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
- package/dist/plugin/builtin/seed/index.d.mts +2 -2
- package/dist/plugin/builtin/seed/index.mjs +1 -1
- package/dist/plugin/index.d.mts +2 -1
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/{types--G4ilVmx.d.mts → plugin-3sT6Tcq0.d.mts} +1068 -1761
- package/dist/{query-BLQBOaAM.mjs → query-c9RCJduH.mjs} +451 -60
- package/dist/query-c9RCJduH.mjs.map +1 -0
- package/dist/{schema-Cjm-OvPF.mjs → schema-DOx_W_s2.mjs} +2 -2
- package/dist/schema-DOx_W_s2.mjs.map +1 -0
- package/dist/seed/index.d.mts +29 -0
- package/dist/seed/index.mjs +89 -0
- package/dist/seed/index.mjs.map +1 -0
- package/dist/{seed-CXvCW3Xc.mjs → seed-DkKAheSe.mjs} +76 -9
- package/dist/seed-DkKAheSe.mjs.map +1 -0
- package/dist/telemetry-J6dpByo2.mjs +3 -0
- package/dist/{telemetry-C46fds1l.mjs → telemetry-d_lgTL33.mjs} +2 -2
- package/dist/{telemetry-C46fds1l.mjs.map → telemetry-d_lgTL33.mjs.map} +1 -1
- package/dist/utils/test/index.d.mts +3 -3
- package/dist/utils/test/index.mjs +2 -2
- package/docs/cli/tailordb.md +1 -1
- package/docs/cli-reference.md +8 -8
- package/package.json +31 -24
- package/dist/application-CTQe2HSB.mjs.map +0 -1
- package/dist/application-DdSu3baZ.mjs +0 -8
- package/dist/enum-constants-B5Nl-yzx.mjs.map +0 -1
- package/dist/kysely-type-CSlcwNFH.mjs.map +0 -1
- package/dist/package-json-BI0ng3_5.mjs +0 -3
- package/dist/query-BLQBOaAM.mjs.map +0 -1
- package/dist/schema-Cjm-OvPF.mjs.map +0 -1
- package/dist/seed-CXvCW3Xc.mjs.map +0 -1
- package/dist/telemetry-BAxP8-PR.mjs +0 -3
- package/dist/types-CBTSg-LK.mjs +0 -13
- package/dist/types-CBTSg-LK.mjs.map +0 -1
- package/dist/types-IR-hw0-y.d.mts +0 -245
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { t as db } from "./schema-
|
|
2
|
-
import { $ as AuthSCIMAttribute_Mutability, A as platformBaseUrl, B as TailorDBType_Permission_Permit, C as readPlatformConfig, E as fetchMachineUserToken, F as WorkflowJobExecution_Status, H as PipelineResolver_OperationType, I as TailorDBGQLPermission_Action, J as ExecutorTriggerType, K as ExecutorJobStatus, L as TailorDBGQLPermission_Operator, M as userAgent, N as WorkspacePlatformUserRole, P as WorkflowExecution_Status, Q as AuthOAuth2Client_GrantType, R as TailorDBGQLPermission_Permit, S as loadWorkspaceId, T as fetchAll, U as IdPLang, V as TailorDBType_PermitAction, W as FunctionExecution_Status, X as AuthInvokerSchema, Y as AuthIDPConfig_AuthType, Z as AuthOAuth2Client_ClientType, _ as hashFile, a as loadConfig, at as UserProfileProviderConfig_UserProfileProviderType, b as loadFolderId, ct as Condition_Operator, d as TailorDBTypeSchema, dt as ApplicationSchemaUpdateAttemptStatus, et as AuthSCIMAttribute_Type, f as stringifyFunction, ft as Subgraph_ServiceType, g as getDistDir, h as createBundleCache, ht as symbols, it as TenantProviderConfig_TenantProviderType, j as resolveStaticWebsiteUrls, k as initOperatorClient, l as OAuth2ClientSchema, lt as FilterSchema, m as loadFilesWithIgnores, mt as styles, n as generatePluginFilesIfNeeded, nt as AuthSCIMConfig_AuthorizationType, ot as GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus, p as tailorUserMap, pt as logger, q as ExecutorTargetType, r as loadApplication, s as createExecutorService, st as ConditionSchema, t as defineApplication, tt as AuthSCIMAttribute_Uniqueness, ut as PageDirection, w as writePlatformConfig, x as loadOrganizationId, y as loadAccessToken, z as TailorDBType_Permission_Operator } from "./application-
|
|
3
|
-
import { t as readPackageJson } from "./package-json-
|
|
4
|
-
import { r as withSpan } from "./telemetry-
|
|
1
|
+
import { t as db } from "./schema-DOx_W_s2.mjs";
|
|
2
|
+
import { $ as AuthSCIMAttribute_Mutability, A as platformBaseUrl, B as TailorDBType_Permission_Permit, C as readPlatformConfig, E as fetchMachineUserToken, F as WorkflowJobExecution_Status, H as PipelineResolver_OperationType, I as TailorDBGQLPermission_Action, J as ExecutorTriggerType, K as ExecutorJobStatus, L as TailorDBGQLPermission_Operator, M as userAgent, N as WorkspacePlatformUserRole, P as WorkflowExecution_Status, Q as AuthOAuth2Client_GrantType, R as TailorDBGQLPermission_Permit, S as loadWorkspaceId, T as fetchAll, U as IdPLang, V as TailorDBType_PermitAction, W as FunctionExecution_Status, X as AuthInvokerSchema, Y as AuthIDPConfig_AuthType, Z as AuthOAuth2Client_ClientType, _ as hashFile, a as loadConfig, at as UserProfileProviderConfig_UserProfileProviderType, b as loadFolderId, ct as Condition_Operator, d as TailorDBTypeSchema, dt as ApplicationSchemaUpdateAttemptStatus, et as AuthSCIMAttribute_Type, f as stringifyFunction, ft as Subgraph_ServiceType, g as getDistDir, h as createBundleCache, ht as symbols, it as TenantProviderConfig_TenantProviderType, j as resolveStaticWebsiteUrls, k as initOperatorClient, l as OAuth2ClientSchema, lt as FilterSchema, m as loadFilesWithIgnores, mt as styles, n as generatePluginFilesIfNeeded, nt as AuthSCIMConfig_AuthorizationType, ot as GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus, p as tailorUserMap, pt as logger, q as ExecutorTargetType, r as loadApplication, s as createExecutorService, st as ConditionSchema, t as defineApplication, tt as AuthSCIMAttribute_Uniqueness, ut as PageDirection, w as writePlatformConfig, x as loadOrganizationId, y as loadAccessToken, z as TailorDBType_Permission_Operator } from "./application-CxDvCZts.mjs";
|
|
3
|
+
import { t as readPackageJson } from "./package-json-DnbGCOkg.mjs";
|
|
4
|
+
import { r as withSpan } from "./telemetry-d_lgTL33.mjs";
|
|
5
5
|
import { arg, defineCommand, runCommand } from "politty";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import * as fs$1 from "node:fs";
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
8
9
|
import { parseEnv } from "node:util";
|
|
9
10
|
import * as path from "pathe";
|
|
10
11
|
import chalk from "chalk";
|
|
@@ -13,9 +14,11 @@ import { getBorderCharacters, table } from "table";
|
|
|
13
14
|
import { ValueSchema, timestampDate } from "@bufbuild/protobuf/wkt";
|
|
14
15
|
import { Code, ConnectError } from "@connectrpc/connect";
|
|
15
16
|
import { resolveTSConfig } from "pkg-types";
|
|
17
|
+
import { tmpdir } from "node:os";
|
|
16
18
|
import { findUpSync } from "find-up-simple";
|
|
17
19
|
import ml from "multiline-ts";
|
|
18
20
|
import * as crypto from "node:crypto";
|
|
21
|
+
import { createHash } from "node:crypto";
|
|
19
22
|
import { pathToFileURL } from "node:url";
|
|
20
23
|
import * as inflection from "inflection";
|
|
21
24
|
import * as rolldown from "rolldown";
|
|
@@ -212,7 +215,7 @@ const withCommonArgs = (handler) => async (args) => {
|
|
|
212
215
|
try {
|
|
213
216
|
if ("json" in args && typeof args.json === "boolean") logger.jsonMode = args.json;
|
|
214
217
|
loadEnvFiles(args["env-file"], args["env-file-if-exists"]);
|
|
215
|
-
const { initTelemetry } = await import("./telemetry-
|
|
218
|
+
const { initTelemetry } = await import("./telemetry-J6dpByo2.mjs");
|
|
216
219
|
await initTelemetry();
|
|
217
220
|
await handler(args);
|
|
218
221
|
} catch (error) {
|
|
@@ -225,7 +228,7 @@ const withCommonArgs = (handler) => async (args) => {
|
|
|
225
228
|
} else logger.error(`Unknown error: ${error}`);
|
|
226
229
|
process.exit(1);
|
|
227
230
|
} finally {
|
|
228
|
-
const { shutdownTelemetry } = await import("./telemetry-
|
|
231
|
+
const { shutdownTelemetry } = await import("./telemetry-J6dpByo2.mjs");
|
|
229
232
|
await shutdownTelemetry();
|
|
230
233
|
}
|
|
231
234
|
process.exit(0);
|
|
@@ -592,14 +595,14 @@ async function generateUserTypes(options) {
|
|
|
592
595
|
}
|
|
593
596
|
|
|
594
597
|
//#endregion
|
|
595
|
-
//#region src/
|
|
598
|
+
//#region src/types/plugin-generation.ts
|
|
596
599
|
/**
|
|
597
600
|
* Derives generation-time dependency set from hook presence on a plugin.
|
|
598
|
-
* @param plugin -
|
|
599
|
-
* @param plugin.onTailorDBReady - TailorDB
|
|
600
|
-
* @param plugin.onResolverReady -
|
|
601
|
-
* @param plugin.onExecutorReady -
|
|
602
|
-
* @returns Set of dependency kinds
|
|
601
|
+
* @param plugin - The plugin object to inspect.
|
|
602
|
+
* @param plugin.onTailorDBReady - Hook for TailorDB readiness.
|
|
603
|
+
* @param plugin.onResolverReady - Hook for resolver readiness.
|
|
604
|
+
* @param plugin.onExecutorReady - Hook for executor readiness.
|
|
605
|
+
* @returns Set of dependency kinds required by the plugin.
|
|
603
606
|
*/
|
|
604
607
|
function getPluginGenerationDependencies(plugin) {
|
|
605
608
|
const deps = /* @__PURE__ */ new Set();
|
|
@@ -610,11 +613,11 @@ function getPluginGenerationDependencies(plugin) {
|
|
|
610
613
|
}
|
|
611
614
|
/**
|
|
612
615
|
* Checks if a plugin has any generation-time hooks.
|
|
613
|
-
* @param plugin -
|
|
614
|
-
* @param plugin.onTailorDBReady - TailorDB
|
|
615
|
-
* @param plugin.onResolverReady -
|
|
616
|
-
* @param plugin.onExecutorReady -
|
|
617
|
-
* @returns True if the plugin has at least one generation hook
|
|
616
|
+
* @param plugin - The plugin object to inspect.
|
|
617
|
+
* @param plugin.onTailorDBReady - Hook for TailorDB readiness.
|
|
618
|
+
* @param plugin.onResolverReady - Hook for resolver readiness.
|
|
619
|
+
* @param plugin.onExecutorReady - Hook for executor readiness.
|
|
620
|
+
* @returns True if the plugin has at least one generation hook.
|
|
618
621
|
*/
|
|
619
622
|
function hasGenerationHooks(plugin) {
|
|
620
623
|
return !!(plugin.onTailorDBReady || plugin.onResolverReady || plugin.onExecutorReady);
|
|
@@ -3250,6 +3253,257 @@ function protoFields(fields, baseName, isInput) {
|
|
|
3250
3253
|
});
|
|
3251
3254
|
}
|
|
3252
3255
|
|
|
3256
|
+
//#endregion
|
|
3257
|
+
//#region src/cli/commands/apply/secrets-state.ts
|
|
3258
|
+
const SecretsStateSchema = z.object({ vaults: z.record(z.string(), z.record(z.string(), z.string())) });
|
|
3259
|
+
/**
|
|
3260
|
+
* Get the file path for the secrets state JSON.
|
|
3261
|
+
* @returns Absolute path to secrets-state.json
|
|
3262
|
+
*/
|
|
3263
|
+
function getSecretsStatePath() {
|
|
3264
|
+
return path.join(getDistDir(), "secrets-state.json");
|
|
3265
|
+
}
|
|
3266
|
+
/**
|
|
3267
|
+
* Load secrets hash state from disk.
|
|
3268
|
+
* @returns Persisted state, or empty state if file is missing or corrupted
|
|
3269
|
+
*/
|
|
3270
|
+
function loadSecretsState() {
|
|
3271
|
+
const filePath = getSecretsStatePath();
|
|
3272
|
+
if (!existsSync(filePath)) return { vaults: {} };
|
|
3273
|
+
try {
|
|
3274
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
3275
|
+
return SecretsStateSchema.parse(JSON.parse(raw));
|
|
3276
|
+
} catch {
|
|
3277
|
+
return { vaults: {} };
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
/**
|
|
3281
|
+
* Save secrets hash state to disk.
|
|
3282
|
+
* @param state - The secrets state to persist
|
|
3283
|
+
*/
|
|
3284
|
+
function saveSecretsState(state) {
|
|
3285
|
+
const filePath = getSecretsStatePath();
|
|
3286
|
+
mkdirSync(path.dirname(filePath), { recursive: true });
|
|
3287
|
+
writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
|
|
3288
|
+
}
|
|
3289
|
+
/**
|
|
3290
|
+
* Compute SHA-256 hex digest of a value.
|
|
3291
|
+
* @param value - The string to hash
|
|
3292
|
+
* @returns Hex-encoded SHA-256 hash
|
|
3293
|
+
*/
|
|
3294
|
+
function hashValue(value) {
|
|
3295
|
+
return createHash("sha256").update(value).digest("hex");
|
|
3296
|
+
}
|
|
3297
|
+
|
|
3298
|
+
//#endregion
|
|
3299
|
+
//#region src/cli/commands/apply/secret-manager.ts
|
|
3300
|
+
/**
|
|
3301
|
+
* Plan secret manager changes based on current and desired state.
|
|
3302
|
+
* @param context - Planning context
|
|
3303
|
+
* @returns Planned changes for vaults and secrets
|
|
3304
|
+
*/
|
|
3305
|
+
async function planSecretManager(context) {
|
|
3306
|
+
const { client, workspaceId, application, forRemoval } = context;
|
|
3307
|
+
const secretVaults = forRemoval ? [] : application.secrets;
|
|
3308
|
+
const vaultChangeSet = createChangeSet("Secret Manager vaults");
|
|
3309
|
+
const secretChangeSet = createChangeSet("Secret Manager secrets");
|
|
3310
|
+
const conflicts = [];
|
|
3311
|
+
const unmanaged = [];
|
|
3312
|
+
const resourceOwners = /* @__PURE__ */ new Set();
|
|
3313
|
+
const existingVaultList = await fetchAll(async (pageToken, maxPageSize) => {
|
|
3314
|
+
try {
|
|
3315
|
+
const { vaults, nextPageToken } = await client.listSecretManagerVaults({
|
|
3316
|
+
workspaceId,
|
|
3317
|
+
pageToken,
|
|
3318
|
+
pageSize: maxPageSize
|
|
3319
|
+
});
|
|
3320
|
+
return [vaults, nextPageToken];
|
|
3321
|
+
} catch (error) {
|
|
3322
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) return [[], ""];
|
|
3323
|
+
throw error;
|
|
3324
|
+
}
|
|
3325
|
+
});
|
|
3326
|
+
const existingVaults = {};
|
|
3327
|
+
await Promise.all(existingVaultList.map(async (resource) => {
|
|
3328
|
+
const { metadata } = await client.getMetadata({ trn: vaultTrn(workspaceId, resource.name) });
|
|
3329
|
+
existingVaults[resource.name] = {
|
|
3330
|
+
resource,
|
|
3331
|
+
label: metadata?.labels[sdkNameLabelKey]
|
|
3332
|
+
};
|
|
3333
|
+
}));
|
|
3334
|
+
const state = loadSecretsState();
|
|
3335
|
+
await Promise.all(secretVaults.map(async (vault) => {
|
|
3336
|
+
const vaultName = vault.vaultName;
|
|
3337
|
+
const existing = existingVaults[vaultName];
|
|
3338
|
+
if (existing) {
|
|
3339
|
+
if (!existing.label) unmanaged.push({
|
|
3340
|
+
resourceType: "Secret Manager vault",
|
|
3341
|
+
resourceName: vaultName
|
|
3342
|
+
});
|
|
3343
|
+
else if (existing.label !== application.name) conflicts.push({
|
|
3344
|
+
resourceType: "Secret Manager vault",
|
|
3345
|
+
resourceName: vaultName,
|
|
3346
|
+
currentOwner: existing.label
|
|
3347
|
+
});
|
|
3348
|
+
vaultChangeSet.updates.push({
|
|
3349
|
+
name: vaultName,
|
|
3350
|
+
workspaceId
|
|
3351
|
+
});
|
|
3352
|
+
delete existingVaults[vaultName];
|
|
3353
|
+
} else vaultChangeSet.creates.push({
|
|
3354
|
+
name: vaultName,
|
|
3355
|
+
workspaceId
|
|
3356
|
+
});
|
|
3357
|
+
let existingSecrets = [];
|
|
3358
|
+
if (existing) existingSecrets = (await fetchAll(async (pageToken, maxPageSize) => {
|
|
3359
|
+
try {
|
|
3360
|
+
const { secrets, nextPageToken } = await client.listSecretManagerSecrets({
|
|
3361
|
+
workspaceId,
|
|
3362
|
+
secretmanagerVaultName: vaultName,
|
|
3363
|
+
pageToken,
|
|
3364
|
+
pageSize: maxPageSize
|
|
3365
|
+
});
|
|
3366
|
+
return [secrets, nextPageToken];
|
|
3367
|
+
} catch (error) {
|
|
3368
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) return [[], ""];
|
|
3369
|
+
throw error;
|
|
3370
|
+
}
|
|
3371
|
+
})).map((s) => s.name);
|
|
3372
|
+
const existingSet = new Set(existingSecrets);
|
|
3373
|
+
for (const secret of vault.secrets) if (existingSet.has(secret.name)) {
|
|
3374
|
+
if (hashValue(secret.value) !== state.vaults[vaultName]?.[secret.name]) secretChangeSet.updates.push({
|
|
3375
|
+
name: `${vaultName}/${secret.name}`,
|
|
3376
|
+
secretName: secret.name,
|
|
3377
|
+
workspaceId,
|
|
3378
|
+
vaultName,
|
|
3379
|
+
value: secret.value
|
|
3380
|
+
});
|
|
3381
|
+
existingSet.delete(secret.name);
|
|
3382
|
+
} else secretChangeSet.creates.push({
|
|
3383
|
+
name: `${vaultName}/${secret.name}`,
|
|
3384
|
+
secretName: secret.name,
|
|
3385
|
+
workspaceId,
|
|
3386
|
+
vaultName,
|
|
3387
|
+
value: secret.value
|
|
3388
|
+
});
|
|
3389
|
+
for (const orphanName of existingSet) secretChangeSet.deletes.push({
|
|
3390
|
+
name: `${vaultName}/${orphanName}`,
|
|
3391
|
+
secretName: orphanName,
|
|
3392
|
+
workspaceId,
|
|
3393
|
+
vaultName
|
|
3394
|
+
});
|
|
3395
|
+
}));
|
|
3396
|
+
for (const [name, entry] of Object.entries(existingVaults)) {
|
|
3397
|
+
if (!entry) continue;
|
|
3398
|
+
const label = entry.label;
|
|
3399
|
+
if (label && label !== application.name) resourceOwners.add(label);
|
|
3400
|
+
if (label === application.name) {
|
|
3401
|
+
const secrets = await fetchAll(async (pageToken, maxPageSize) => {
|
|
3402
|
+
try {
|
|
3403
|
+
const { secrets: secrets$1, nextPageToken } = await client.listSecretManagerSecrets({
|
|
3404
|
+
workspaceId,
|
|
3405
|
+
secretmanagerVaultName: name,
|
|
3406
|
+
pageToken,
|
|
3407
|
+
pageSize: maxPageSize
|
|
3408
|
+
});
|
|
3409
|
+
return [secrets$1, nextPageToken];
|
|
3410
|
+
} catch (error) {
|
|
3411
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) return [[], ""];
|
|
3412
|
+
throw error;
|
|
3413
|
+
}
|
|
3414
|
+
});
|
|
3415
|
+
for (const secret of secrets) secretChangeSet.deletes.push({
|
|
3416
|
+
name: `${name}/${secret.name}`,
|
|
3417
|
+
secretName: secret.name,
|
|
3418
|
+
workspaceId,
|
|
3419
|
+
vaultName: name
|
|
3420
|
+
});
|
|
3421
|
+
vaultChangeSet.deletes.push({
|
|
3422
|
+
name,
|
|
3423
|
+
workspaceId
|
|
3424
|
+
});
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
3427
|
+
vaultChangeSet.print();
|
|
3428
|
+
secretChangeSet.print();
|
|
3429
|
+
return {
|
|
3430
|
+
vaultChangeSet,
|
|
3431
|
+
secretChangeSet,
|
|
3432
|
+
conflicts,
|
|
3433
|
+
unmanaged,
|
|
3434
|
+
resourceOwners
|
|
3435
|
+
};
|
|
3436
|
+
}
|
|
3437
|
+
function vaultTrn(workspaceId, name) {
|
|
3438
|
+
return `trn:v1:workspace:${workspaceId}:vault:${name}`;
|
|
3439
|
+
}
|
|
3440
|
+
/**
|
|
3441
|
+
* Apply secret manager changes for the given phase.
|
|
3442
|
+
* @param client - Operator client instance
|
|
3443
|
+
* @param result - Planned secret changes
|
|
3444
|
+
* @param phase - Apply phase
|
|
3445
|
+
* @param application - Application to read secrets from for hash state persistence
|
|
3446
|
+
* @returns Promise that resolves when secret changes are applied
|
|
3447
|
+
*/
|
|
3448
|
+
async function applySecretManager(client, result, phase = "create-update", application) {
|
|
3449
|
+
const { vaultChangeSet, secretChangeSet } = result;
|
|
3450
|
+
if (phase === "create-update") {
|
|
3451
|
+
await Promise.all(vaultChangeSet.creates.map(async (create$1) => {
|
|
3452
|
+
await client.createSecretManagerVault({
|
|
3453
|
+
workspaceId: create$1.workspaceId,
|
|
3454
|
+
secretmanagerVaultName: create$1.name
|
|
3455
|
+
});
|
|
3456
|
+
if (application) {
|
|
3457
|
+
const metaRequest = await buildMetaRequest(vaultTrn(create$1.workspaceId, create$1.name), application.name);
|
|
3458
|
+
await client.setMetadata(metaRequest);
|
|
3459
|
+
}
|
|
3460
|
+
}));
|
|
3461
|
+
if (application) await Promise.all(vaultChangeSet.updates.map(async (update) => {
|
|
3462
|
+
const metaRequest = await buildMetaRequest(vaultTrn(update.workspaceId, update.name), application.name);
|
|
3463
|
+
await client.setMetadata(metaRequest);
|
|
3464
|
+
}));
|
|
3465
|
+
await Promise.all(secretChangeSet.creates.map((create$1) => client.createSecretManagerSecret({
|
|
3466
|
+
workspaceId: create$1.workspaceId,
|
|
3467
|
+
secretmanagerVaultName: create$1.vaultName,
|
|
3468
|
+
secretmanagerSecretName: create$1.secretName,
|
|
3469
|
+
secretmanagerSecretValue: create$1.value
|
|
3470
|
+
})));
|
|
3471
|
+
await Promise.all(secretChangeSet.updates.map((update) => client.updateSecretManagerSecret({
|
|
3472
|
+
workspaceId: update.workspaceId,
|
|
3473
|
+
secretmanagerVaultName: update.vaultName,
|
|
3474
|
+
secretmanagerSecretName: update.secretName,
|
|
3475
|
+
secretmanagerSecretValue: update.value
|
|
3476
|
+
})));
|
|
3477
|
+
if (application) {
|
|
3478
|
+
const state = loadSecretsState();
|
|
3479
|
+
for (const vault of application.secrets) {
|
|
3480
|
+
if (!state.vaults[vault.vaultName]) state.vaults[vault.vaultName] = {};
|
|
3481
|
+
for (const secret of vault.secrets) state.vaults[vault.vaultName][secret.name] = hashValue(secret.value);
|
|
3482
|
+
}
|
|
3483
|
+
saveSecretsState(state);
|
|
3484
|
+
}
|
|
3485
|
+
} else if (phase === "delete") {
|
|
3486
|
+
await Promise.all(secretChangeSet.deletes.map((del) => client.deleteSecretManagerSecret({
|
|
3487
|
+
workspaceId: del.workspaceId,
|
|
3488
|
+
secretmanagerVaultName: del.vaultName,
|
|
3489
|
+
secretmanagerSecretName: del.secretName
|
|
3490
|
+
})));
|
|
3491
|
+
await Promise.all(vaultChangeSet.deletes.map((del) => client.deleteSecretManagerVault({
|
|
3492
|
+
workspaceId: del.workspaceId,
|
|
3493
|
+
secretmanagerVaultName: del.name
|
|
3494
|
+
})));
|
|
3495
|
+
if (secretChangeSet.deletes.length > 0 || vaultChangeSet.deletes.length > 0) {
|
|
3496
|
+
const state = loadSecretsState();
|
|
3497
|
+
for (const del of secretChangeSet.deletes) if (state.vaults[del.vaultName]) {
|
|
3498
|
+
delete state.vaults[del.vaultName][del.secretName];
|
|
3499
|
+
if (Object.keys(state.vaults[del.vaultName]).length === 0) delete state.vaults[del.vaultName];
|
|
3500
|
+
}
|
|
3501
|
+
for (const del of vaultChangeSet.deletes) delete state.vaults[del.name];
|
|
3502
|
+
saveSecretsState(state);
|
|
3503
|
+
}
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
|
|
3253
3507
|
//#endregion
|
|
3254
3508
|
//#region src/cli/commands/apply/staticwebsite.ts
|
|
3255
3509
|
/**
|
|
@@ -3672,7 +3926,7 @@ function createSnapshotFieldConfig(field) {
|
|
|
3672
3926
|
}
|
|
3673
3927
|
/**
|
|
3674
3928
|
* Create a snapshot field config from an OperatorFieldConfig (for nested fields)
|
|
3675
|
-
* @param {import("@/
|
|
3929
|
+
* @param {import("@/types/tailordb").OperatorFieldConfig} fieldConfig - Field configuration
|
|
3676
3930
|
* @returns {SnapshotFieldConfig} Snapshot field configuration
|
|
3677
3931
|
*/
|
|
3678
3932
|
function createSnapshotFieldConfigFromOperatorConfig(fieldConfig) {
|
|
@@ -6381,7 +6635,7 @@ async function apply(options) {
|
|
|
6381
6635
|
const functionEntries = collectFunctionEntries(application, workflowService?.jobs ?? []);
|
|
6382
6636
|
const dryRun = options?.dryRun ?? false;
|
|
6383
6637
|
const yes = options?.yes ?? false;
|
|
6384
|
-
const { functionRegistry, tailorDB, staticWebsite, idp, auth, pipeline, app, executor, workflow } = await withSpan("plan", async () => {
|
|
6638
|
+
const { functionRegistry, tailorDB, staticWebsite, idp, auth, pipeline, app, executor, workflow, secretManager } = await withSpan("plan", async () => {
|
|
6385
6639
|
const ctx = {
|
|
6386
6640
|
client,
|
|
6387
6641
|
workspaceId,
|
|
@@ -6390,7 +6644,7 @@ async function apply(options) {
|
|
|
6390
6644
|
config,
|
|
6391
6645
|
noSchemaCheck: options?.noSchemaCheck
|
|
6392
6646
|
};
|
|
6393
|
-
const [functionRegistry$1, tailorDB$1, staticWebsite$1, idp$1, auth$1, pipeline$1, app$1, executor$1, workflow$1] = await Promise.all([
|
|
6647
|
+
const [functionRegistry$1, tailorDB$1, staticWebsite$1, idp$1, auth$1, pipeline$1, app$1, executor$1, workflow$1, secretManager$1] = await Promise.all([
|
|
6394
6648
|
withSpan("plan.functionRegistry", () => planFunctionRegistry(client, workspaceId, application.name, functionEntries)),
|
|
6395
6649
|
withSpan("plan.tailorDB", () => planTailorDB(ctx)),
|
|
6396
6650
|
withSpan("plan.staticWebsite", () => planStaticWebsite(ctx)),
|
|
@@ -6399,7 +6653,8 @@ async function apply(options) {
|
|
|
6399
6653
|
withSpan("plan.pipeline", () => planPipeline(ctx)),
|
|
6400
6654
|
withSpan("plan.application", () => planApplication(ctx)),
|
|
6401
6655
|
withSpan("plan.executor", () => planExecutor(ctx)),
|
|
6402
|
-
withSpan("plan.workflow", () => planWorkflow(client, workspaceId, application.name, workflowService?.workflows ?? {}, workflowBuildResult?.mainJobDeps ?? {}))
|
|
6656
|
+
withSpan("plan.workflow", () => planWorkflow(client, workspaceId, application.name, workflowService?.workflows ?? {}, workflowBuildResult?.mainJobDeps ?? {})),
|
|
6657
|
+
withSpan("plan.secretManager", () => planSecretManager(ctx))
|
|
6403
6658
|
]);
|
|
6404
6659
|
return {
|
|
6405
6660
|
functionRegistry: functionRegistry$1,
|
|
@@ -6410,7 +6665,8 @@ async function apply(options) {
|
|
|
6410
6665
|
pipeline: pipeline$1,
|
|
6411
6666
|
app: app$1,
|
|
6412
6667
|
executor: executor$1,
|
|
6413
|
-
workflow: workflow$1
|
|
6668
|
+
workflow: workflow$1,
|
|
6669
|
+
secretManager: secretManager$1
|
|
6414
6670
|
};
|
|
6415
6671
|
});
|
|
6416
6672
|
await withSpan("confirm", async () => {
|
|
@@ -6422,7 +6678,8 @@ async function apply(options) {
|
|
|
6422
6678
|
...auth.conflicts,
|
|
6423
6679
|
...pipeline.conflicts,
|
|
6424
6680
|
...executor.conflicts,
|
|
6425
|
-
...workflow.conflicts
|
|
6681
|
+
...workflow.conflicts,
|
|
6682
|
+
...secretManager.conflicts
|
|
6426
6683
|
];
|
|
6427
6684
|
await confirmOwnerConflict(allConflicts, application.name, yes);
|
|
6428
6685
|
await confirmUnmanagedResources([
|
|
@@ -6433,7 +6690,8 @@ async function apply(options) {
|
|
|
6433
6690
|
...auth.unmanaged,
|
|
6434
6691
|
...pipeline.unmanaged,
|
|
6435
6692
|
...executor.unmanaged,
|
|
6436
|
-
...workflow.unmanaged
|
|
6693
|
+
...workflow.unmanaged,
|
|
6694
|
+
...secretManager.unmanaged
|
|
6437
6695
|
], application.name, yes);
|
|
6438
6696
|
const importantDeletions = [];
|
|
6439
6697
|
for (const del of tailorDB.changeSet.type.deletes) importantDeletions.push({
|
|
@@ -6452,6 +6710,14 @@ async function apply(options) {
|
|
|
6452
6710
|
resourceType: "OAuth2 client (client type change)",
|
|
6453
6711
|
resourceName: replace.name
|
|
6454
6712
|
});
|
|
6713
|
+
for (const del of secretManager.vaultChangeSet.deletes) importantDeletions.push({
|
|
6714
|
+
resourceType: "Secret Manager vault",
|
|
6715
|
+
resourceName: del.name
|
|
6716
|
+
});
|
|
6717
|
+
for (const del of secretManager.secretChangeSet.deletes) importantDeletions.push({
|
|
6718
|
+
resourceType: "Secret Manager secret",
|
|
6719
|
+
resourceName: del.name
|
|
6720
|
+
});
|
|
6455
6721
|
await confirmImportantResourceDeletion(importantDeletions, yes);
|
|
6456
6722
|
const resourceOwners = new Set([
|
|
6457
6723
|
...functionRegistry.resourceOwners,
|
|
@@ -6461,7 +6727,8 @@ async function apply(options) {
|
|
|
6461
6727
|
...auth.resourceOwners,
|
|
6462
6728
|
...pipeline.resourceOwners,
|
|
6463
6729
|
...executor.resourceOwners,
|
|
6464
|
-
...workflow.resourceOwners
|
|
6730
|
+
...workflow.resourceOwners,
|
|
6731
|
+
...secretManager.resourceOwners
|
|
6465
6732
|
]);
|
|
6466
6733
|
const emptyApps = [...new Set(allConflicts.map((c) => c.currentOwner))].filter((owner) => !resourceOwners.has(owner));
|
|
6467
6734
|
for (const emptyApp of emptyApps) app.deletes.push({
|
|
@@ -6477,6 +6744,7 @@ async function apply(options) {
|
|
|
6477
6744
|
return;
|
|
6478
6745
|
}
|
|
6479
6746
|
await withSpan("apply.createUpdateServices", async () => {
|
|
6747
|
+
await applySecretManager(client, secretManager, "create-update", application);
|
|
6480
6748
|
await applyFunctionRegistry(client, workspaceId, functionRegistry, "create-update");
|
|
6481
6749
|
await applyStaticWebsite(client, staticWebsite, "create-update");
|
|
6482
6750
|
await applyIdP(client, idp, "create-update");
|
|
@@ -6498,6 +6766,7 @@ async function apply(options) {
|
|
|
6498
6766
|
await applyWorkflow(client, workflow, "delete");
|
|
6499
6767
|
await applyExecutor(client, executor, "delete");
|
|
6500
6768
|
await applyStaticWebsite(client, staticWebsite, "delete");
|
|
6769
|
+
await applySecretManager(client, secretManager, "delete");
|
|
6501
6770
|
});
|
|
6502
6771
|
await withSpan("apply.deleteApplication", () => applyApplication(client, app, "delete"));
|
|
6503
6772
|
await withSpan("apply.deleteSubgraphServices", async () => {
|
|
@@ -9399,7 +9668,8 @@ async function execRemove(client, workspaceId, application, config, confirm) {
|
|
|
9399
9668
|
const executor = await planExecutor(ctx);
|
|
9400
9669
|
const workflow = await planWorkflow(client, workspaceId, application.name, {}, {});
|
|
9401
9670
|
const functionRegistry = await planFunctionRegistry(client, workspaceId, application.name, []);
|
|
9402
|
-
|
|
9671
|
+
const secretManager = await planSecretManager(ctx);
|
|
9672
|
+
if (tailorDB.changeSet.service.deletes.length === 0 && staticWebsite.changeSet.deletes.length === 0 && idp.changeSet.service.deletes.length === 0 && auth.changeSet.service.deletes.length === 0 && pipeline.changeSet.service.deletes.length === 0 && app.deletes.length === 0 && executor.changeSet.deletes.length === 0 && workflow.changeSet.deletes.length === 0 && functionRegistry.changeSet.deletes.length === 0 && secretManager.vaultChangeSet.deletes.length === 0 && secretManager.secretChangeSet.deletes.length === 0) return;
|
|
9403
9673
|
if (confirm) await confirm();
|
|
9404
9674
|
await applyWorkflow(client, workflow, "delete");
|
|
9405
9675
|
await applyExecutor(client, executor, "delete");
|
|
@@ -9414,6 +9684,7 @@ async function execRemove(client, workspaceId, application, config, confirm) {
|
|
|
9414
9684
|
await applyTailorDB(client, tailorDB, "delete-resources");
|
|
9415
9685
|
await applyTailorDB(client, tailorDB, "delete-services");
|
|
9416
9686
|
await applyFunctionRegistry(client, workspaceId, functionRegistry, "delete");
|
|
9687
|
+
await applySecretManager(client, secretManager, "delete");
|
|
9417
9688
|
}
|
|
9418
9689
|
/**
|
|
9419
9690
|
* Remove all resources managed by the current application.
|
|
@@ -9527,6 +9798,70 @@ function logBetaWarning(featureName) {
|
|
|
9527
9798
|
logger.newline();
|
|
9528
9799
|
}
|
|
9529
9800
|
|
|
9801
|
+
//#endregion
|
|
9802
|
+
//#region src/cli/shared/editor.ts
|
|
9803
|
+
const DEFAULT_EDITOR = "editor";
|
|
9804
|
+
function normalizeEditorCommand(editor) {
|
|
9805
|
+
const normalized = editor?.trim();
|
|
9806
|
+
return normalized && normalized.length > 0 ? normalized : void 0;
|
|
9807
|
+
}
|
|
9808
|
+
/**
|
|
9809
|
+
* Resolve an editor command only from explicit environment variables.
|
|
9810
|
+
* @returns Configured editor command, if any
|
|
9811
|
+
*/
|
|
9812
|
+
function getConfiguredEditorCommand() {
|
|
9813
|
+
return normalizeEditorCommand(process.env.VISUAL) ?? normalizeEditorCommand(process.env.EDITOR);
|
|
9814
|
+
}
|
|
9815
|
+
/**
|
|
9816
|
+
* Resolve the editor command used for interactive file editing.
|
|
9817
|
+
* @returns Configured editor command or the system default fallback
|
|
9818
|
+
*/
|
|
9819
|
+
function getEditorCommand() {
|
|
9820
|
+
return getConfiguredEditorCommand() ?? DEFAULT_EDITOR;
|
|
9821
|
+
}
|
|
9822
|
+
function parseEditorCommand(editor) {
|
|
9823
|
+
const [command, ...args] = editor.trim().split(/\s+/);
|
|
9824
|
+
if (!command) throw new Error("Editor command is empty.");
|
|
9825
|
+
return {
|
|
9826
|
+
command,
|
|
9827
|
+
args
|
|
9828
|
+
};
|
|
9829
|
+
}
|
|
9830
|
+
/**
|
|
9831
|
+
* Open a file in the resolved editor and wait for the process to exit.
|
|
9832
|
+
* @param filePath - File path to open
|
|
9833
|
+
* @param editor - Editor command string
|
|
9834
|
+
* @returns Whether an editor process was launched
|
|
9835
|
+
*/
|
|
9836
|
+
async function openInEditor(filePath, editor = getEditorCommand()) {
|
|
9837
|
+
const { command, args } = parseEditorCommand(editor);
|
|
9838
|
+
await new Promise((resolve$1, reject) => {
|
|
9839
|
+
const child = spawn(command, [...args, filePath], {
|
|
9840
|
+
stdio: "inherit",
|
|
9841
|
+
detached: false
|
|
9842
|
+
});
|
|
9843
|
+
child.once("error", (error) => reject(error));
|
|
9844
|
+
child.once("close", (code) => {
|
|
9845
|
+
if (code == null || code === 0) {
|
|
9846
|
+
resolve$1();
|
|
9847
|
+
return;
|
|
9848
|
+
}
|
|
9849
|
+
reject(/* @__PURE__ */ new Error(`Editor exited with code ${code}.`));
|
|
9850
|
+
});
|
|
9851
|
+
});
|
|
9852
|
+
return true;
|
|
9853
|
+
}
|
|
9854
|
+
/**
|
|
9855
|
+
* Open a file only when an editor is explicitly configured in the environment.
|
|
9856
|
+
* @param filePath - File path to open
|
|
9857
|
+
* @returns Whether an editor process was launched
|
|
9858
|
+
*/
|
|
9859
|
+
async function openInConfiguredEditor(filePath) {
|
|
9860
|
+
const editor = getConfiguredEditorCommand();
|
|
9861
|
+
if (!editor) return false;
|
|
9862
|
+
return await openInEditor(filePath, editor);
|
|
9863
|
+
}
|
|
9864
|
+
|
|
9530
9865
|
//#endregion
|
|
9531
9866
|
//#region src/cli/commands/tailordb/migrate/db-types-generator.ts
|
|
9532
9867
|
/**
|
|
@@ -10036,7 +10371,7 @@ async function generate(options) {
|
|
|
10036
10371
|
if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
|
|
10037
10372
|
let pluginManager;
|
|
10038
10373
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
10039
|
-
const { defineApplication: defineApplication$1 } = await import("./application-
|
|
10374
|
+
const { defineApplication: defineApplication$1 } = await import("./application-EQCsho6Z.mjs");
|
|
10040
10375
|
const application = defineApplication$1({
|
|
10041
10376
|
config,
|
|
10042
10377
|
pluginManager
|
|
@@ -10135,35 +10470,23 @@ async function generateDiffFromSnapshot(previousSnapshot, currentSnapshot, migra
|
|
|
10135
10470
|
logger.newline();
|
|
10136
10471
|
logger.log("A migration script was generated for breaking changes.");
|
|
10137
10472
|
logger.log("Please review and edit the script before running 'tailor-sdk apply'.");
|
|
10138
|
-
|
|
10473
|
+
const editor = getConfiguredEditorCommand();
|
|
10474
|
+
if (!editor) return;
|
|
10475
|
+
try {
|
|
10476
|
+
await fs.access(result.migrateFilePath);
|
|
10477
|
+
} catch {
|
|
10478
|
+
return;
|
|
10479
|
+
}
|
|
10480
|
+
logger.newline();
|
|
10481
|
+
logger.info(`Opening ${path.basename(result.migrateFilePath)} in ${editor}...`);
|
|
10482
|
+
try {
|
|
10483
|
+
await openInConfiguredEditor(result.migrateFilePath);
|
|
10484
|
+
} catch {
|
|
10485
|
+
return;
|
|
10486
|
+
}
|
|
10139
10487
|
}
|
|
10140
10488
|
}
|
|
10141
10489
|
/**
|
|
10142
|
-
* Open a file in the user's preferred editor
|
|
10143
|
-
* @param {string} filePath - Path to file to open
|
|
10144
|
-
* @returns {Promise<void>} Promise that resolves when editor closes
|
|
10145
|
-
*/
|
|
10146
|
-
async function openInEditor(filePath) {
|
|
10147
|
-
const editor = process.env.EDITOR;
|
|
10148
|
-
if (!editor) return;
|
|
10149
|
-
try {
|
|
10150
|
-
await fs.access(filePath);
|
|
10151
|
-
} catch {
|
|
10152
|
-
return;
|
|
10153
|
-
}
|
|
10154
|
-
const [command, ...args] = editor.trim().split(/\s+/);
|
|
10155
|
-
logger.newline();
|
|
10156
|
-
logger.info(`Opening ${path.basename(filePath)} in ${editor}...`);
|
|
10157
|
-
const child = spawn(command, [...args, filePath], {
|
|
10158
|
-
stdio: "inherit",
|
|
10159
|
-
detached: false
|
|
10160
|
-
});
|
|
10161
|
-
await new Promise((resolve$1) => {
|
|
10162
|
-
child.on("close", () => resolve$1());
|
|
10163
|
-
child.on("error", () => resolve$1());
|
|
10164
|
-
});
|
|
10165
|
-
}
|
|
10166
|
-
/**
|
|
10167
10490
|
* CLI command definition for generate
|
|
10168
10491
|
*/
|
|
10169
10492
|
const generateCommand = defineCommand({
|
|
@@ -11763,11 +12086,49 @@ function parseExecutionResult(result) {
|
|
|
11763
12086
|
* Resolve query input mode from CLI args.
|
|
11764
12087
|
* @param args - Query input flags
|
|
11765
12088
|
* @param args.query - Direct query string
|
|
12089
|
+
* @param args.file - File path containing query text
|
|
12090
|
+
* @param args.edit - Open a query editor instead of REPL
|
|
12091
|
+
* @param args.engine - Query engine used to choose temp file extension
|
|
11766
12092
|
* @returns Normalized input mode
|
|
11767
12093
|
*/
|
|
11768
|
-
function resolveQueryCommandInput(args) {
|
|
11769
|
-
if (args.query != null) return {
|
|
11770
|
-
|
|
12094
|
+
async function resolveQueryCommandInput(args) {
|
|
12095
|
+
if (args.query != null) return {
|
|
12096
|
+
mode: "query",
|
|
12097
|
+
query: args.query
|
|
12098
|
+
};
|
|
12099
|
+
if (args.file != null) return {
|
|
12100
|
+
mode: "query",
|
|
12101
|
+
query: await fs.readFile(args.file, "utf-8")
|
|
12102
|
+
};
|
|
12103
|
+
if (args.edit) return await resolveEditedQueryInput(args.engine);
|
|
12104
|
+
return { mode: "repl" };
|
|
12105
|
+
}
|
|
12106
|
+
async function resolveEditedQueryInput(engine) {
|
|
12107
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("Non-interactive terminals are not supported. Pass -q/--query or -f/--file to run a query.");
|
|
12108
|
+
const editor = getEditorCommand();
|
|
12109
|
+
const tempDir = await fs.mkdtemp(path.join(tmpdir(), "tailor-query-"));
|
|
12110
|
+
const fileExtension = engine === "sql" ? "sql" : "graphql";
|
|
12111
|
+
const filePath = path.join(tempDir, `query.${fileExtension}`);
|
|
12112
|
+
const initialQuery = "";
|
|
12113
|
+
try {
|
|
12114
|
+
await fs.writeFile(filePath, initialQuery, "utf-8");
|
|
12115
|
+
try {
|
|
12116
|
+
await openInEditor(filePath, editor);
|
|
12117
|
+
} catch (error) {
|
|
12118
|
+
throw new Error(`Failed to open query editor "${editor}": ${error instanceof Error ? error.message : String(error)}`);
|
|
12119
|
+
}
|
|
12120
|
+
const editedQuery = await fs.readFile(filePath, "utf-8");
|
|
12121
|
+
if (editedQuery.trim().length === 0 || editedQuery === initialQuery) return { mode: "abort" };
|
|
12122
|
+
return {
|
|
12123
|
+
mode: "query",
|
|
12124
|
+
query: editedQuery
|
|
12125
|
+
};
|
|
12126
|
+
} finally {
|
|
12127
|
+
await fs.rm(tempDir, {
|
|
12128
|
+
recursive: true,
|
|
12129
|
+
force: true
|
|
12130
|
+
});
|
|
12131
|
+
}
|
|
11771
12132
|
}
|
|
11772
12133
|
/**
|
|
11773
12134
|
* Dispatch query execution.
|
|
@@ -11849,7 +12210,7 @@ function clearReplScreen() {
|
|
|
11849
12210
|
process.stdout.write("\x1Bc");
|
|
11850
12211
|
}
|
|
11851
12212
|
async function runRepl(options) {
|
|
11852
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("Non-interactive terminals are not supported. Pass -q/--query to run a query.");
|
|
12213
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("Non-interactive terminals are not supported. Pass -q/--query or -f/--file to run a query.");
|
|
11853
12214
|
const execute = await prepareQueryExecutor(options);
|
|
11854
12215
|
const rl = createInterface({
|
|
11855
12216
|
input: process.stdin,
|
|
@@ -12042,13 +12403,39 @@ const queryCommand = defineCommand({
|
|
|
12042
12403
|
alias: "q",
|
|
12043
12404
|
description: "Query string to execute directly; omit to start REPL mode"
|
|
12044
12405
|
}),
|
|
12406
|
+
file: arg(z.string().optional(), {
|
|
12407
|
+
alias: "f",
|
|
12408
|
+
description: "Read query string from file; omit to start REPL mode"
|
|
12409
|
+
}),
|
|
12410
|
+
edit: arg(z.boolean().default(false), { description: "Open a temporary file in your editor; omit to start REPL mode" }),
|
|
12045
12411
|
machineuser: arg(z.string(), {
|
|
12046
12412
|
alias: "m",
|
|
12047
12413
|
description: "Machine user name for query execution"
|
|
12048
12414
|
})
|
|
12415
|
+
}).superRefine((args, ctx) => {
|
|
12416
|
+
if (args.query != null && args.file != null) ctx.addIssue({
|
|
12417
|
+
code: "custom",
|
|
12418
|
+
path: ["file"],
|
|
12419
|
+
message: "Pass either -q/--query or -f/--file, not both."
|
|
12420
|
+
});
|
|
12421
|
+
if (args.edit && args.query != null) ctx.addIssue({
|
|
12422
|
+
code: "custom",
|
|
12423
|
+
path: ["edit"],
|
|
12424
|
+
message: "Pass only one of --edit, -q/--query, or -f/--file."
|
|
12425
|
+
});
|
|
12426
|
+
if (args.edit && args.file != null) ctx.addIssue({
|
|
12427
|
+
code: "custom",
|
|
12428
|
+
path: ["edit"],
|
|
12429
|
+
message: "Pass only one of --edit, -q/--query, or -f/--file."
|
|
12430
|
+
});
|
|
12049
12431
|
}).strict(),
|
|
12050
12432
|
run: withCommonArgs(async (args) => {
|
|
12051
|
-
const mode = resolveQueryCommandInput({
|
|
12433
|
+
const mode = await resolveQueryCommandInput({
|
|
12434
|
+
query: args.query,
|
|
12435
|
+
file: args.file,
|
|
12436
|
+
edit: args.edit,
|
|
12437
|
+
engine: args.engine
|
|
12438
|
+
});
|
|
12052
12439
|
const sharedOptions = {
|
|
12053
12440
|
workspaceId: args["workspace-id"],
|
|
12054
12441
|
profile: args.profile,
|
|
@@ -12056,7 +12443,11 @@ const queryCommand = defineCommand({
|
|
|
12056
12443
|
engine: args.engine,
|
|
12057
12444
|
machineUser: args.machineuser
|
|
12058
12445
|
};
|
|
12059
|
-
if (mode.
|
|
12446
|
+
if (mode.mode === "abort") {
|
|
12447
|
+
logger.info("Editor closed without a query. Nothing was executed.");
|
|
12448
|
+
return;
|
|
12449
|
+
}
|
|
12450
|
+
if (mode.mode === "repl") {
|
|
12060
12451
|
await runRepl({
|
|
12061
12452
|
...sharedOptions,
|
|
12062
12453
|
json: args.json
|
|
@@ -12154,4 +12545,4 @@ function printGqlResult(result, options = {}) {
|
|
|
12154
12545
|
|
|
12155
12546
|
//#endregion
|
|
12156
12547
|
export { getExecutorJob as $, truncateCommand as A, getMigrationDirPath as At, getCommand$1 as B, getNamespacesWithMigrations as Bt, getAppHealth as C, MIGRATE_FILE_NAME as Ct, listCommand$3 as D, createSnapshotFromLocalTypes as Dt, resumeWorkflow as E, compareSnapshots as Et, showCommand as F, loadDiff as Ft, listMachineUsers as G, commonArgs as Gt, getMachineUserToken as H, generateUserTypes as Ht, remove as I, reconstructSnapshotFromMigrations as It, webhookCommand as J, jsonArgs as Jt, generate$1 as K, confirmationArgs as Kt, removeCommand$1 as L, formatDiffSummary as Lt, generateCommand as M, getMigrationFiles as Mt, logBetaWarning as N, getNextMigrationNumber as Nt, listWorkflows as O, formatMigrationNumber as Ot, show as P, isValidMigrationNumber as Pt, listExecutors as Q, listCommand$4 as R, formatMigrationDiff as Rt, listCommand$2 as S, INITIAL_SCHEMA_NUMBER as St, resumeCommand as T, compareLocalTypesWithSnapshot as Tt, tokenCommand as U, apiCall as Ut, getOAuth2Client as V, trnPrefix as Vt, listCommand$5 as W, apiCommand as Wt, triggerExecutor as X, workspaceArgs as Xt, triggerCommand as Y, withCommonArgs as Yt, listCommand$6 as Z, deleteCommand as _, MIGRATION_LABEL_KEY as _t, removeCommand as a, getCommand$2 as at, createWorkspace as b, DB_TYPES_FILE_NAME as bt, listUsers as c, getWorkflowExecution as ct, restoreCommand as d, formatKeyValueTable as dt, jobsCommand as et, restoreWorkspace as f, getCommand$3 as ft, getWorkspace as g, waitForExecution$1 as gt, getCommand as h, executeScript as ht, updateUser as i, startWorkflow as it, generate as j, getMigrationFilePath as jt, truncate as k, getLatestMigrationNumber as kt, inviteCommand as l, listWorkflowExecutions as lt, listWorkspaces as m, apply as mt, queryCommand as n, watchExecutorJob as nt, removeUser as o, getWorkflow as ot, listCommand$1 as p, getExecutor as pt, listWebhookExecutors as q, deploymentArgs as qt, updateCommand as r, startCommand as rt, listCommand as s, executionsCommand as st, query as t, listExecutorJobs as tt, inviteUser as u, functionExecutionStatusToString as ut, deleteWorkspace as v, parseMigrationLabelNumber as vt, healthCommand as w, SCHEMA_FILE_NAME as wt, listApps as x, DIFF_FILE_NAME as xt, createCommand as y, bundleMigrationScript as yt, listOAuth2Clients as z, hasChanges as zt };
|
|
12157
|
-
//# sourceMappingURL=query-
|
|
12548
|
+
//# sourceMappingURL=query-c9RCJduH.mjs.map
|