@tailor-platform/sdk 1.68.0 → 1.70.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 +105 -0
- package/dist/application-BakHtldG.mjs +4 -0
- package/dist/application-Df5_I83n.mjs +6432 -0
- package/dist/application-Df5_I83n.mjs.map +1 -0
- package/dist/cli/erd-viewer-assets/app.js +279 -36
- package/dist/cli/erd-viewer-assets/index.html +4 -0
- package/dist/cli/erd-viewer-assets/styles.css +252 -5
- package/dist/cli/index.mjs +650 -98
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +247 -160
- package/dist/cli/lib.mjs +3 -3
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/skills.mjs +1 -1
- package/dist/completion/zsh-worker.zsh +175 -24
- package/dist/configure/index.d.mts +5 -5
- package/dist/configure/index.mjs +12 -6
- package/dist/configure/index.mjs.map +1 -1
- package/dist/{crashreport-u9y2npiy.mjs → crashreport-BqyvFk-_.mjs} +2 -2
- package/dist/{crashreport-u9y2npiy.mjs.map → crashreport-BqyvFk-_.mjs.map} +1 -1
- package/dist/{crashreport-6jpCceOF.mjs → crashreport-BwF8cHF0.mjs} +1 -1
- package/dist/enum-constants-C7DaWeQo.mjs.map +1 -1
- package/dist/field-C4zdJLW5.mjs.map +1 -1
- package/dist/file-utils-BHPxPXmn.mjs.map +1 -1
- package/dist/{idp-BlBPtXJ-.d.mts → idp-BmYwCXnJ.d.mts} +30 -3
- package/dist/{idp-BZPqpcYY.mjs → idp-ynUfzwpz.mjs} +9 -1
- package/dist/idp-ynUfzwpz.mjs.map +1 -0
- package/dist/{index-DvEUb3pX.d.mts → index-BAEaAqmz.d.mts} +112 -53
- package/dist/{index-CklcVeMG.d.mts → index-C-vsbx27.d.mts} +2 -2
- package/dist/{index-hXoO-AOC.d.mts → index-CKI0eZP6.d.mts} +2 -2
- package/dist/{index-DYhnxXYR.d.mts → index-CrqOgUF2.d.mts} +2 -2
- package/dist/{index-DlDRSzFZ.d.mts → index-DESLU9kI.d.mts} +2 -2
- package/dist/{index-DRhMpdnA.d.mts → index-dKNk8hjo.d.mts} +2 -2
- package/dist/job-BpsFXPbi.mjs.map +1 -1
- package/dist/{kysely-type-D1e0Vwkd.mjs → kysely-type-CSoZxVKN.mjs} +2 -2
- package/dist/{kysely-type-D1e0Vwkd.mjs.map → kysely-type-CSoZxVKN.mjs.map} +1 -1
- package/dist/{logger-DpJyJvNz.mjs → logger-DKF-JsAK.mjs} +3 -3
- package/dist/{logger-DpJyJvNz.mjs.map → logger-DKF-JsAK.mjs.map} +1 -1
- package/dist/{mock-DMgIygjE.mjs → mock-wf5qeZLi.mjs} +19 -9
- package/dist/mock-wf5qeZLi.mjs.map +1 -0
- package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
- package/dist/plugin/builtin/file-utils/index.d.mts +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/index.d.mts +1 -1
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/registry-D0uB0OrK.mjs.map +1 -1
- package/dist/{repl-editor-CJG3sz7A.mjs → repl-editor-DD5YP5mt.mjs} +4 -4
- package/dist/{repl-editor-CJG3sz7A.mjs.map → repl-editor-DD5YP5mt.mjs.map} +1 -1
- package/dist/runtime/globals.d.mts +3 -2
- package/dist/runtime/idp.d.mts +2 -2
- package/dist/runtime/idp.mjs +1 -1
- package/dist/runtime/index.d.mts +2 -2
- package/dist/runtime/index.mjs +1 -1
- package/dist/{runtime-DxaBq6U8.mjs → runtime-CSY0eD4_.mjs} +411 -221
- package/dist/runtime-CSY0eD4_.mjs.map +1 -0
- package/dist/{schema-1msIhXwA.mjs → schema-C4fkpWV_.mjs} +9 -15
- package/dist/schema-C4fkpWV_.mjs.map +1 -0
- package/dist/seed-YAbtMy65.mjs.map +1 -1
- package/dist/{service-wI3Hvrgx.mjs → service-B2Jd9CxS.mjs} +2 -2
- package/dist/service-B2Jd9CxS.mjs.map +1 -0
- package/dist/service-CRaa4Joe.mjs +4 -0
- package/dist/{service-DMohAx8a.mjs → service-DDWgZL_L2.mjs} +2 -2
- package/dist/service-DDWgZL_L2.mjs.map +1 -0
- package/dist/service_pb-DGSmn-aF.mjs +4 -0
- package/dist/{application-WpWwTyk9.mjs → service_pb-DSNjrcbW.mjs} +22 -6176
- package/dist/service_pb-DSNjrcbW.mjs.map +1 -0
- package/dist/telemetry-BQbbVo2t.mjs.map +1 -1
- package/dist/{types-2Be3wSMc.mjs → types-32lUMToj.mjs} +1 -1
- package/dist/{types-CmzfQP_m.mjs → types-D4QMmNWh.mjs} +1 -12
- package/dist/types-D4QMmNWh.mjs.map +1 -0
- package/dist/{types-Bzr0RQME.d.mts → types-Dynq4AJv.d.mts} +2 -2
- package/dist/{types-DZrtN6-H.d.mts → types-rj8YJcEe.d.mts} +5 -2
- package/dist/utils/test/index.d.mts +2 -2
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/vitest/environment.mjs +1 -1
- package/dist/vitest/environment.mjs.map +1 -1
- package/dist/vitest/index.mjs +4 -4
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/setup.mjs +1 -1
- package/dist/{workflow.generated-1S50BhEb.d.mts → workflow.generated-DJULCuRr.d.mts} +274 -174
- package/docs/cli/application.md +39 -201
- package/docs/cli/auth.md +12 -256
- package/docs/cli/completion.md +0 -24
- package/docs/cli/crashreport.md +0 -58
- package/docs/cli/executor.md +2 -166
- package/docs/cli/function.md +2 -118
- package/docs/cli/organization.md +1 -211
- package/docs/cli/query.md +0 -20
- package/docs/cli/secret.md +70 -250
- package/docs/cli/setup.md +2 -41
- package/docs/cli/skills.md +0 -39
- package/docs/cli/staticwebsite.md +24 -172
- package/docs/cli/tailordb.md +25 -251
- package/docs/cli/upgrade.md +0 -20
- package/docs/cli/user.md +41 -246
- package/docs/cli/workflow.md +30 -189
- package/docs/cli/workspace.md +164 -537
- package/docs/cli-reference.md +61 -37
- package/docs/configuration.md +7 -1
- package/docs/github-actions.md +27 -0
- package/docs/multi-environment.md +22 -0
- package/docs/services/aigateway.md +4 -2
- package/docs/services/http-adapter.md +16 -1
- package/docs/services/idp.md +55 -2
- package/docs/services/staticwebsite.md +7 -1
- package/package.json +23 -18
- package/dist/application-Djeezk3m.mjs +0 -4
- package/dist/application-WpWwTyk9.mjs.map +0 -1
- package/dist/idp-BZPqpcYY.mjs.map +0 -1
- package/dist/mock-DMgIygjE.mjs.map +0 -1
- package/dist/runtime-DxaBq6U8.mjs.map +0 -1
- package/dist/schema-1msIhXwA.mjs.map +0 -1
- package/dist/service-BHQIerYh.mjs +0 -4
- package/dist/service-DMohAx8a.mjs.map +0 -1
- package/dist/service-wI3Hvrgx.mjs.map +0 -1
- package/dist/types-CmzfQP_m.mjs.map +0 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { C as CustomDomainStatus, R as FunctionExecution_Type, ft as AuthInvokerSchema, yt as PATScope } from "../service_pb-DSNjrcbW.mjs";
|
|
4
4
|
import { t as assertDefined } from "../assert-CKfwrmCV.mjs";
|
|
5
|
-
import { n as logger, r as styles } from "../logger-
|
|
6
|
-
import { $
|
|
7
|
-
import {
|
|
5
|
+
import { n as logger, r as styles } from "../logger-DKF-JsAK.mjs";
|
|
6
|
+
import { $t as generateAllTypeManifestsFromSnapshot, A as listCommand$12, An as apiCommand, Bn as paginationArgs, C as listCommand$13, Cn as getNamespacesWithMigrations, Dn as PluginManager, Dt as listCommand$6, E as waitCommand, En as sdkNameLabelKey, F as generateCommand$1, Fn as configArg, G as removeCommand$1, Gt as deploy, H as extractOwnedNamespaces, Hn as workspaceArgs, Ht as formatKeyValueTable, I as generateMigrationScript, In as confirmationArgs, It as getCommand$6, K as updateCommand$3, Kt as executeScript, L as writeDbTypesFile, Ln as deploymentArgs, Mn as assertWritable, N as truncateCommand, Nn as defineAppCommand, O as resumeCommand, On as generateUserTypes, Pn as commonArgs, Pt as startCommand, Q as getCommand$5, Qt as compareSnapshotWithRemote, R as getConfiguredEditorCommand, Rn as isVerbose, Rt as executionsCommand, Sn as hasChanges, T as healthCommand, Tn as resourceTrn, Tt as triggerCommand, U as logBetaWarning, Ut as getCommand$1, V as showCommand, Vn as toPageDirection, Vt as functionExecutionStatusToString, X as listCommand$11, Xt as handleOptionalToRequiredError, Y as treeCommand, Yt as MIGRATION_LABEL_KEY, Zt as parseMigrationLabelNumber, _n as reconstructSnapshotFromMigrations, b as createCommand$4, c as listCommand$14, ct as createCommand$3, en as protoGqlPermission, et as updateCommand$2, f as restoreCommand, fn as getMigrationFilePath, ft as getCommand$3, g as getCommand$7, gn as loadDiff, gt as listCommand$8, hn as isValidMigrationNumber, ht as tokenCommand, i as updateCommand$4, it as getCommand$4, jt as jobsCommand, kn as prompt, ln as createSnapshotFromLocalTypes, m as listCommand$15, nt as listCommand$10, o as removeCommand, on as assertValidMigrationFiles, ot as deleteCommand$3, pn as getMigrationFiles, r as queryCommand, rn as INITIAL_SCHEMA_NUMBER, sn as compareLocalTypesWithSnapshot, t as isNativeTypeScriptRuntime, u as inviteCommand, un as getLatestMigrationNumber, ut as listCommand$9, v as deleteCommand$4, vn as formatMigrationNumber, vt as generate, wn as ensureConfigId, wt as webhookCommand, xn as formatMigrationDiff, xt as getCommand$2, yn as parseMigrationNumberArg, yt as listCommand$7, z as openInConfiguredEditor, zn as pagedLogArgs } from "../runtime-CSY0eD4_.mjs";
|
|
7
|
+
import { $ as initOperatorClient, A as loadAccessToken, B as saveUserTokens, C as hashContent$1, D as fetchLatestToken, E as deleteUserTokens, F as loadStoredUserTokens, H as closeConnectionPool, I as loadWorkspaceId, J as fetchUserInfo, K as fetchPaged, L as platformConfigFromProfile, M as loadConsoleBaseUrl, N as loadMachineUserName, O as hasAnyUserTokenEntry, Q as initOAuth2Client, R as readPlatformConfig, S as getDistDir, T as loadConfig, U as defaultPlatformBaseUrl, V as writePlatformConfig, W as fetchAll, _ as createLogLevelTreeshakeOptions, a as WorkflowJobSchema, c as INVOKER_EXPR, et as isDefaultPlatform, g as composeFunctionTreeshakeOptions, h as platformBundleDefinePlugin, i as resolveInlineSourcemap, k as hasUserTokenEntry, o as ResolverSchema, q as fetchPlatformMachineUserToken, t as defineApplication, v as resolveBundleLogLevel, z as resolveUserTokenKey } from "../application-Df5_I83n.mjs";
|
|
8
|
+
import { n as ExecutorSchema } from "../service-B2Jd9CxS.mjs";
|
|
8
9
|
import { t as multiline } from "../multiline-Cf9ODpr1.mjs";
|
|
9
10
|
import { r as isPluginGeneratedType } from "../seed-YAbtMy65.mjs";
|
|
10
11
|
import { t as readPackageJson } from "../package-json-DcQApfPQ.mjs";
|
|
11
12
|
import { i as userAgent } from "../secret-file-eB3R3Fil.mjs";
|
|
12
13
|
import { n as isCLIError } from "../errors-EsY4XO6O.mjs";
|
|
13
|
-
import { a as JSON_FOOTER_MARKER, i as CRASH_LOG_EXTENSION, o as parseCrashReportConfig, r as sendCrashReport, t as initCrashReporting } from "../crashreport-
|
|
14
|
+
import { a as JSON_FOOTER_MARKER, i as CRASH_LOG_EXTENSION, o as parseCrashReportConfig, r as sendCrashReport, t as initCrashReporting } from "../crashreport-BqyvFk-_.mjs";
|
|
14
15
|
import { arg, defineCommand, runCommand, runMain } from "politty";
|
|
15
16
|
import { withCompletionCommand } from "politty/completion";
|
|
16
17
|
import { z } from "zod";
|
|
@@ -254,7 +255,6 @@ const listAuthConnectionCommand = defineAppCommand({
|
|
|
254
255
|
|
|
255
256
|
//#endregion
|
|
256
257
|
//#region src/cli/commands/authconnection/open.ts
|
|
257
|
-
const consoleBaseUrl$1 = "https://console.tailor.tech";
|
|
258
258
|
const openAuthConnectionCommand = defineAppCommand({
|
|
259
259
|
name: "open",
|
|
260
260
|
description: "Open the auth connections page in the Tailor Platform Console.",
|
|
@@ -265,7 +265,11 @@ const openAuthConnectionCommand = defineAppCommand({
|
|
|
265
265
|
profile: args.profile
|
|
266
266
|
});
|
|
267
267
|
const consolePath = `/workspaces/${workspaceId}/settings/connections`;
|
|
268
|
-
const
|
|
268
|
+
const consoleBaseUrl = await loadConsoleBaseUrl({
|
|
269
|
+
profile: args.profile,
|
|
270
|
+
...args["workspace-id"] !== void 0 ? { allowMissingProfile: true } : {}
|
|
271
|
+
});
|
|
272
|
+
const consoleUrl = new URL(consolePath, consoleBaseUrl).toString();
|
|
269
273
|
const jsonOutput = logger.jsonMode;
|
|
270
274
|
logger.info("Opening auth connections page in Tailor Platform Console...");
|
|
271
275
|
let opened = true;
|
|
@@ -1284,7 +1288,7 @@ async function detectFunctionType(options) {
|
|
|
1284
1288
|
const rawInput = module.default.input;
|
|
1285
1289
|
let inputSchema;
|
|
1286
1290
|
if (rawInput) {
|
|
1287
|
-
const { t } = await import("../types-
|
|
1291
|
+
const { t } = await import("../types-32lUMToj.mjs");
|
|
1288
1292
|
inputSchema = t.object(rawInput);
|
|
1289
1293
|
}
|
|
1290
1294
|
return {
|
|
@@ -1733,8 +1737,15 @@ const redirectUri = `http://localhost:${redirectPort}/callback`;
|
|
|
1733
1737
|
function randomState() {
|
|
1734
1738
|
return crypto.randomBytes(32).toString("base64url");
|
|
1735
1739
|
}
|
|
1736
|
-
|
|
1737
|
-
|
|
1740
|
+
function assertProfileLoginUser(args, authenticatedUser) {
|
|
1741
|
+
if (args.profile && args.profileUser && authenticatedUser !== args.profileUser) throw new Error(`Profile "${args.profile}" is configured for "${args.profileUser}", but login authenticated "${authenticatedUser}".`);
|
|
1742
|
+
}
|
|
1743
|
+
function shouldUpdateCurrentUser(profile, platformConfig) {
|
|
1744
|
+
if (!profile) return true;
|
|
1745
|
+
return isDefaultPlatform(platformConfig);
|
|
1746
|
+
}
|
|
1747
|
+
const startAuthServer = async (args = {}) => {
|
|
1748
|
+
const client = initOAuth2Client(args.platformConfig);
|
|
1738
1749
|
const state = randomState();
|
|
1739
1750
|
const codeVerifier = await generateCodeVerifier();
|
|
1740
1751
|
return new Promise((resolve, reject) => {
|
|
@@ -1746,13 +1757,14 @@ const startAuthServer = async () => {
|
|
|
1746
1757
|
state,
|
|
1747
1758
|
codeVerifier
|
|
1748
1759
|
});
|
|
1749
|
-
const userInfo = await fetchUserInfo(tokens.accessToken);
|
|
1760
|
+
const userInfo = await fetchUserInfo(tokens.accessToken, args.platformConfig);
|
|
1761
|
+
assertProfileLoginUser(args, userInfo.email);
|
|
1750
1762
|
const pfConfig = await readPlatformConfig();
|
|
1751
1763
|
await saveUserTokens(pfConfig, userInfo.email, {
|
|
1752
1764
|
accessToken: tokens.accessToken,
|
|
1753
1765
|
refreshToken: tokens.refreshToken ?? void 0
|
|
1754
|
-
}, new Date(assertDefined(tokens.expiresAt, "token response missing expiresAt")).toISOString());
|
|
1755
|
-
pfConfig.current_user = userInfo.email;
|
|
1766
|
+
}, new Date(assertDefined(tokens.expiresAt, "token response missing expiresAt")).toISOString(), args.platformConfig);
|
|
1767
|
+
if (args.updateCurrentUser ?? true) pfConfig.current_user = userInfo.email;
|
|
1756
1768
|
writePlatformConfig(pfConfig);
|
|
1757
1769
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1758
1770
|
res.end(JSON.stringify({
|
|
@@ -1794,17 +1806,22 @@ const startAuthServer = async () => {
|
|
|
1794
1806
|
});
|
|
1795
1807
|
};
|
|
1796
1808
|
async function loginAsMachineUser(args) {
|
|
1809
|
+
assertProfileLoginUser(args, args.clientId);
|
|
1797
1810
|
const clientSecret = args.clientSecret ?? await prompt.password({ message: "Client secret" });
|
|
1798
|
-
const tokens = await fetchPlatformMachineUserToken(args.clientId, clientSecret);
|
|
1811
|
+
const tokens = await fetchPlatformMachineUserToken(args.clientId, clientSecret, args.platformConfig);
|
|
1799
1812
|
const pfConfig = await readPlatformConfig();
|
|
1800
|
-
await saveUserTokens(pfConfig, args.clientId, { accessToken: tokens.accessToken }, new Date(assertDefined(tokens.expiresAt, "token response missing expiresAt")).toISOString());
|
|
1801
|
-
pfConfig.current_user = args.clientId;
|
|
1813
|
+
await saveUserTokens(pfConfig, args.clientId, { accessToken: tokens.accessToken }, new Date(assertDefined(tokens.expiresAt, "token response missing expiresAt")).toISOString(), args.platformConfig);
|
|
1814
|
+
if (args.updateCurrentUser ?? true) pfConfig.current_user = args.clientId;
|
|
1802
1815
|
writePlatformConfig(pfConfig);
|
|
1803
1816
|
}
|
|
1804
1817
|
const loginCommand = defineAppCommand({
|
|
1805
1818
|
name: "login",
|
|
1806
1819
|
description: "Login to Tailor Platform.",
|
|
1807
|
-
args: z.xor([z.object({
|
|
1820
|
+
args: z.xor([z.object({ profile: arg(z.string().optional(), {
|
|
1821
|
+
alias: "p",
|
|
1822
|
+
description: "Workspace profile whose platform settings should be used for login.",
|
|
1823
|
+
env: "TAILOR_PLATFORM_PROFILE"
|
|
1824
|
+
}) }).strict().describe("User Login"), z.object({
|
|
1808
1825
|
"machine-user": arg(z.literal(true), {
|
|
1809
1826
|
hiddenAlias: "machineuser",
|
|
1810
1827
|
description: "Login as a platform machine user.",
|
|
@@ -1818,14 +1835,37 @@ const loginCommand = defineAppCommand({
|
|
|
1818
1835
|
"client-secret": arg(z.string().optional(), {
|
|
1819
1836
|
description: "Client secret",
|
|
1820
1837
|
env: "TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET"
|
|
1838
|
+
}),
|
|
1839
|
+
profile: arg(z.string().optional(), {
|
|
1840
|
+
alias: "p",
|
|
1841
|
+
description: "Workspace profile whose platform settings should be used for login.",
|
|
1842
|
+
env: "TAILOR_PLATFORM_PROFILE"
|
|
1821
1843
|
})
|
|
1822
1844
|
}).strict().describe("Machine User Login")]),
|
|
1823
1845
|
run: async (args) => {
|
|
1846
|
+
let platformConfig;
|
|
1847
|
+
let profileUser;
|
|
1848
|
+
if ("profile" in args && args.profile) {
|
|
1849
|
+
const profileEntry = (await readPlatformConfig()).profiles[args.profile];
|
|
1850
|
+
if (!profileEntry) throw new Error(`Profile "${args.profile}" not found`);
|
|
1851
|
+
platformConfig = platformConfigFromProfile(profileEntry);
|
|
1852
|
+
profileUser = profileEntry.user;
|
|
1853
|
+
}
|
|
1854
|
+
const updateCurrentUser = shouldUpdateCurrentUser(args.profile, platformConfig);
|
|
1824
1855
|
if ("machine-user" in args) await loginAsMachineUser({
|
|
1825
1856
|
clientId: args.clientId,
|
|
1826
|
-
clientSecret: args.clientSecret
|
|
1857
|
+
clientSecret: args.clientSecret,
|
|
1858
|
+
profile: args.profile,
|
|
1859
|
+
profileUser,
|
|
1860
|
+
platformConfig,
|
|
1861
|
+
updateCurrentUser
|
|
1862
|
+
});
|
|
1863
|
+
else await startAuthServer({
|
|
1864
|
+
profile: args.profile,
|
|
1865
|
+
profileUser,
|
|
1866
|
+
platformConfig,
|
|
1867
|
+
updateCurrentUser
|
|
1827
1868
|
});
|
|
1828
|
-
else await startAuthServer();
|
|
1829
1869
|
logger.success("Successfully logged in to Tailor Platform.");
|
|
1830
1870
|
await closeConnectionPool();
|
|
1831
1871
|
}
|
|
@@ -1836,30 +1876,53 @@ const loginCommand = defineAppCommand({
|
|
|
1836
1876
|
const logoutCommand = defineAppCommand({
|
|
1837
1877
|
name: "logout",
|
|
1838
1878
|
description: "Logout from Tailor Platform.",
|
|
1839
|
-
args: z.object({
|
|
1840
|
-
|
|
1879
|
+
args: z.object({ profile: arg(z.string().optional(), {
|
|
1880
|
+
alias: "p",
|
|
1881
|
+
description: "Workspace profile whose platform settings should be used for logout.",
|
|
1882
|
+
env: "TAILOR_PLATFORM_PROFILE"
|
|
1883
|
+
}) }).strict(),
|
|
1884
|
+
run: async (args) => {
|
|
1885
|
+
const profile = args.profile || process.env.TAILOR_PLATFORM_PROFILE;
|
|
1841
1886
|
const pfConfig = await readPlatformConfig();
|
|
1842
|
-
const
|
|
1843
|
-
|
|
1844
|
-
|
|
1887
|
+
const profileEntry = profile ? pfConfig.profiles[profile] : void 0;
|
|
1888
|
+
if (profile && !profileEntry) throw new Error(`Profile "${profile}" not found`);
|
|
1889
|
+
const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : void 0;
|
|
1890
|
+
const currentUser = profileEntry ? profileEntry.user : pfConfig.current_user;
|
|
1891
|
+
const deletesDefaultToken = isDefaultPlatform(platformConfig);
|
|
1892
|
+
const lookupOptions = profile ? { allowLegacyUserKey: true } : void 0;
|
|
1893
|
+
if (!currentUser) {
|
|
1845
1894
|
logger.info("You are not logged in.");
|
|
1846
1895
|
return;
|
|
1847
1896
|
}
|
|
1897
|
+
const hasDefaultUserToken = () => hasUserTokenEntry(pfConfig, currentUser, { platformUrl: defaultPlatformBaseUrl });
|
|
1898
|
+
const shouldClearCurrentUser = () => pfConfig.current_user === currentUser && (deletesDefaultToken ? !hasDefaultUserToken() : !hasAnyUserTokenEntry(pfConfig, currentUser) && !hasDefaultUserToken());
|
|
1899
|
+
let storedTokens;
|
|
1900
|
+
let tokenLoadFailed = false;
|
|
1848
1901
|
try {
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1902
|
+
storedTokens = await loadStoredUserTokens(pfConfig, currentUser, platformConfig, lookupOptions);
|
|
1903
|
+
} catch (error) {
|
|
1904
|
+
tokenLoadFailed = true;
|
|
1905
|
+
logger.warn(`Failed to revoke token: ${error instanceof Error ? error.message : error}`);
|
|
1906
|
+
}
|
|
1907
|
+
if (!storedTokens && !tokenLoadFailed) {
|
|
1908
|
+
logger.info("You are not logged in.");
|
|
1909
|
+
if (shouldClearCurrentUser()) pfConfig.current_user = null;
|
|
1910
|
+
writePlatformConfig(pfConfig);
|
|
1911
|
+
return;
|
|
1912
|
+
}
|
|
1913
|
+
if (storedTokens) try {
|
|
1914
|
+
const client = initOAuth2Client(platformConfig);
|
|
1915
|
+
const tokenTypeHint = storedTokens.refreshToken ? "refresh_token" : "access_token";
|
|
1852
1916
|
await client.revoke({
|
|
1853
|
-
accessToken,
|
|
1854
|
-
refreshToken: refreshToken ?? null,
|
|
1855
|
-
expiresAt: Date.parse(userEntry.token_expires_at)
|
|
1917
|
+
accessToken: storedTokens.accessToken,
|
|
1918
|
+
refreshToken: storedTokens.refreshToken ?? null,
|
|
1919
|
+
expiresAt: Date.parse(storedTokens.userEntry.token_expires_at)
|
|
1856
1920
|
}, tokenTypeHint);
|
|
1857
1921
|
} catch (error) {
|
|
1858
1922
|
logger.warn(`Failed to revoke token: ${error instanceof Error ? error.message : error}`);
|
|
1859
1923
|
}
|
|
1860
|
-
await deleteUserTokens(pfConfig, currentUser);
|
|
1861
|
-
|
|
1862
|
-
pfConfig.current_user = null;
|
|
1924
|
+
await deleteUserTokens(pfConfig, currentUser, platformConfig, lookupOptions);
|
|
1925
|
+
if (shouldClearCurrentUser()) pfConfig.current_user = null;
|
|
1863
1926
|
writePlatformConfig(pfConfig);
|
|
1864
1927
|
logger.success("Successfully logged out from Tailor Platform.");
|
|
1865
1928
|
}
|
|
@@ -1895,7 +1958,6 @@ const oauth2clientCommand = defineCommand({
|
|
|
1895
1958
|
|
|
1896
1959
|
//#endregion
|
|
1897
1960
|
//#region src/cli/commands/open.ts
|
|
1898
|
-
const consoleBaseUrl = "https://console.tailor.tech";
|
|
1899
1961
|
const openCommand = defineAppCommand({
|
|
1900
1962
|
name: "open",
|
|
1901
1963
|
description: "Open Tailor Platform Console.",
|
|
@@ -1908,6 +1970,10 @@ const openCommand = defineAppCommand({
|
|
|
1908
1970
|
const { config } = await loadConfig(args.config);
|
|
1909
1971
|
const applicationName = config.name;
|
|
1910
1972
|
const consolePath = `/workspaces/${workspaceId}/applications/${encodeURIComponent(applicationName)}/overview`;
|
|
1973
|
+
const consoleBaseUrl = await loadConsoleBaseUrl({
|
|
1974
|
+
profile: args.profile,
|
|
1975
|
+
...args["workspace-id"] !== void 0 ? { allowMissingProfile: true } : {}
|
|
1976
|
+
});
|
|
1911
1977
|
const consoleUrl = new URL(consolePath, consoleBaseUrl).toString();
|
|
1912
1978
|
const jsonOutput = logger.jsonMode;
|
|
1913
1979
|
logger.info("Opening Tailor Platform Console...");
|
|
@@ -1988,13 +2054,31 @@ const createCommand$2 = defineAppCommand({
|
|
|
1988
2054
|
alias: "m",
|
|
1989
2055
|
description: "Default machine user name for application-data commands (query, workflow start, function test-run, machineuser token)."
|
|
1990
2056
|
}),
|
|
1991
|
-
"machine-user-override": arg(z.enum(["allow", "deny"]).optional(), { description: "Whether the command line or TAILOR_PLATFORM_MACHINE_USER_NAME may override the profile's machine user. 'deny' requires --machine-user." })
|
|
2057
|
+
"machine-user-override": arg(z.enum(["allow", "deny"]).optional(), { description: "Whether the command line or TAILOR_PLATFORM_MACHINE_USER_NAME may override the profile's machine user. 'deny' requires --machine-user." }),
|
|
2058
|
+
"platform-url": arg(z.url().optional(), {
|
|
2059
|
+
description: "Platform API base URL for this profile.",
|
|
2060
|
+
env: "TAILOR_PLATFORM_URL"
|
|
2061
|
+
}),
|
|
2062
|
+
"oauth2-client-id": arg(z.string().optional(), {
|
|
2063
|
+
description: "OAuth2 client ID for logging in to this profile's platform.",
|
|
2064
|
+
env: "TAILOR_PLATFORM_OAUTH2_CLIENT_ID"
|
|
2065
|
+
}),
|
|
2066
|
+
"console-url": arg(z.url().optional(), {
|
|
2067
|
+
description: "Console base URL for this profile.",
|
|
2068
|
+
env: "TAILOR_PLATFORM_CONSOLE_URL"
|
|
2069
|
+
})
|
|
1992
2070
|
}).strict(),
|
|
1993
2071
|
run: async (args) => {
|
|
1994
2072
|
if (args["machine-user-override"] === "deny" && !args["machine-user"]) throw new Error("--machine-user-override deny requires --machine-user.");
|
|
1995
2073
|
const config = await readPlatformConfig();
|
|
1996
2074
|
if (config.profiles[args.name]) throw new Error(`Profile "${args.name}" already exists.`);
|
|
1997
|
-
const
|
|
2075
|
+
const platformConfigInput = {
|
|
2076
|
+
...args["platform-url"] ? { platformUrl: args["platform-url"] } : {},
|
|
2077
|
+
...args["oauth2-client-id"] ? { oauth2ClientId: args["oauth2-client-id"] } : {},
|
|
2078
|
+
...args["console-url"] ? { consoleUrl: args["console-url"] } : {}
|
|
2079
|
+
};
|
|
2080
|
+
const platformConfig = Object.keys(platformConfigInput).length > 0 ? platformConfigInput : void 0;
|
|
2081
|
+
const client = await initOperatorClient(await fetchLatestToken(config, args.user, platformConfig), platformConfig);
|
|
1998
2082
|
if (!(await fetchAll(async (pageToken, maxPageSize) => {
|
|
1999
2083
|
const { workspaces, nextPageToken } = await client.listWorkspaces({
|
|
2000
2084
|
pageToken,
|
|
@@ -2007,7 +2091,10 @@ const createCommand$2 = defineAppCommand({
|
|
|
2007
2091
|
workspace_id: args["workspace-id"],
|
|
2008
2092
|
...args.permission === "read" ? { readonly: true } : {},
|
|
2009
2093
|
...args["machine-user"] ? { machine_user: args["machine-user"] } : {},
|
|
2010
|
-
...args["machine-user-override"] === "deny" ? { machine_user_override: "deny" } : {}
|
|
2094
|
+
...args["machine-user-override"] === "deny" ? { machine_user_override: "deny" } : {},
|
|
2095
|
+
...args["platform-url"] ? { platform_url: args["platform-url"] } : {},
|
|
2096
|
+
...args["oauth2-client-id"] ? { oauth2_client_id: args["oauth2-client-id"] } : {},
|
|
2097
|
+
...args["console-url"] ? { console_url: args["console-url"] } : {}
|
|
2011
2098
|
};
|
|
2012
2099
|
writePlatformConfig(config);
|
|
2013
2100
|
if (!args.json) logger.success(`Profile "${args.name}" created successfully.`);
|
|
@@ -2019,7 +2106,10 @@ const createCommand$2 = defineAppCommand({
|
|
|
2019
2106
|
...args["machine-user"] ? {
|
|
2020
2107
|
machineUser: args["machine-user"],
|
|
2021
2108
|
machineUserOverride: args["machine-user-override"] ?? "allow"
|
|
2022
|
-
} : {}
|
|
2109
|
+
} : {},
|
|
2110
|
+
...args["platform-url"] ? { platformUrl: args["platform-url"] } : {},
|
|
2111
|
+
...args["oauth2-client-id"] ? { oauth2ClientId: args["oauth2-client-id"] } : {},
|
|
2112
|
+
...args["console-url"] ? { consoleUrl: args["console-url"] } : {}
|
|
2023
2113
|
};
|
|
2024
2114
|
logger.out(profileInfo);
|
|
2025
2115
|
}
|
|
@@ -2071,7 +2161,10 @@ const listCommand$4 = defineAppCommand({
|
|
|
2071
2161
|
...p.machine_user ? {
|
|
2072
2162
|
machineUser: p.machine_user,
|
|
2073
2163
|
machineUserOverride: p.machine_user_override ?? "allow"
|
|
2074
|
-
} : {}
|
|
2164
|
+
} : {},
|
|
2165
|
+
...p.platform_url ? { platformUrl: p.platform_url } : {},
|
|
2166
|
+
...p.oauth2_client_id ? { oauth2ClientId: p.oauth2_client_id } : {},
|
|
2167
|
+
...p.console_url ? { consoleUrl: p.console_url } : {}
|
|
2075
2168
|
};
|
|
2076
2169
|
});
|
|
2077
2170
|
logger.out(profileInfos);
|
|
@@ -2101,25 +2194,38 @@ const updateCommand$1 = defineAppCommand({
|
|
|
2101
2194
|
alias: "m",
|
|
2102
2195
|
description: "Default machine user name for application-data commands (query, workflow start, function test-run, machineuser token). Pass an empty string to clear."
|
|
2103
2196
|
}),
|
|
2104
|
-
"machine-user-override": arg(z.enum(["allow", "deny"]).optional(), { description: "Whether the command line or TAILOR_PLATFORM_MACHINE_USER_NAME may override the profile's machine user. 'deny' requires --machine-user; 'allow' lifts the restriction." })
|
|
2197
|
+
"machine-user-override": arg(z.enum(["allow", "deny"]).optional(), { description: "Whether the command line or TAILOR_PLATFORM_MACHINE_USER_NAME may override the profile's machine user. 'deny' requires --machine-user; 'allow' lifts the restriction." }),
|
|
2198
|
+
"platform-url": arg(z.union([z.url(), z.literal("")]).optional(), { description: "Platform API base URL for this profile. Pass an empty string to clear." }),
|
|
2199
|
+
"oauth2-client-id": arg(z.string().optional(), { description: "OAuth2 client ID for logging in to this profile's platform. Pass an empty string to clear." }),
|
|
2200
|
+
"console-url": arg(z.union([z.url(), z.literal("")]).optional(), { description: "Console base URL for this profile. Pass an empty string to clear." })
|
|
2105
2201
|
}).strict(),
|
|
2106
2202
|
run: async (args) => {
|
|
2107
2203
|
const config = await readPlatformConfig();
|
|
2108
2204
|
const profile = config.profiles[args.name];
|
|
2109
2205
|
if (!profile) throw new Error(`Profile "${args.name}" not found.`);
|
|
2110
|
-
if (!args.user && !args["workspace-id"] && args.permission === void 0 && args["machine-user"] === void 0 && args["machine-user-override"] === void 0) throw new Error("Please provide at least one property to update.");
|
|
2206
|
+
if (!args.user && !args["workspace-id"] && args.permission === void 0 && args["machine-user"] === void 0 && args["machine-user-override"] === void 0 && args["platform-url"] === void 0 && args["oauth2-client-id"] === void 0 && args["console-url"] === void 0) throw new Error("Please provide at least one property to update.");
|
|
2111
2207
|
const oldUser = profile.user;
|
|
2112
2208
|
const newUser = args.user || oldUser;
|
|
2113
2209
|
const oldWorkspaceId = profile.workspace_id;
|
|
2114
2210
|
const newWorkspaceId = args["workspace-id"] || oldWorkspaceId;
|
|
2115
2211
|
const finalMachineUser = args["machine-user"] === "" ? void 0 : args["machine-user"] ?? profile.machine_user;
|
|
2116
2212
|
const finalOverride = args["machine-user-override"] === "allow" ? void 0 : args["machine-user-override"] ?? profile.machine_user_override;
|
|
2213
|
+
const finalPlatformUrl = args["platform-url"] === "" ? void 0 : args["platform-url"] ?? profile.platform_url;
|
|
2214
|
+
const finalOAuth2ClientId = args["oauth2-client-id"] === "" ? void 0 : args["oauth2-client-id"] ?? profile.oauth2_client_id;
|
|
2215
|
+
const finalConsoleUrl = args["console-url"] === "" ? void 0 : args["console-url"] ?? profile.console_url;
|
|
2216
|
+
const finalPlatformConfigInput = {
|
|
2217
|
+
...finalPlatformUrl ? { platformUrl: finalPlatformUrl } : {},
|
|
2218
|
+
...finalOAuth2ClientId ? { oauth2ClientId: finalOAuth2ClientId } : {},
|
|
2219
|
+
...finalConsoleUrl ? { consoleUrl: finalConsoleUrl } : {}
|
|
2220
|
+
};
|
|
2221
|
+
const finalPlatformConfig = Object.keys(finalPlatformConfigInput).length > 0 ? finalPlatformConfigInput : void 0;
|
|
2222
|
+
const tokenLookupPlatformConfig = args["platform-url"] === "" ? platformConfigFromProfile(profile) : finalPlatformConfig;
|
|
2117
2223
|
if ((args["machine-user"] !== void 0 || args["machine-user-override"] !== void 0) && finalOverride === "deny" && !finalMachineUser) {
|
|
2118
2224
|
if (args["machine-user-override"] === "deny") throw new Error("--machine-user-override deny requires --machine-user.");
|
|
2119
2225
|
throw new Error(`Cannot clear the machine user while machine-user-override is "deny". Also pass --machine-user-override allow.`);
|
|
2120
2226
|
}
|
|
2121
|
-
if (args.user !== void 0 || args["workspace-id"] !== void 0) {
|
|
2122
|
-
const client = await initOperatorClient(await fetchLatestToken(config, newUser));
|
|
2227
|
+
if (args.user !== void 0 || args["workspace-id"] !== void 0 || args["platform-url"] !== void 0) {
|
|
2228
|
+
const client = await initOperatorClient(await fetchLatestToken(config, newUser, tokenLookupPlatformConfig), finalPlatformConfig);
|
|
2123
2229
|
if (!(await fetchAll(async (pageToken, maxPageSize) => {
|
|
2124
2230
|
const { workspaces, nextPageToken } = await client.listWorkspaces({
|
|
2125
2231
|
pageToken,
|
|
@@ -2136,6 +2242,12 @@ const updateCommand$1 = defineAppCommand({
|
|
|
2136
2242
|
else profile.machine_user = args["machine-user"];
|
|
2137
2243
|
if (args["machine-user-override"] === "deny") profile.machine_user_override = "deny";
|
|
2138
2244
|
else if (args["machine-user-override"] === "allow") delete profile.machine_user_override;
|
|
2245
|
+
if (args["platform-url"] !== void 0) if (args["platform-url"] === "") delete profile.platform_url;
|
|
2246
|
+
else profile.platform_url = args["platform-url"];
|
|
2247
|
+
if (args["oauth2-client-id"] !== void 0) if (args["oauth2-client-id"] === "") delete profile.oauth2_client_id;
|
|
2248
|
+
else profile.oauth2_client_id = args["oauth2-client-id"];
|
|
2249
|
+
if (args["console-url"] !== void 0) if (args["console-url"] === "") delete profile.console_url;
|
|
2250
|
+
else profile.console_url = args["console-url"];
|
|
2139
2251
|
writePlatformConfig(config);
|
|
2140
2252
|
if (!args.json) logger.success(`Profile "${args.name}" updated successfully`);
|
|
2141
2253
|
const profileInfo = {
|
|
@@ -2146,7 +2258,10 @@ const updateCommand$1 = defineAppCommand({
|
|
|
2146
2258
|
...profile.machine_user ? {
|
|
2147
2259
|
machineUser: profile.machine_user,
|
|
2148
2260
|
machineUserOverride: profile.machine_user_override ?? "allow"
|
|
2149
|
-
} : {}
|
|
2261
|
+
} : {},
|
|
2262
|
+
...profile.platform_url ? { platformUrl: profile.platform_url } : {},
|
|
2263
|
+
...profile.oauth2_client_id ? { oauth2ClientId: profile.oauth2_client_id } : {},
|
|
2264
|
+
...profile.console_url ? { consoleUrl: profile.console_url } : {}
|
|
2150
2265
|
};
|
|
2151
2266
|
logger.out(profileInfo);
|
|
2152
2267
|
}
|
|
@@ -2707,11 +2822,11 @@ function findTarget(lock, kind, workspaceName) {
|
|
|
2707
2822
|
|
|
2708
2823
|
//#endregion
|
|
2709
2824
|
//#region src/cli/commands/setup/branch.workflow.yml
|
|
2710
|
-
var branch_workflow_default = "# __HEADER__\nname: Tailor (__WORKSPACE_NAME__)\n\non:\n # __PULL_REQUEST_START__\n pull_request:\n branches: [\"__BRANCH__\"]\n # __PATHS__\n # __PULL_REQUEST_END__\n push:\n branches: [\"__BRANCH__\"]\n # __PATHS__\n workflow_dispatch:\n # __DISPATCH_INPUTS_START__\n inputs:\n dry-run:\n description: Preview changes without deploying\n type: boolean\n default: false\n # __DISPATCH_INPUTS_END__\n\npermissions:\n contents: read\n\njobs:\n # __PLAN_JOB_START__\n tailor-plan:\n if: >-\n github.event_name == 'pull_request' ||\n (github.event_name == 'workflow_dispatch' && inputs['dry-run'])\n runs-on: ubuntu-latest\n timeout-minutes: 30\n environment: __ENVIRONMENT__\n permissions:\n contents: read\n pull-requests: write\n concurrency:\n group: tailor-plan-__WORKSPACE_NAME__-${{ github.event.pull_request.number || github.run_id }}\n cancel-in-progress: true\n steps:\n - id: tailor-checkout\n uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3\n - id: tailor-setup\n uses: tailor-platform/actions/setup@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n package-manager: __PACKAGE_MANAGER__\n - id: tailor-generate-check\n uses: tailor-platform/actions/generate-check@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n package-manager: __PACKAGE_MANAGER__\n # __WORKING_DIRECTORY__\n - id: tailor-plan\n # Fork PRs cannot read secrets; the checks above still run for them.\n if: github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork\n uses: tailor-platform/actions/plan@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}\n package-manager: __PACKAGE_MANAGER__\n label: __WORKSPACE_NAME__\n # __WORKING_DIRECTORY__\n platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}\n platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}\n github-token: ${{ secrets.GITHUB_TOKEN }}\n # __PLAN_JOB_END__\n tailor-deploy:\n # __DEPLOY_IF__\n runs-on: ubuntu-latest\n timeout-minutes: 30\n permissions:\n contents: read\n environment: __ENVIRONMENT__\n concurrency:\n group: tailor-deploy-__WORKSPACE_NAME__\n cancel-in-progress: false\n steps:\n - id: tailor-checkout\n uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3\n - id: tailor-setup\n uses: tailor-platform/actions/setup@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n package-manager: __PACKAGE_MANAGER__\n - id: tailor-apply\n uses: tailor-platform/actions/deploy@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}\n package-manager: __PACKAGE_MANAGER__\n # __WORKING_DIRECTORY__\n platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}\n platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}\n";
|
|
2825
|
+
var branch_workflow_default = "# __HEADER__\nname: Tailor (__WORKSPACE_NAME__)\n\non:\n # __PULL_REQUEST_START__\n pull_request:\n branches: [\"__BRANCH__\"]\n # __PATHS__\n # __PULL_REQUEST_END__\n push:\n branches: [\"__BRANCH__\"]\n # __PATHS__\n workflow_dispatch:\n # __DISPATCH_INPUTS_START__\n inputs:\n dry-run:\n description: Preview changes without deploying\n type: boolean\n default: false\n # __DISPATCH_INPUTS_END__\n\npermissions:\n contents: read\n\njobs:\n # __PLAN_JOB_START__\n tailor-plan:\n if: >-\n github.event_name == 'pull_request' ||\n (github.event_name == 'workflow_dispatch' && inputs['dry-run'])\n runs-on: ubuntu-latest\n timeout-minutes: 30\n environment: __ENVIRONMENT__\n permissions:\n contents: read\n pull-requests: write\n concurrency:\n group: tailor-plan-__WORKSPACE_NAME__-${{ github.event.pull_request.number || github.run_id }}\n cancel-in-progress: true\n steps:\n - id: tailor-checkout\n uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n - id: tailor-setup\n uses: tailor-platform/actions/setup@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n package-manager: __PACKAGE_MANAGER__\n - id: tailor-generate-check\n uses: tailor-platform/actions/generate-check@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n package-manager: __PACKAGE_MANAGER__\n # __WORKING_DIRECTORY__\n - id: tailor-plan\n # Fork PRs cannot read secrets; the checks above still run for them.\n if: github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork\n uses: tailor-platform/actions/plan@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}\n package-manager: __PACKAGE_MANAGER__\n label: __WORKSPACE_NAME__\n # __WORKING_DIRECTORY__\n platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}\n platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}\n github-token: ${{ secrets.GITHUB_TOKEN }}\n # __PLAN_JOB_END__\n # __ERD_PREVIEW_JOB_START__\n tailor-erd-preview-matrix:\n if: github.event_name == 'pull_request'\n runs-on: ubuntu-latest\n timeout-minutes: 5\n permissions:\n contents: read\n outputs:\n namespaces: ${{ steps.tailor-erd-preview-matrix.outputs.namespaces }}\n base-app-dir: ${{ steps.tailor-erd-preview-matrix.outputs['base-app-dir'] }}\n steps:\n - id: tailor-checkout\n uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n with:\n persist-credentials: false\n - id: tailor-checkout-base\n uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n with:\n repository: ${{ github.event.pull_request.base.repo.full_name }}\n ref: ${{ github.event.pull_request.base.sha }}\n path: .tailor-erd-base\n persist-credentials: false\n - id: tailor-erd-preview-matrix\n shell: bash\n env:\n APP_DIR: \"__APP_DIR__\"\n WORKSPACE_NAME: \"__WORKSPACE_NAME__\"\n run: |\n set -euo pipefail\n node <<'NODE'\n const fs = require(\"node:fs\");\n\n const appDir = process.env.APP_DIR || \".\";\n const workspaceName = process.env.WORKSPACE_NAME;\n const output = process.env.GITHUB_OUTPUT;\n const dirPattern = /^[A-Za-z0-9._/-]+$/;\n const namespacePattern = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\n\n function lockTarget(file) {\n try {\n const lock = JSON.parse(fs.readFileSync(file, \"utf8\"));\n return lock.targets?.find(\n (candidate) =>\n candidate.kind === \"branch\" &&\n candidate.workspaceName === workspaceName,\n );\n } catch (error) {\n if (error && error.code === \"ENOENT\") return undefined;\n throw error;\n }\n }\n\n function namespacesFromTarget(target, label) {\n const namespaces =\n target?.inputs?.erdPreview === true && Array.isArray(target.inputs?.erdNamespaces)\n ? target.inputs.erdNamespaces\n : [];\n for (const namespace of namespaces) {\n if (typeof namespace !== \"string\" || !namespacePattern.test(namespace)) {\n throw new Error(`Invalid ERD namespace in ${label}: ${String(namespace)}`);\n }\n }\n return namespaces;\n }\n\n function normalizeDir(value, label) {\n const raw = typeof value === \"string\" && value.length > 0 ? value : appDir;\n const normalized =\n raw.replaceAll(\"\\\\\", \"/\").replace(/\\/{2,}/g, \"/\").replace(/^\\.\\//, \"\").replace(/\\/$/, \"\") ||\n \".\";\n if (\n !dirPattern.test(normalized) ||\n normalized.startsWith(\"/\") ||\n normalized.split(\"/\").includes(\"..\")\n ) {\n throw new Error(`Invalid ERD app dir in ${label}: ${raw}`);\n }\n return normalized;\n }\n\n const headTarget = lockTarget(\".github/tailor-sdk.lock\");\n const baseTarget = lockTarget(\".tailor-erd-base/.github/tailor-sdk.lock\");\n const baseAppDir = normalizeDir(baseTarget?.inputs?.dir, \"base setup lock\");\n const namespaces = [\n ...new Set([\n ...namespacesFromTarget(headTarget, \"head setup lock\"),\n ...namespacesFromTarget(baseTarget, \"base setup lock\"),\n ]),\n ].sort((a, b) => a.localeCompare(b));\n\n if (namespaces.length === 0) {\n console.error(\"No ERD preview namespaces found in the head or base setup lock.\");\n process.exit(1);\n }\n\n fs.appendFileSync(output, `namespaces=${JSON.stringify(namespaces)}\\n`);\n fs.appendFileSync(output, `base-app-dir=${baseAppDir}\\n`);\n NODE\n\n tailor-erd-preview:\n needs: tailor-erd-preview-matrix\n if: github.event_name == 'pull_request'\n runs-on: ubuntu-latest\n timeout-minutes: 15\n permissions:\n contents: read\n strategy:\n fail-fast: false\n matrix:\n namespace: ${{ fromJSON(needs.tailor-erd-preview-matrix.outputs.namespaces) }}\n steps:\n - id: tailor-checkout\n uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n with:\n persist-credentials: false\n - id: tailor-setup\n uses: tailor-platform/actions/setup@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n package-manager: __PACKAGE_MANAGER__\n - id: tailor-checkout-base\n uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n with:\n repository: ${{ github.event.pull_request.base.repo.full_name }}\n ref: ${{ github.event.pull_request.base.sha }}\n path: .tailor-erd-base\n persist-credentials: false\n - id: tailor-detect-base-package-manager\n shell: bash\n run: |\n set -euo pipefail\n cd .tailor-erd-base\n base_package_manager=\"$(\n if [ -f pnpm-lock.yaml ]; then\n echo pnpm\n elif [ -f yarn.lock ]; then\n echo yarn\n elif [ -f bun.lockb ] || [ -f bun.lock ]; then\n echo bun\n elif [ -f package-lock.json ]; then\n echo npm\n else\n echo \"__PACKAGE_MANAGER__\"\n fi\n )\"\n echo \"package-manager=$base_package_manager\" >> \"$GITHUB_OUTPUT\"\n if [ \"$base_package_manager\" = \"pnpm\" ]; then\n base_pnpm_version=\"$(node <<'NODE'\n const fs = require(\"node:fs\");\n\n const fallback = \"10\";\n\n function readManifest(file) {\n try {\n return JSON.parse(fs.readFileSync(file, \"utf8\"));\n } catch {\n return {};\n }\n }\n\n function pnpmVersion(manifest) {\n const packageManager = manifest.packageManager;\n if (typeof packageManager === \"string\" && packageManager.startsWith(\"pnpm@\")) {\n return packageManager.slice(\"pnpm@\".length).split(\"+\")[0];\n }\n\n const devPackageManager = manifest.devEngines?.packageManager;\n if (devPackageManager?.name === \"pnpm\" && devPackageManager.version) {\n return devPackageManager.version;\n }\n\n return undefined;\n }\n\n process.stdout.write(\n pnpmVersion(readManifest(\"package.json\")) ?? fallback,\n );\n NODE\n )\"\n echo \"pnpm-version=$base_pnpm_version\" >> \"$GITHUB_OUTPUT\"\n fi\n - id: tailor-setup-base-pnpm\n if: steps.tailor-detect-base-package-manager.outputs['package-manager'] == 'pnpm'\n uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9\n with:\n version: ${{ steps.tailor-detect-base-package-manager.outputs['pnpm-version'] }}\n package_json_file: .tailor-erd-base/package.json\n run_install: false\n - id: tailor-setup-base-node\n if: steps.tailor-detect-base-package-manager.outputs['package-manager'] != 'bun'\n uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0\n with:\n node-version-file: .tailor-erd-base/package.json\n - id: tailor-setup-base-yarn\n if: steps.tailor-detect-base-package-manager.outputs['package-manager'] == 'yarn'\n shell: bash\n working-directory: .tailor-erd-base\n run: |\n set -euo pipefail\n corepack enable\n - id: tailor-setup-base-bun\n if: steps.tailor-detect-base-package-manager.outputs['package-manager'] == 'bun'\n uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0\n - id: tailor-install-base\n shell: bash\n working-directory: .tailor-erd-base\n env:\n BASE_PACKAGE_MANAGER: ${{ steps.tailor-detect-base-package-manager.outputs['package-manager'] }}\n run: |\n set -euo pipefail\n case \"$BASE_PACKAGE_MANAGER\" in\n pnpm) pnpm install --frozen-lockfile ;;\n npm) npm ci ;;\n yarn)\n if grep -q '^__metadata:' yarn.lock; then\n yarn install --immutable\n else\n yarn install --frozen-lockfile\n fi\n ;;\n bun) bun install --frozen-lockfile ;;\n *)\n echo \"::error::Unsupported base package-manager '$BASE_PACKAGE_MANAGER' (expected pnpm, npm, yarn, or bun)\"\n exit 1\n ;;\n esac\n - id: tailor-restore-head-setup\n uses: tailor-platform/actions/setup@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n package-manager: __PACKAGE_MANAGER__\n - id: tailor-build-erd-preview\n shell: bash\n env:\n APP_DIR: \"__APP_DIR__\"\n BASE_APP_DIR: ${{ needs.tailor-erd-preview-matrix.outputs['base-app-dir'] }}\n BASE_PACKAGE_MANAGER: ${{ steps.tailor-detect-base-package-manager.outputs['package-manager'] }}\n NAMESPACE: ${{ matrix.namespace }}\n run: |\n set -euo pipefail\n\n run_tailor_sdk() {\n case \"__PACKAGE_MANAGER__\" in\n pnpm) pnpm exec tailor-sdk \"$@\" ;;\n npm) npx tailor-sdk \"$@\" ;;\n yarn) yarn tailor-sdk \"$@\" ;;\n bun) bunx tailor-sdk \"$@\" ;;\n *)\n echo \"::error::Unsupported package-manager '__PACKAGE_MANAGER__' (expected pnpm, npm, yarn, or bun)\"\n exit 1\n ;;\n esac\n }\n\n run_head_node() {\n case \"__PACKAGE_MANAGER__\" in\n pnpm) pnpm exec node \"$@\" ;;\n npm) node \"$@\" ;;\n yarn) yarn node \"$@\" ;;\n bun) node \"$@\" ;;\n *)\n echo \"::error::Unsupported package-manager '__PACKAGE_MANAGER__' (expected pnpm, npm, yarn, or bun)\"\n exit 1\n ;;\n esac\n }\n\n tailor_sdk_bin=\"$(\n run_head_node - <<'NODE'\n const path = require(\"node:path\");\n const { createRequire } = require(\"node:module\");\n const appDir = process.env.APP_DIR || \".\";\n const githubWorkspace = process.env.GITHUB_WORKSPACE;\n if (!githubWorkspace) {\n throw new Error(\"GITHUB_WORKSPACE is required.\");\n }\n\n let lastError;\n for (const manifestPath of [\n path.join(githubWorkspace, appDir, \"package.json\"),\n path.join(githubWorkspace, \"package.json\"),\n ]) {\n try {\n const requireFromManifest = createRequire(manifestPath);\n process.stdout.write(\n path.join(\n path.dirname(requireFromManifest.resolve(\"@tailor-platform/sdk/cli\")),\n \"index.mjs\",\n ),\n );\n process.exit(0);\n } catch (error) {\n lastError = error;\n }\n }\n throw lastError || new Error(\"Failed to resolve @tailor-platform/sdk/cli.\");\n NODE\n )\"\n\n run_head_tailor_sdk_bin() {\n local command_cwd=\"$1\"\n shift\n\n run_head_cli_env() {\n env TAILOR_SDK_BIN=\"$tailor_sdk_bin\" TAILOR_SDK_CWD=\"$command_cwd\" \"$@\"\n }\n\n (\n cd \"$GITHUB_WORKSPACE\" || exit 1\n case \"__PACKAGE_MANAGER__\" in\n pnpm) run_head_cli_env pnpm exec node \"$head_cli_runner\" \"$@\" ;;\n npm) run_head_cli_env node \"$head_cli_runner\" \"$@\" ;;\n yarn) run_head_cli_env yarn node \"$head_cli_runner\" \"$@\" ;;\n bun) run_head_cli_env bun \"$head_cli_runner\" \"$@\" ;;\n *)\n echo \"::error::Unsupported package-manager '__PACKAGE_MANAGER__' (expected pnpm, npm, yarn, or bun)\"\n exit 1\n ;;\n esac\n )\n }\n\n run_base_tailor_sdk_bin() {\n local command_cwd=\"$1\"\n shift\n\n run_head_cli_env() {\n env TAILOR_SDK_BIN=\"$tailor_sdk_bin\" TAILOR_SDK_CWD=\"$command_cwd\" \"$@\"\n }\n\n (\n cd \"$command_cwd\" || exit 1\n case \"$BASE_PACKAGE_MANAGER\" in\n pnpm) run_head_cli_env pnpm exec node \"$head_cli_runner\" \"$@\" ;;\n npm) run_head_cli_env node \"$head_cli_runner\" \"$@\" ;;\n yarn) run_head_cli_env yarn node \"$head_cli_runner\" \"$@\" ;;\n bun) run_head_cli_env bun \"$head_cli_runner\" \"$@\" ;;\n *)\n echo \"::error::Unsupported base package-manager '$BASE_PACKAGE_MANAGER' (expected pnpm, npm, yarn, or bun)\"\n exit 1\n ;;\n esac\n )\n }\n\n head_output=\"$RUNNER_TEMP/tailor-erd/head\"\n base_output=\"$RUNNER_TEMP/tailor-erd/base\"\n preview_output=\"$RUNNER_TEMP/tailor-erd/preview\"\n dts_output=\"$RUNNER_TEMP/tailor-erd/dts\"\n head_cli_runner=\"$RUNNER_TEMP/tailor-erd/run-head-tailor-sdk.mjs\"\n head_log=\"$RUNNER_TEMP/tailor-erd/head-$NAMESPACE.log\"\n base_log=\"$RUNNER_TEMP/tailor-erd/base-$NAMESPACE.log\"\n rm -rf \"$head_output\" \"$base_output\" \"$preview_output\" \"$dts_output\"\n mkdir -p \"$head_output\" \"$base_output\" \"$preview_output\" \"$dts_output\"\n cat > \"$head_cli_runner\" <<'NODE'\n import { pathToFileURL } from \"node:url\";\n\n const cliBin = process.env.TAILOR_SDK_BIN;\n const commandCwd = process.env.TAILOR_SDK_CWD;\n if (!cliBin || !commandCwd) {\n throw new Error(\"TAILOR_SDK_BIN and TAILOR_SDK_CWD are required.\");\n }\n\n process.chdir(commandCwd);\n process.argv = [process.argv[0], cliBin, ...process.argv.slice(2)];\n await import(pathToFileURL(cliBin).href);\n NODE\n\n head_config=\"$GITHUB_WORKSPACE/$APP_DIR/tailor.config.ts\"\n base_config=\"$GITHUB_WORKSPACE/.tailor-erd-base/$BASE_APP_DIR/tailor.config.ts\"\n head_html=\"$head_output/$NAMESPACE/dist/index.html\"\n base_html=\"$base_output/$NAMESPACE/dist/index.html\"\n preview_html=\"$preview_output/$NAMESPACE-viewer.html\"\n\n head_missing=\"false\"\n if [ ! -f \"$head_config\" ]; then\n echo \"Head ERD config not found; rendering base objects as removed.\"\n head_missing=\"true\"\n elif ! (\n cd \"$GITHUB_WORKSPACE/$APP_DIR\" || exit 1\n TAILOR_PLATFORM_SDK_DTS_PATH=\"$dts_output/head-$NAMESPACE.d.ts\" \\\n run_tailor_sdk tailordb erd export --config \"$head_config\" --namespace \"$NAMESPACE\" --output \"$head_output\"\n ) >\"$head_log\" 2>&1; then\n if grep -q 'not found in local config.db' \"$head_log\"; then\n cat \"$head_log\"\n echo \"Head ERD namespace '$NAMESPACE' not found; rendering base objects as removed.\"\n head_missing=\"true\"\n else\n cat \"$head_log\"\n exit 1\n fi\n elif [ -s \"$head_log\" ]; then\n cat \"$head_log\"\n fi\n\n base_missing=\"false\"\n if [ ! -f \"$base_config\" ]; then\n echo \"Base ERD config not found; rendering current objects as added.\"\n base_missing=\"true\"\n elif ! (\n TAILOR_PLATFORM_SDK_DTS_PATH=\"$dts_output/base-$NAMESPACE.d.ts\" \\\n run_base_tailor_sdk_bin \"$GITHUB_WORKSPACE/.tailor-erd-base/$BASE_APP_DIR\" tailordb erd export --config \"$base_config\" --namespace \"$NAMESPACE\" --output \"$base_output\"\n ) >\"$base_log\" 2>&1; then\n if grep -q 'not found in local config.db' \"$base_log\"; then\n cat \"$base_log\"\n echo \"Base ERD namespace '$NAMESPACE' not found; rendering current objects as added.\"\n base_missing=\"true\"\n else\n cat \"$base_log\"\n exit 1\n fi\n elif [ -s \"$base_log\" ]; then\n cat \"$base_log\"\n fi\n\n if [ \"$head_missing\" = \"true\" ] && [ \"$base_missing\" = \"true\" ]; then\n echo \"::error::ERD namespace '$NAMESPACE' was not found in head or base.\"\n exit 1\n fi\n if [ \"$head_missing\" = \"false\" ] && [ ! -f \"$head_html\" ]; then\n echo \"::error::Head ERD viewer was not generated at $head_html\"\n exit 1\n fi\n if [ \"$base_missing\" = \"false\" ] && [ ! -f \"$base_html\" ]; then\n echo \"::error::Base ERD viewer was not generated at $base_html\"\n exit 1\n fi\n\n diff_args=(--namespace \"$NAMESPACE\" --output \"$preview_html\")\n if [ \"$head_missing\" = \"false\" ]; then\n diff_args+=(--head-html \"$head_html\")\n fi\n if [ \"$base_missing\" = \"false\" ]; then\n diff_args+=(--base-html \"$base_html\")\n fi\n run_head_tailor_sdk_bin \"$GITHUB_WORKSPACE\" tailordb erd diff \"${diff_args[@]}\"\n - id: tailor-upload-erd-viewer\n uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1\n with:\n name: ${{ matrix.namespace }}-viewer.html\n path: ${{ runner.temp }}/tailor-erd/preview/${{ matrix.namespace }}-viewer.html\n if-no-files-found: error\n archive: false\n retention-days: 7\n\n # __ERD_PREVIEW_JOB_END__\n # __ERD_PREVIEW_COMMENT_JOB_START__\n tailor-erd-preview-comment:\n needs: tailor-erd-preview\n if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository\n runs-on: ubuntu-latest\n timeout-minutes: 5\n permissions:\n actions: read\n pull-requests: write\n steps:\n - id: tailor-comment-erd-preview\n env:\n GH_TOKEN: ${{ github.token }}\n REPO: ${{ github.repository }}\n RUN_ID: ${{ github.run_id }}\n SERVER: ${{ github.server_url }}\n PR_NUMBER: ${{ github.event.pull_request.number }}\n BASE_REF: ${{ github.event.pull_request.base.ref }}\n HEAD_SHA: ${{ github.event.pull_request.head.sha }}\n MARKER: \"<!-- tailor-erd-preview: __WORKSPACE_NAME__ -->\"\n run: |\n set -euo pipefail\n\n current_head=$(gh api \"repos/$REPO/pulls/$PR_NUMBER\" --jq '.head.sha')\n if [ \"$current_head\" != \"$HEAD_SHA\" ]; then\n echo \"Skipping stale ERD preview comment for $HEAD_SHA; current head is $current_head.\"\n exit 0\n fi\n\n body=\"$MARKER\"$'\\n'\"### TailorDB ERD preview (__WORKSPACE_NAME__)\"$'\\n\\n'\n body+=\"Self-contained ERD viewer HTML artifacts for this pull request. Each viewer can switch between the current schema and a diff against base branch \\`$BASE_REF\\`.\"$'\\n'\n\n while IFS=$'\\t' read -r name id; do\n [ -z \"$name\" ] && continue\n if [[ \"$name\" != *-viewer.html ]]; then\n continue\n fi\n ns=${name%-viewer.html}\n label=\"$ns viewer\"\n body+=$'\\n'\"- **$label**: [$name]($SERVER/$REPO/actions/runs/$RUN_ID/artifacts/$id)\"\n done < <(gh api \"repos/$REPO/actions/runs/$RUN_ID/artifacts\" --paginate \\\n --jq '.artifacts[] | select(.name | endswith(\"-viewer.html\")) | [.name, (.id|tostring)] | @tsv' | sort)\n\n existing=$(gh api \"repos/$REPO/issues/$PR_NUMBER/comments\" --paginate \\\n --jq 'map(select(.body | contains(env.MARKER))) | .[0].id // empty')\n if [ -n \"$existing\" ]; then\n gh api --method PATCH \"repos/$REPO/issues/comments/$existing\" -f body=\"$body\" >/dev/null\n else\n gh api --method POST \"repos/$REPO/issues/$PR_NUMBER/comments\" -f body=\"$body\" >/dev/null\n fi\n\n # __ERD_PREVIEW_COMMENT_JOB_END__\n tailor-deploy:\n # __DEPLOY_IF__\n runs-on: ubuntu-latest\n timeout-minutes: 30\n permissions:\n contents: read\n environment: __ENVIRONMENT__\n concurrency:\n group: tailor-deploy-__WORKSPACE_NAME__\n cancel-in-progress: false\n steps:\n - id: tailor-checkout\n uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n - id: tailor-setup\n uses: tailor-platform/actions/setup@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n package-manager: __PACKAGE_MANAGER__\n - id: tailor-apply\n uses: tailor-platform/actions/deploy@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}\n package-manager: __PACKAGE_MANAGER__\n # __WORKING_DIRECTORY__\n platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}\n platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}\n";
|
|
2711
2826
|
|
|
2712
2827
|
//#endregion
|
|
2713
2828
|
//#region src/cli/commands/setup/tag.workflow.yml
|
|
2714
|
-
var tag_workflow_default = "# __HEADER__\nname: Tailor (__WORKSPACE_NAME__)\n\non:\n push:\n tags: [\"__TAG_PATTERN__\"]\n workflow_dispatch:\n inputs:\n dry-run:\n description: Preview changes without deploying\n type: boolean\n default: false\n\npermissions:\n contents: read\n\njobs:\n # __TAG_GUARD_JOB_START__\n tailor-tag-guard:\n runs-on: ubuntu-latest\n timeout-minutes: 10\n permissions:\n contents: read\n outputs:\n on-branch: ${{ steps.tailor-tag-guard.outputs.on-branch }}\n steps:\n - id: tailor-checkout\n uses: actions/checkout@
|
|
2829
|
+
var tag_workflow_default = "# __HEADER__\nname: Tailor (__WORKSPACE_NAME__)\n\non:\n push:\n tags: [\"__TAG_PATTERN__\"]\n workflow_dispatch:\n inputs:\n dry-run:\n description: Preview changes without deploying\n type: boolean\n default: false\n\npermissions:\n contents: read\n\njobs:\n # __TAG_GUARD_JOB_START__\n tailor-tag-guard:\n runs-on: ubuntu-latest\n timeout-minutes: 10\n permissions:\n contents: read\n outputs:\n on-branch: ${{ steps.tailor-tag-guard.outputs.on-branch }}\n steps:\n - id: tailor-checkout\n uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n with:\n fetch-depth: 0\n - id: tailor-tag-guard\n uses: tailor-platform/actions/tag-guard@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n target-branch: \"__BRANCH__\"\n # __TAG_GUARD_JOB_END__\n tailor-plan:\n # __PLAN_NEEDS__\n # __PLAN_IF__\n runs-on: ubuntu-latest\n timeout-minutes: 30\n environment: __ENVIRONMENT__\n permissions:\n contents: read\n steps:\n - id: tailor-checkout\n uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n - id: tailor-setup\n uses: tailor-platform/actions/setup@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n package-manager: __PACKAGE_MANAGER__\n - id: tailor-generate-check\n uses: tailor-platform/actions/generate-check@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n package-manager: __PACKAGE_MANAGER__\n # __WORKING_DIRECTORY__\n - id: tailor-plan\n uses: tailor-platform/actions/plan@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}\n package-manager: __PACKAGE_MANAGER__\n label: __WORKSPACE_NAME__\n # __WORKING_DIRECTORY__\n platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}\n platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}\n\n tailor-deploy:\n needs: tailor-plan\n if: ${{ !(github.event_name == 'workflow_dispatch' && inputs['dry-run']) }}\n environment: __ENVIRONMENT__\n runs-on: ubuntu-latest\n timeout-minutes: 30\n permissions:\n contents: read\n concurrency:\n group: tailor-deploy-__WORKSPACE_NAME__\n cancel-in-progress: false\n steps:\n - id: tailor-checkout\n uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0\n - id: tailor-setup\n uses: tailor-platform/actions/setup@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n package-manager: __PACKAGE_MANAGER__\n - id: tailor-apply\n uses: tailor-platform/actions/deploy@7817f37adf2891fbb2ebbe0a3b222a5fa2ed0c1f # v1.3.0\n with:\n workspace-id: ${{ vars.TAILOR_PLATFORM_WORKSPACE_ID }}\n package-manager: __PACKAGE_MANAGER__\n # __WORKING_DIRECTORY__\n platform-client-id: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}\n platform-client-secret: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}\n";
|
|
2715
2830
|
|
|
2716
2831
|
//#endregion
|
|
2717
2832
|
//#region src/cli/commands/setup/templates.ts
|
|
@@ -2751,7 +2866,7 @@ function applyCommon(content, params) {
|
|
|
2751
2866
|
const { workingDirectory, environment, packageManager } = params;
|
|
2752
2867
|
let out = line(content, "HEADER", HEADER);
|
|
2753
2868
|
out = line(out, "WORKING_DIRECTORY", workingDirectory ? `working-directory: ${workingDirectory}` : void 0);
|
|
2754
|
-
return out.replaceAll("__WORKSPACE_NAME__", () => params.workspaceName).replaceAll("__ENVIRONMENT__", () => environment).replaceAll("__PACKAGE_MANAGER__", () => packageManager);
|
|
2869
|
+
return out.replaceAll("__WORKSPACE_NAME__", () => params.workspaceName).replaceAll("__ENVIRONMENT__", () => environment).replaceAll("__PACKAGE_MANAGER__", () => packageManager).replaceAll("__APP_DIR__", () => workingDirectory ?? ".");
|
|
2755
2870
|
}
|
|
2756
2871
|
/**
|
|
2757
2872
|
* Render the branch-target deploy workflow.
|
|
@@ -2764,8 +2879,11 @@ function applyCommon(content, params) {
|
|
|
2764
2879
|
*/
|
|
2765
2880
|
function renderBranchWorkflow(params) {
|
|
2766
2881
|
const { branch, plan } = params;
|
|
2882
|
+
const erdPreview = plan ? params.erdPreview : null;
|
|
2767
2883
|
let out = branch_workflow_default;
|
|
2768
2884
|
out = block(out, "PLAN_JOB", plan);
|
|
2885
|
+
out = block(out, "ERD_PREVIEW_JOB", erdPreview !== null);
|
|
2886
|
+
out = block(out, "ERD_PREVIEW_COMMENT_JOB", erdPreview !== null);
|
|
2769
2887
|
out = block(out, "PULL_REQUEST", plan);
|
|
2770
2888
|
out = block(out, "DISPATCH_INPUTS", plan);
|
|
2771
2889
|
out = line(out, "DEPLOY_IF", plan ? `if: >-\n github.event_name == 'push' ||\n (github.event_name == 'workflow_dispatch' && !inputs['dry-run'])` : void 0);
|
|
@@ -2773,6 +2891,7 @@ function renderBranchWorkflow(params) {
|
|
|
2773
2891
|
out = applyCommon(out, params).replaceAll("__BRANCH__", () => branch);
|
|
2774
2892
|
const generatedIds = [];
|
|
2775
2893
|
if (plan) generatedIds.push("tailor-plan", "tailor-plan/tailor-checkout", "tailor-plan/tailor-setup", "tailor-plan/tailor-generate-check", "tailor-plan/tailor-plan");
|
|
2894
|
+
if (erdPreview) generatedIds.push("tailor-erd-preview-matrix", "tailor-erd-preview-matrix/tailor-checkout", "tailor-erd-preview-matrix/tailor-checkout-base", "tailor-erd-preview-matrix/tailor-erd-preview-matrix", "tailor-erd-preview", "tailor-erd-preview/tailor-checkout", "tailor-erd-preview/tailor-setup", "tailor-erd-preview/tailor-checkout-base", "tailor-erd-preview/tailor-detect-base-package-manager", "tailor-erd-preview/tailor-setup-base-pnpm", "tailor-erd-preview/tailor-setup-base-node", "tailor-erd-preview/tailor-setup-base-yarn", "tailor-erd-preview/tailor-setup-base-bun", "tailor-erd-preview/tailor-install-base", "tailor-erd-preview/tailor-restore-head-setup", "tailor-erd-preview/tailor-build-erd-preview", "tailor-erd-preview/tailor-upload-erd-viewer", "tailor-erd-preview-comment", "tailor-erd-preview-comment/tailor-comment-erd-preview");
|
|
2776
2895
|
generatedIds.push("tailor-deploy", "tailor-deploy/tailor-checkout", "tailor-deploy/tailor-setup", "tailor-deploy/tailor-apply");
|
|
2777
2896
|
return {
|
|
2778
2897
|
content: out,
|
|
@@ -2842,6 +2961,15 @@ function findTargetDrift(target, state) {
|
|
|
2842
2961
|
rule: "default-branch",
|
|
2843
2962
|
message: `The workflow triggers on "${target.inputs.branch}" but the repository default branch is now "${state.defaultBranch}". If this is intentional, ignore this; otherwise re-run setup so the trigger matches the default branch.`
|
|
2844
2963
|
});
|
|
2964
|
+
if (target.kind === "branch" && target.inputs.erdPreview && state.configExists) {
|
|
2965
|
+
const recorded = [...target.inputs.erdNamespaces ?? []].toSorted((a, b) => a.localeCompare(b));
|
|
2966
|
+
const current = state.erdNamespaces?.toSorted((a, b) => a.localeCompare(b)) ?? null;
|
|
2967
|
+
if (current === null || recorded.length !== current.length || recorded.some((namespace, index) => namespace !== current[index])) findings.push({
|
|
2968
|
+
target: id,
|
|
2969
|
+
rule: "erd-namespaces",
|
|
2970
|
+
message: "TailorDB namespaces for ERD preview changed. Re-run setup so the ERD preview matrix is regenerated."
|
|
2971
|
+
});
|
|
2972
|
+
}
|
|
2845
2973
|
return findings;
|
|
2846
2974
|
}
|
|
2847
2975
|
function detectDefaultBranchSafe(cwd, run) {
|
|
@@ -2870,6 +2998,10 @@ function readHash(absFile) {
|
|
|
2870
2998
|
return null;
|
|
2871
2999
|
}
|
|
2872
3000
|
}
|
|
3001
|
+
async function defaultLoadErdNamespaces$1(configPath) {
|
|
3002
|
+
const { config } = await loadConfig(configPath);
|
|
3003
|
+
return extractOwnedNamespaces(config);
|
|
3004
|
+
}
|
|
2873
3005
|
/**
|
|
2874
3006
|
* Audit the generated workflows for drift against the current config/repo
|
|
2875
3007
|
* state. Read-only: never writes files, the lock, or the config.
|
|
@@ -2879,24 +3011,28 @@ function readHash(absFile) {
|
|
|
2879
3011
|
* (per-rule ignore / continue-on-error); the CLI itself reports via exit code.
|
|
2880
3012
|
* @param options - Check options
|
|
2881
3013
|
*/
|
|
2882
|
-
function checkGitHub(options) {
|
|
3014
|
+
async function checkGitHub(options) {
|
|
2883
3015
|
logBetaWarning("setup");
|
|
2884
3016
|
const { outputDir } = options;
|
|
2885
3017
|
const lock = readLock(outputDir);
|
|
2886
3018
|
if (!lock || lock.targets.length === 0) throw new Error("No managed workflows found (.github/tailor-sdk.lock is missing or empty). Run `tailor-sdk setup` first.");
|
|
2887
3019
|
const exists = options.configExistsAt ?? ((p) => fs$1.existsSync(p));
|
|
2888
3020
|
const defaultBranch = detectDefaultBranchSafe(outputDir, options.gitRunner);
|
|
3021
|
+
const loadErdNamespaces = options.loadErdNamespaces ?? defaultLoadErdNamespaces$1;
|
|
2889
3022
|
const findings = [];
|
|
2890
3023
|
for (const target of lock.targets) {
|
|
2891
3024
|
const absFile = resolveWithinRoot(outputDir, target.file);
|
|
2892
3025
|
const currentHash = absFile === null ? null : readHash(absFile);
|
|
2893
3026
|
const configAbs = resolveWithinRoot(outputDir, path.join(target.inputs.dir, "tailor.config.ts"));
|
|
3027
|
+
const configExists = configAbs !== null && exists(configAbs);
|
|
3028
|
+
const erdNamespaces = target.kind === "branch" && target.inputs.erdPreview && configAbs !== null && configExists ? await loadErdNamespaces(configAbs) : null;
|
|
2894
3029
|
findings.push(...findTargetDrift(target, {
|
|
2895
3030
|
fileExists: currentHash !== null,
|
|
2896
3031
|
currentHash,
|
|
2897
|
-
configExists
|
|
3032
|
+
configExists,
|
|
2898
3033
|
defaultBranch,
|
|
2899
|
-
templateVersion:
|
|
3034
|
+
templateVersion: 5,
|
|
3035
|
+
erdNamespaces
|
|
2900
3036
|
}));
|
|
2901
3037
|
}
|
|
2902
3038
|
const count = lock.targets.length;
|
|
@@ -2914,6 +3050,10 @@ async function defaultLoadConfigName(configPath) {
|
|
|
2914
3050
|
const { config } = await loadConfig(configPath);
|
|
2915
3051
|
return config.name;
|
|
2916
3052
|
}
|
|
3053
|
+
async function defaultLoadErdNamespaces(configPath) {
|
|
3054
|
+
const { config } = await loadConfig(configPath);
|
|
3055
|
+
return extractOwnedNamespaces(config);
|
|
3056
|
+
}
|
|
2917
3057
|
const WORKSPACE_NAME_RE = /^[a-z0-9-]+$/;
|
|
2918
3058
|
function validateWorkspaceName(name) {
|
|
2919
3059
|
if (name.length < 3 || name.length > 63 || !WORKSPACE_NAME_RE.test(name) || name.startsWith("-") || name.endsWith("-")) throw new Error(`Invalid workspace name "${name}". Names must be 3-63 characters of lowercase letters, numbers, and hyphens, and cannot start or end with a hyphen. Pass a valid name with --workspace-name.`);
|
|
@@ -2934,6 +3074,10 @@ const DIR_RE = /^[A-Za-z0-9._/-]+$/;
|
|
|
2934
3074
|
function validateDir(dir) {
|
|
2935
3075
|
if (!DIR_RE.test(dir)) throw new Error(`Invalid --dir "${dir}". Only letters, numbers, ".", "_", "/", and "-" are supported.`);
|
|
2936
3076
|
}
|
|
3077
|
+
const ERD_NAMESPACE_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
3078
|
+
function validateErdNamespaces(namespaces) {
|
|
3079
|
+
for (const namespace of namespaces) if (!ERD_NAMESPACE_RE.test(namespace)) throw new Error(`TailorDB namespace "${namespace}" cannot be used in --erd-preview. Only letters, numbers, '.', '_', and '-' are supported, and the name must start with a letter or number.`);
|
|
3080
|
+
}
|
|
2937
3081
|
function escapesRoot(rel) {
|
|
2938
3082
|
return rel === ".." || rel.startsWith(`..${path.sep}`) || rel.startsWith("../") || path.isAbsolute(rel);
|
|
2939
3083
|
}
|
|
@@ -2967,6 +3111,7 @@ function resolveConfigPath(outputDir, dir) {
|
|
|
2967
3111
|
*/
|
|
2968
3112
|
async function resolve$1(options) {
|
|
2969
3113
|
if (options.tag && !options.plan) throw new Error("--no-plan cannot be combined with --tag (tag targets always run plan before deploy). Drop --no-plan or use a branch target.");
|
|
3114
|
+
if (options.erdPreview && (options.tag || !options.plan)) throw new Error("--erd-preview requires a branch target with plan enabled.");
|
|
2970
3115
|
const dir = options.dir.replaceAll("\\", "/").replace(/\/{2,}/g, "/").replace(/^\.\//, "").replace(/\/$/, "") || ".";
|
|
2971
3116
|
validateDir(dir);
|
|
2972
3117
|
const workingDirectory = dir !== "." ? dir : void 0;
|
|
@@ -2983,6 +3128,12 @@ async function resolve$1(options) {
|
|
|
2983
3128
|
let branch = null;
|
|
2984
3129
|
let branchAutoDetected = false;
|
|
2985
3130
|
let render;
|
|
3131
|
+
let erdNamespaces = [];
|
|
3132
|
+
if (options.erdPreview) {
|
|
3133
|
+
erdNamespaces = await (options.loadErdNamespaces ?? defaultLoadErdNamespaces)(configPath);
|
|
3134
|
+
if (erdNamespaces.length === 0) throw new Error("No TailorDB namespaces found for --erd-preview. Define owned db namespaces in tailor.config.ts.");
|
|
3135
|
+
validateErdNamespaces(erdNamespaces);
|
|
3136
|
+
}
|
|
2986
3137
|
if (kind === "branch") {
|
|
2987
3138
|
branchAutoDetected = options.branch === void 0;
|
|
2988
3139
|
branch = options.branch ?? detectDefaultBranch(options.outputDir, options.gitRunner);
|
|
@@ -2993,7 +3144,8 @@ async function resolve$1(options) {
|
|
|
2993
3144
|
workingDirectory,
|
|
2994
3145
|
environment,
|
|
2995
3146
|
packageManager,
|
|
2996
|
-
plan: options.plan
|
|
3147
|
+
plan: options.plan,
|
|
3148
|
+
erdPreview: options.erdPreview ? { namespaces: erdNamespaces } : null
|
|
2997
3149
|
});
|
|
2998
3150
|
} else {
|
|
2999
3151
|
branch = options.branch ?? null;
|
|
@@ -3015,7 +3167,9 @@ async function resolve$1(options) {
|
|
|
3015
3167
|
environment,
|
|
3016
3168
|
dir,
|
|
3017
3169
|
packageManager,
|
|
3018
|
-
plan: kind === "branch" ? options.plan : true
|
|
3170
|
+
plan: kind === "branch" ? options.plan : true,
|
|
3171
|
+
erdPreview: kind === "branch" ? options.erdPreview : false,
|
|
3172
|
+
erdNamespaces: kind === "branch" && options.erdPreview ? erdNamespaces : void 0
|
|
3019
3173
|
};
|
|
3020
3174
|
return {
|
|
3021
3175
|
kind,
|
|
@@ -3023,6 +3177,7 @@ async function resolve$1(options) {
|
|
|
3023
3177
|
branch,
|
|
3024
3178
|
environment,
|
|
3025
3179
|
packageManager,
|
|
3180
|
+
erdNamespaces,
|
|
3026
3181
|
render,
|
|
3027
3182
|
inputs,
|
|
3028
3183
|
file,
|
|
@@ -3127,7 +3282,7 @@ async function setupGitHub(options) {
|
|
|
3127
3282
|
kind: resolved.kind,
|
|
3128
3283
|
workspaceName: resolved.workspaceName,
|
|
3129
3284
|
file: resolved.file,
|
|
3130
|
-
templateVersion:
|
|
3285
|
+
templateVersion: 5,
|
|
3131
3286
|
inputs: resolved.inputs,
|
|
3132
3287
|
generatedIds: resolved.render.generatedIds,
|
|
3133
3288
|
ejectedIds: existing?.ejectedIds ?? [],
|
|
@@ -3156,8 +3311,8 @@ const checkCommand = defineAppCommand({
|
|
|
3156
3311
|
name: "check",
|
|
3157
3312
|
description: "Audit generated workflows for drift against the current config/repo (read-only).",
|
|
3158
3313
|
args: z.object({}).strict(),
|
|
3159
|
-
run: () => {
|
|
3160
|
-
checkGitHub({ outputDir: process.cwd() });
|
|
3314
|
+
run: async () => {
|
|
3315
|
+
await checkGitHub({ outputDir: process.cwd() });
|
|
3161
3316
|
}
|
|
3162
3317
|
});
|
|
3163
3318
|
const setupCommand = defineAppCommand({
|
|
@@ -3177,6 +3332,7 @@ const setupCommand = defineAppCommand({
|
|
|
3177
3332
|
"tag-pattern": arg(z.string().min(1).optional(), { description: "Tag glob to match (requires --tag; defaults to v*)" }),
|
|
3178
3333
|
environment: arg(z.string().min(1).optional(), { description: "GitHub Environment for the plan/deploy jobs (defaults to the workspace name)" }),
|
|
3179
3334
|
"no-plan": arg(z.boolean().default(false), { description: "Disable the plan job for a branch target (cannot be combined with --tag)" }),
|
|
3335
|
+
"erd-preview": arg(z.boolean().default(false), { description: "Add PR ERD viewer artifacts with current/diff previews for TailorDB namespaces" }),
|
|
3180
3336
|
dir: arg(z.string().min(1).default("."), {
|
|
3181
3337
|
alias: "d",
|
|
3182
3338
|
description: "App directory (for monorepo setups)"
|
|
@@ -3194,6 +3350,7 @@ const setupCommand = defineAppCommand({
|
|
|
3194
3350
|
tagPattern: args["tag-pattern"] ?? "v*",
|
|
3195
3351
|
environment: args.environment,
|
|
3196
3352
|
plan: !args["no-plan"],
|
|
3353
|
+
erdPreview: args["erd-preview"],
|
|
3197
3354
|
dir: args.dir,
|
|
3198
3355
|
force: args.force,
|
|
3199
3356
|
outputDir: process.cwd()
|
|
@@ -3331,7 +3488,7 @@ async function withTimeout(p, ms, message) {
|
|
|
3331
3488
|
//#endregion
|
|
3332
3489
|
//#region src/cli/commands/staticwebsite/deploy.ts
|
|
3333
3490
|
const CHUNK_SIZE = 64 * 1024;
|
|
3334
|
-
const IGNORED_FILES = new Set([
|
|
3491
|
+
const IGNORED_FILES = /* @__PURE__ */ new Set([
|
|
3335
3492
|
".DS_Store",
|
|
3336
3493
|
"thumbs.db",
|
|
3337
3494
|
"desktop.ini"
|
|
@@ -3971,6 +4128,9 @@ async function initErdDeployContext(args) {
|
|
|
3971
4128
|
const VIEWER_ASSETS_DIR = "erd-viewer-assets";
|
|
3972
4129
|
const STYLES_LINK = "<link rel=\"stylesheet\" href=\"./styles.css\" />";
|
|
3973
4130
|
const APP_SCRIPT = "<script src=\"./app.js\" type=\"module\"><\/script>";
|
|
4131
|
+
function escapeHtml(value) {
|
|
4132
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """);
|
|
4133
|
+
}
|
|
3974
4134
|
function assetDirCandidates() {
|
|
3975
4135
|
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
3976
4136
|
return [
|
|
@@ -3993,8 +4153,8 @@ function resolveViewerAssetsDir() {
|
|
|
3993
4153
|
* are inlined as separately extractable blocks: a `<style>` element, a
|
|
3994
4154
|
* `<script type="module">`, and a `<script type="application/json"
|
|
3995
4155
|
* id="erd-schema">` data block. This renders without any sibling asset files
|
|
3996
|
-
* and lets external tooling (
|
|
3997
|
-
* `JSON.parse`.
|
|
4156
|
+
* and lets external tooling (including the ERD diff command) pull out the
|
|
4157
|
+
* schema via `JSON.parse`.
|
|
3998
4158
|
* @param options - Viewer build options.
|
|
3999
4159
|
* @returns The self-contained HTML document.
|
|
4000
4160
|
*/
|
|
@@ -4005,8 +4165,10 @@ function buildViewerHtml(options) {
|
|
|
4005
4165
|
const appJs = fs$1.readFileSync(path.join(assetsDir, "app.js"), "utf8");
|
|
4006
4166
|
if (!html.includes(STYLES_LINK) || !html.includes(APP_SCRIPT)) throw new Error("ERD viewer index.html is missing expected asset references for inlining.");
|
|
4007
4167
|
const embedScript = `<script type="application/json" id="erd-schema">${JSON.stringify(options.schema).replaceAll("<", "\\u003c")}<\/script>`;
|
|
4168
|
+
const currentSchemaScript = options.currentSchema === void 0 ? "" : `\n <script type="application/json" id="erd-current-schema">${JSON.stringify(options.currentSchema).replaceAll("<", "\\u003c")}<\/script>`;
|
|
4169
|
+
const diffScript = options.diff === void 0 ? "" : `\n <script type="application/json" id="erd-diff">${JSON.stringify(options.diff).replaceAll("<", "\\u003c")}<\/script>`;
|
|
4008
4170
|
const inlineScript = `<script type="module">\n${appJs.replace(/<\/script/gi, "<\\/script")}\n<\/script>`;
|
|
4009
|
-
return html.replace(STYLES_LINK, `<style>\n${css}\n</style>`).replace(APP_SCRIPT, `${embedScript}\n ${inlineScript}`);
|
|
4171
|
+
return html.replace("<title>TailorDB ERD</title>", `<title>${escapeHtml(options.title ?? "TailorDB ERD")}</title>`).replace(STYLES_LINK, `<style>\n${css}\n</style>`).replace(APP_SCRIPT, `${embedScript}${currentSchemaScript}${diffScript}\n ${inlineScript}`);
|
|
4010
4172
|
}
|
|
4011
4173
|
/**
|
|
4012
4174
|
* Write the self-contained TailorDB ERD viewer to `<distDir>/index.html`.
|
|
@@ -4176,6 +4338,362 @@ const erdDeployCommand = defineAppCommand({
|
|
|
4176
4338
|
}
|
|
4177
4339
|
});
|
|
4178
4340
|
|
|
4341
|
+
//#endregion
|
|
4342
|
+
//#region src/cli/commands/tailordb/erd/diff.ts
|
|
4343
|
+
const SCHEMA_BLOCK_PATTERN = /<script type="application\/json" id="erd-schema">([\s\S]*?)<\/script>/;
|
|
4344
|
+
function stableValue(value) {
|
|
4345
|
+
if (Array.isArray(value)) return value.map((item) => stableValue(item));
|
|
4346
|
+
if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, item]) => [key, stableValue(item)]));
|
|
4347
|
+
return value;
|
|
4348
|
+
}
|
|
4349
|
+
function stableJson(value) {
|
|
4350
|
+
return JSON.stringify(stableValue(value));
|
|
4351
|
+
}
|
|
4352
|
+
function changedFields(base, head) {
|
|
4353
|
+
return [.../* @__PURE__ */ new Set([...Object.keys(base), ...Object.keys(head)])].toSorted((a, b) => a.localeCompare(b)).filter((key) => stableJson(base[key]) !== stableJson(head[key]));
|
|
4354
|
+
}
|
|
4355
|
+
function detailForChangedFields(fields) {
|
|
4356
|
+
return `Changed fields: ${fields.join(", ")}`;
|
|
4357
|
+
}
|
|
4358
|
+
function mapByName(items) {
|
|
4359
|
+
return new Map(items.map((item) => [item.name, item]));
|
|
4360
|
+
}
|
|
4361
|
+
function compareCommonNamed(baseItems, headItems, addChange) {
|
|
4362
|
+
const baseByName = mapByName(baseItems);
|
|
4363
|
+
const headByName = mapByName(headItems);
|
|
4364
|
+
const commonNames = [...baseByName.keys()].filter((name) => headByName.has(name)).toSorted((a, b) => a.localeCompare(b));
|
|
4365
|
+
for (const name of commonNames) {
|
|
4366
|
+
const base = baseByName.get(name);
|
|
4367
|
+
const head = headByName.get(name);
|
|
4368
|
+
if (!base || !head) continue;
|
|
4369
|
+
const fields = changedFields(base, head);
|
|
4370
|
+
if (fields.length > 0) addChange(name, fields);
|
|
4371
|
+
}
|
|
4372
|
+
}
|
|
4373
|
+
function removedNames(baseItems, headItems) {
|
|
4374
|
+
const headByName = mapByName(headItems);
|
|
4375
|
+
return baseItems.map((item) => item.name).filter((name) => !headByName.has(name)).toSorted((a, b) => a.localeCompare(b));
|
|
4376
|
+
}
|
|
4377
|
+
function addedNames(baseItems, headItems) {
|
|
4378
|
+
const baseByName = mapByName(baseItems);
|
|
4379
|
+
return headItems.map((item) => item.name).filter((name) => !baseByName.has(name)).toSorted((a, b) => a.localeCompare(b));
|
|
4380
|
+
}
|
|
4381
|
+
function tableMetadata(table) {
|
|
4382
|
+
return {
|
|
4383
|
+
backwardRelationships: table.backwardRelationships,
|
|
4384
|
+
description: table.description,
|
|
4385
|
+
forwardRelationships: table.forwardRelationships,
|
|
4386
|
+
pluralForm: table.pluralForm,
|
|
4387
|
+
source: table.source
|
|
4388
|
+
};
|
|
4389
|
+
}
|
|
4390
|
+
function pushChange(changes, change) {
|
|
4391
|
+
changes.push(change);
|
|
4392
|
+
}
|
|
4393
|
+
function diffColumns(changes, tableName, baseColumns, headColumns) {
|
|
4394
|
+
compareCommonNamed(baseColumns, headColumns, (name, fields) => {
|
|
4395
|
+
pushChange(changes, {
|
|
4396
|
+
action: "changed",
|
|
4397
|
+
entity: "column",
|
|
4398
|
+
path: `${tableName}.${name}`,
|
|
4399
|
+
detail: detailForChangedFields(fields)
|
|
4400
|
+
});
|
|
4401
|
+
});
|
|
4402
|
+
for (const name of removedNames(baseColumns, headColumns)) pushChange(changes, {
|
|
4403
|
+
action: "removed",
|
|
4404
|
+
entity: "column",
|
|
4405
|
+
path: `${tableName}.${name}`,
|
|
4406
|
+
detail: "Column removed"
|
|
4407
|
+
});
|
|
4408
|
+
for (const name of addedNames(baseColumns, headColumns)) pushChange(changes, {
|
|
4409
|
+
action: "added",
|
|
4410
|
+
entity: "column",
|
|
4411
|
+
path: `${tableName}.${name}`,
|
|
4412
|
+
detail: "Column added"
|
|
4413
|
+
});
|
|
4414
|
+
}
|
|
4415
|
+
function diffIndexes(changes, tableName, baseIndexes, headIndexes) {
|
|
4416
|
+
compareCommonNamed(baseIndexes, headIndexes, (name, fields) => {
|
|
4417
|
+
pushChange(changes, {
|
|
4418
|
+
action: "changed",
|
|
4419
|
+
entity: "index",
|
|
4420
|
+
path: `${tableName}.${name}`,
|
|
4421
|
+
detail: detailForChangedFields(fields)
|
|
4422
|
+
});
|
|
4423
|
+
});
|
|
4424
|
+
for (const name of removedNames(baseIndexes, headIndexes)) pushChange(changes, {
|
|
4425
|
+
action: "removed",
|
|
4426
|
+
entity: "index",
|
|
4427
|
+
path: `${tableName}.${name}`,
|
|
4428
|
+
detail: "Index removed"
|
|
4429
|
+
});
|
|
4430
|
+
for (const name of addedNames(baseIndexes, headIndexes)) pushChange(changes, {
|
|
4431
|
+
action: "added",
|
|
4432
|
+
entity: "index",
|
|
4433
|
+
path: `${tableName}.${name}`,
|
|
4434
|
+
detail: "Index added"
|
|
4435
|
+
});
|
|
4436
|
+
}
|
|
4437
|
+
function diffTables(changes, baseTables, headTables) {
|
|
4438
|
+
const baseByName = mapByName(baseTables);
|
|
4439
|
+
const headByName = mapByName(headTables);
|
|
4440
|
+
for (const name of removedNames(baseTables, headTables)) pushChange(changes, {
|
|
4441
|
+
action: "removed",
|
|
4442
|
+
entity: "table",
|
|
4443
|
+
path: name,
|
|
4444
|
+
detail: "Table removed"
|
|
4445
|
+
});
|
|
4446
|
+
for (const name of addedNames(baseTables, headTables)) pushChange(changes, {
|
|
4447
|
+
action: "added",
|
|
4448
|
+
entity: "table",
|
|
4449
|
+
path: name,
|
|
4450
|
+
detail: "Table added"
|
|
4451
|
+
});
|
|
4452
|
+
const commonNames = [...baseByName.keys()].filter((name) => headByName.has(name)).toSorted((a, b) => a.localeCompare(b));
|
|
4453
|
+
for (const name of commonNames) {
|
|
4454
|
+
const base = baseByName.get(name);
|
|
4455
|
+
const head = headByName.get(name);
|
|
4456
|
+
if (!base || !head) continue;
|
|
4457
|
+
const tableFields = changedFields(tableMetadata(base), tableMetadata(head));
|
|
4458
|
+
if (tableFields.length > 0) pushChange(changes, {
|
|
4459
|
+
action: "changed",
|
|
4460
|
+
entity: "table",
|
|
4461
|
+
path: name,
|
|
4462
|
+
detail: detailForChangedFields(tableFields)
|
|
4463
|
+
});
|
|
4464
|
+
diffColumns(changes, name, base.columns, head.columns);
|
|
4465
|
+
diffIndexes(changes, name, base.indexes, head.indexes);
|
|
4466
|
+
}
|
|
4467
|
+
}
|
|
4468
|
+
function diffRelations(changes, baseRelations, headRelations) {
|
|
4469
|
+
compareCommonNamed(baseRelations, headRelations, (name, fields) => {
|
|
4470
|
+
pushChange(changes, {
|
|
4471
|
+
action: "changed",
|
|
4472
|
+
entity: "relation",
|
|
4473
|
+
path: name,
|
|
4474
|
+
detail: detailForChangedFields(fields)
|
|
4475
|
+
});
|
|
4476
|
+
});
|
|
4477
|
+
for (const name of removedNames(baseRelations, headRelations)) pushChange(changes, {
|
|
4478
|
+
action: "removed",
|
|
4479
|
+
entity: "relation",
|
|
4480
|
+
path: name,
|
|
4481
|
+
detail: "Relation removed"
|
|
4482
|
+
});
|
|
4483
|
+
for (const name of addedNames(baseRelations, headRelations)) pushChange(changes, {
|
|
4484
|
+
action: "added",
|
|
4485
|
+
entity: "relation",
|
|
4486
|
+
path: name,
|
|
4487
|
+
detail: "Relation added"
|
|
4488
|
+
});
|
|
4489
|
+
}
|
|
4490
|
+
function summarize(changes) {
|
|
4491
|
+
return {
|
|
4492
|
+
added: changes.filter((change) => change.action === "added").length,
|
|
4493
|
+
changed: changes.filter((change) => change.action === "changed").length,
|
|
4494
|
+
removed: changes.filter((change) => change.action === "removed").length
|
|
4495
|
+
};
|
|
4496
|
+
}
|
|
4497
|
+
function extractEmbeddedErdSchema(html) {
|
|
4498
|
+
const match = SCHEMA_BLOCK_PATTERN.exec(html);
|
|
4499
|
+
if (!match?.[1]) throw new Error("ERD schema block not found.");
|
|
4500
|
+
try {
|
|
4501
|
+
return JSON.parse(match[1]);
|
|
4502
|
+
} catch (error) {
|
|
4503
|
+
throw new Error(`Failed to parse ERD schema block: ${String(error)}`, { cause: error });
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
function createEmptyErdSchema(options) {
|
|
4507
|
+
return {
|
|
4508
|
+
version: 1,
|
|
4509
|
+
namespace: options.namespace,
|
|
4510
|
+
generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
4511
|
+
revision: options.revision,
|
|
4512
|
+
source: "local",
|
|
4513
|
+
cleanRoom: {
|
|
4514
|
+
implementation: "tailor-sdk",
|
|
4515
|
+
notes: ["Synthetic empty schema used for ERD diff generation."]
|
|
4516
|
+
},
|
|
4517
|
+
tables: [],
|
|
4518
|
+
relations: []
|
|
4519
|
+
};
|
|
4520
|
+
}
|
|
4521
|
+
function buildErdSchemaDiff(options) {
|
|
4522
|
+
const { base, head } = options;
|
|
4523
|
+
if (base.namespace !== head.namespace) throw new Error(`Cannot diff ERD schemas from different namespaces: ${base.namespace}, ${head.namespace}`);
|
|
4524
|
+
const changes = [];
|
|
4525
|
+
diffTables(changes, base.tables, head.tables);
|
|
4526
|
+
diffRelations(changes, base.relations, head.relations);
|
|
4527
|
+
const summary = summarize(changes);
|
|
4528
|
+
return {
|
|
4529
|
+
namespace: head.namespace,
|
|
4530
|
+
baseRevision: base.revision,
|
|
4531
|
+
headRevision: head.revision,
|
|
4532
|
+
changed: changes.length > 0,
|
|
4533
|
+
summary,
|
|
4534
|
+
changes
|
|
4535
|
+
};
|
|
4536
|
+
}
|
|
4537
|
+
function mergeNamedByHead(baseItems, headItems) {
|
|
4538
|
+
const headByName = mapByName(headItems);
|
|
4539
|
+
const removedItems = baseItems.filter((item) => !headByName.has(item.name)).toSorted((a, b) => a.name.localeCompare(b.name));
|
|
4540
|
+
return [...headItems, ...removedItems];
|
|
4541
|
+
}
|
|
4542
|
+
function mergeDiffViewerTable(baseTable, headTable) {
|
|
4543
|
+
return {
|
|
4544
|
+
...headTable,
|
|
4545
|
+
columns: mergeNamedByHead(baseTable.columns, headTable.columns),
|
|
4546
|
+
indexes: mergeNamedByHead(baseTable.indexes, headTable.indexes)
|
|
4547
|
+
};
|
|
4548
|
+
}
|
|
4549
|
+
function mergeDiffViewerTables(baseTables, headTables) {
|
|
4550
|
+
const baseByName = mapByName(baseTables);
|
|
4551
|
+
const headByName = mapByName(headTables);
|
|
4552
|
+
const merged = headTables.map((headTable) => {
|
|
4553
|
+
const baseTable = baseByName.get(headTable.name);
|
|
4554
|
+
return baseTable ? mergeDiffViewerTable(baseTable, headTable) : headTable;
|
|
4555
|
+
});
|
|
4556
|
+
const removedTables = baseTables.filter((table) => !headByName.has(table.name)).toSorted((a, b) => a.name.localeCompare(b.name));
|
|
4557
|
+
return [...merged, ...removedTables];
|
|
4558
|
+
}
|
|
4559
|
+
/**
|
|
4560
|
+
* Build the schema rendered by the diff viewer. The ordinary ERD viewer only
|
|
4561
|
+
* knows how to draw objects present in its schema, so the diff schema keeps
|
|
4562
|
+
* base-only tables, columns, indexes, and relations visible for removal
|
|
4563
|
+
* highlighting while preferring head-side metadata for unchanged objects.
|
|
4564
|
+
* @param options - Base and head schemas to merge for diff rendering.
|
|
4565
|
+
* @returns A TailorDB ERD schema suitable for the visual diff viewer.
|
|
4566
|
+
*/
|
|
4567
|
+
function buildErdDiffViewerSchema(options) {
|
|
4568
|
+
const { base, head } = options;
|
|
4569
|
+
if (base.namespace !== head.namespace) throw new Error(`Cannot diff ERD schemas from different namespaces: ${base.namespace}, ${head.namespace}`);
|
|
4570
|
+
return {
|
|
4571
|
+
...head,
|
|
4572
|
+
tables: mergeDiffViewerTables(base.tables, head.tables),
|
|
4573
|
+
relations: mergeNamedByHead(base.relations, head.relations)
|
|
4574
|
+
};
|
|
4575
|
+
}
|
|
4576
|
+
function renderErdDiffHtml(options) {
|
|
4577
|
+
return buildViewerHtml({
|
|
4578
|
+
schema: options.schema,
|
|
4579
|
+
currentSchema: options.currentSchema,
|
|
4580
|
+
diff: options.diff,
|
|
4581
|
+
title: `TailorDB ERD diff - ${options.diff.namespace}`
|
|
4582
|
+
});
|
|
4583
|
+
}
|
|
4584
|
+
|
|
4585
|
+
//#endregion
|
|
4586
|
+
//#region src/cli/commands/tailordb/erd/diff-command.ts
|
|
4587
|
+
function readSchema(filePath) {
|
|
4588
|
+
if (!filePath) return void 0;
|
|
4589
|
+
return extractEmbeddedErdSchema(fs$1.readFileSync(filePath, "utf8"));
|
|
4590
|
+
}
|
|
4591
|
+
function resolveNamespace(options) {
|
|
4592
|
+
const namespace = options.namespace ?? options.head?.namespace ?? options.base?.namespace;
|
|
4593
|
+
if (!namespace) throw new Error("Missing --namespace when one side of the ERD diff is omitted.");
|
|
4594
|
+
if (options.base && options.base.namespace !== namespace) throw new Error(`Base ERD namespace "${options.base.namespace}" does not match "${namespace}".`);
|
|
4595
|
+
if (options.head && options.head.namespace !== namespace) throw new Error(`Head ERD namespace "${options.head.namespace}" does not match "${namespace}".`);
|
|
4596
|
+
return namespace;
|
|
4597
|
+
}
|
|
4598
|
+
function writeFile(filePath, content) {
|
|
4599
|
+
fs$1.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
4600
|
+
fs$1.writeFileSync(filePath, content, "utf8");
|
|
4601
|
+
}
|
|
4602
|
+
function writeErdDiff(options) {
|
|
4603
|
+
const base = readSchema(options.baseHtml);
|
|
4604
|
+
const head = readSchema(options.headHtml);
|
|
4605
|
+
if (!base && !head) throw new Error("At least one of --base-html or --head-html is required.");
|
|
4606
|
+
const namespace = resolveNamespace({
|
|
4607
|
+
namespace: options.namespace,
|
|
4608
|
+
base,
|
|
4609
|
+
head
|
|
4610
|
+
});
|
|
4611
|
+
const baseSchema = base ?? createEmptyErdSchema({
|
|
4612
|
+
namespace,
|
|
4613
|
+
revision: "missing-base"
|
|
4614
|
+
});
|
|
4615
|
+
const headSchema = head ?? createEmptyErdSchema({
|
|
4616
|
+
namespace,
|
|
4617
|
+
revision: "missing-head"
|
|
4618
|
+
});
|
|
4619
|
+
const diff = buildErdSchemaDiff({
|
|
4620
|
+
base: baseSchema,
|
|
4621
|
+
head: headSchema
|
|
4622
|
+
});
|
|
4623
|
+
const viewerSchema = buildErdDiffViewerSchema({
|
|
4624
|
+
base: baseSchema,
|
|
4625
|
+
head: headSchema
|
|
4626
|
+
});
|
|
4627
|
+
writeFile(options.outputHtml, renderErdDiffHtml({
|
|
4628
|
+
schema: viewerSchema,
|
|
4629
|
+
currentSchema: headSchema,
|
|
4630
|
+
diff
|
|
4631
|
+
}));
|
|
4632
|
+
if (options.outputJson) writeFile(options.outputJson, `${JSON.stringify(diff, null, 2)}\n`);
|
|
4633
|
+
return {
|
|
4634
|
+
namespace,
|
|
4635
|
+
outputHtml: options.outputHtml,
|
|
4636
|
+
outputJson: options.outputJson,
|
|
4637
|
+
diff
|
|
4638
|
+
};
|
|
4639
|
+
}
|
|
4640
|
+
const erdDiffCommand = defineAppCommand({
|
|
4641
|
+
name: "diff",
|
|
4642
|
+
description: "Render TailorDB ERD schema diff HTML from exported ERD viewers.",
|
|
4643
|
+
args: z.object({
|
|
4644
|
+
"base-html": arg(z.string().optional(), {
|
|
4645
|
+
description: "Base ERD viewer HTML file",
|
|
4646
|
+
completion: {
|
|
4647
|
+
type: "file",
|
|
4648
|
+
matcher: [".html"]
|
|
4649
|
+
}
|
|
4650
|
+
}),
|
|
4651
|
+
"head-html": arg(z.string().optional(), {
|
|
4652
|
+
description: "Head ERD viewer HTML file",
|
|
4653
|
+
completion: {
|
|
4654
|
+
type: "file",
|
|
4655
|
+
matcher: [".html"]
|
|
4656
|
+
}
|
|
4657
|
+
}),
|
|
4658
|
+
namespace: arg(z.string().optional(), {
|
|
4659
|
+
alias: "n",
|
|
4660
|
+
description: "TailorDB namespace name (defaults to the provided ERD schema namespace)"
|
|
4661
|
+
}),
|
|
4662
|
+
output: arg(z.string().min(1), {
|
|
4663
|
+
alias: "o",
|
|
4664
|
+
description: "Output ERD diff HTML file",
|
|
4665
|
+
completion: {
|
|
4666
|
+
type: "file",
|
|
4667
|
+
matcher: [".html"]
|
|
4668
|
+
}
|
|
4669
|
+
}),
|
|
4670
|
+
"output-json": arg(z.string().optional(), {
|
|
4671
|
+
description: "Optional output JSON file for the computed diff",
|
|
4672
|
+
completion: {
|
|
4673
|
+
type: "file",
|
|
4674
|
+
matcher: [".json"]
|
|
4675
|
+
}
|
|
4676
|
+
})
|
|
4677
|
+
}).strict(),
|
|
4678
|
+
run: (args) => {
|
|
4679
|
+
initErdCommand();
|
|
4680
|
+
const result = writeErdDiff({
|
|
4681
|
+
baseHtml: args["base-html"],
|
|
4682
|
+
headHtml: args["head-html"],
|
|
4683
|
+
namespace: args.namespace,
|
|
4684
|
+
outputHtml: args.output,
|
|
4685
|
+
outputJson: args["output-json"]
|
|
4686
|
+
});
|
|
4687
|
+
if (args.json) logger.out({
|
|
4688
|
+
namespace: result.namespace,
|
|
4689
|
+
outputHtml: result.outputHtml,
|
|
4690
|
+
outputJson: result.outputJson,
|
|
4691
|
+
summary: result.diff.summary
|
|
4692
|
+
});
|
|
4693
|
+
else logger.success(`Wrote ERD diff to ${path.relative(process.cwd(), result.outputHtml)}`);
|
|
4694
|
+
}
|
|
4695
|
+
});
|
|
4696
|
+
|
|
4179
4697
|
//#endregion
|
|
4180
4698
|
//#region src/cli/commands/tailordb/erd/serve.ts
|
|
4181
4699
|
const DEFAULT_ERD_BASE_DIR = ".tailor-sdk/erd";
|
|
@@ -4536,6 +5054,7 @@ const erdCommand = defineCommand({
|
|
|
4536
5054
|
description: "Generate TailorDB ERD viewer artifacts from local TailorDB schema. (beta)",
|
|
4537
5055
|
subCommands: {
|
|
4538
5056
|
export: erdExportCommand,
|
|
5057
|
+
diff: erdDiffCommand,
|
|
4539
5058
|
serve: erdServeCommand,
|
|
4540
5059
|
deploy: erdDeployCommand
|
|
4541
5060
|
}
|
|
@@ -4872,7 +5391,7 @@ async function fetchRemoteTypes(client, workspaceId, namespace) {
|
|
|
4872
5391
|
async function assertMigrationsReproduceLocalTypes(loaded, target) {
|
|
4873
5392
|
const { config, plugins } = loaded;
|
|
4874
5393
|
const pluginManager = plugins.length > 0 ? new PluginManager(plugins) : void 0;
|
|
4875
|
-
const { defineApplication, generatePluginFilesIfNeeded } = await import("../application-
|
|
5394
|
+
const { defineApplication, generatePluginFilesIfNeeded } = await import("../application-BakHtldG.mjs");
|
|
4876
5395
|
const application = defineApplication({
|
|
4877
5396
|
config,
|
|
4878
5397
|
pluginManager
|
|
@@ -4884,7 +5403,7 @@ async function assertMigrationsReproduceLocalTypes(loaded, target) {
|
|
|
4884
5403
|
await service.processNamespacePlugins();
|
|
4885
5404
|
}
|
|
4886
5405
|
const pluginExecutorFiles = generatePluginFilesIfNeeded(pluginManager, application.tailorDBServices, config.path);
|
|
4887
|
-
const executorService = application.executorService ?? (pluginExecutorFiles.length > 0 ? (await import("../service-
|
|
5406
|
+
const executorService = application.executorService ?? (pluginExecutorFiles.length > 0 ? (await import("../service-CRaa4Joe.mjs")).createExecutorService({ config: { files: [] } }) : void 0);
|
|
4888
5407
|
await executorService?.loadExecutors();
|
|
4889
5408
|
if (pluginExecutorFiles.length > 0) await executorService?.loadPluginExecutorFiles([...pluginExecutorFiles]);
|
|
4890
5409
|
const executorUsedTypes = /* @__PURE__ */ new Set();
|
|
@@ -5161,7 +5680,7 @@ const upgradeCommand = defineAppCommand({
|
|
|
5161
5680
|
run: async (args) => {
|
|
5162
5681
|
const { initTelemetry } = await import("../telemetry-w92bvGdC.mjs");
|
|
5163
5682
|
await initTelemetry();
|
|
5164
|
-
const { upgrade } = await import("../service-
|
|
5683
|
+
const { upgrade } = await import("../service-DDWgZL_L2.mjs");
|
|
5165
5684
|
await upgrade({
|
|
5166
5685
|
from: args.from,
|
|
5167
5686
|
dryRun: args["dry-run"],
|
|
@@ -5178,25 +5697,52 @@ const currentCommand = defineAppCommand({
|
|
|
5178
5697
|
args: z.object({}).strict(),
|
|
5179
5698
|
run: async () => {
|
|
5180
5699
|
const config = await readPlatformConfig();
|
|
5700
|
+
const profile = process.env.TAILOR_PLATFORM_PROFILE;
|
|
5701
|
+
const profileEntry = profile ? config.profiles[profile] : void 0;
|
|
5702
|
+
if (profile && !profileEntry) throw new Error(`Profile "${profile}" not found`);
|
|
5703
|
+
const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : void 0;
|
|
5704
|
+
const currentUser = profile ? profileEntry?.user ?? null : config.current_user;
|
|
5181
5705
|
const jsonOutput = logger.jsonMode;
|
|
5182
|
-
if (!
|
|
5706
|
+
if (!currentUser) throw new Error(multiline`
|
|
5183
5707
|
Current user not set.
|
|
5184
5708
|
Please login first using 'tailor-sdk login' command to register a user.
|
|
5185
5709
|
`);
|
|
5186
|
-
if (!config
|
|
5187
|
-
Current user '${
|
|
5710
|
+
if (!hasUserTokenEntry(config, currentUser, platformConfig)) throw new Error(multiline`
|
|
5711
|
+
Current user '${currentUser}' not found in registered users.
|
|
5188
5712
|
Please login again using 'tailor-sdk login' command to register the user.
|
|
5189
5713
|
`);
|
|
5190
5714
|
if (jsonOutput) {
|
|
5191
|
-
logger.out({ user:
|
|
5715
|
+
logger.out({ user: currentUser });
|
|
5192
5716
|
return;
|
|
5193
5717
|
}
|
|
5194
|
-
logger.out(
|
|
5718
|
+
logger.out(currentUser);
|
|
5195
5719
|
}
|
|
5196
5720
|
});
|
|
5197
5721
|
|
|
5198
5722
|
//#endregion
|
|
5199
5723
|
//#region src/cli/commands/user/list.ts
|
|
5724
|
+
function activeCurrentUserKey(config) {
|
|
5725
|
+
const activeProfile = process.env.TAILOR_PLATFORM_PROFILE;
|
|
5726
|
+
if (!activeProfile) {
|
|
5727
|
+
if (!config.current_user) return null;
|
|
5728
|
+
return resolveUserTokenKey(config, config.current_user);
|
|
5729
|
+
}
|
|
5730
|
+
const profile = config.profiles[activeProfile];
|
|
5731
|
+
if (!profile) return null;
|
|
5732
|
+
return resolveUserTokenKey(config, profile.user, platformConfigFromProfile(profile));
|
|
5733
|
+
}
|
|
5734
|
+
function toUserListInfo(userKey, currentUserKey) {
|
|
5735
|
+
const separatorIndex = userKey.indexOf("|");
|
|
5736
|
+
const platformUrl = separatorIndex === -1 ? null : userKey.slice(0, separatorIndex);
|
|
5737
|
+
return {
|
|
5738
|
+
user: separatorIndex === -1 ? userKey : userKey.slice(separatorIndex + 1),
|
|
5739
|
+
platformUrl,
|
|
5740
|
+
current: currentUserKey === userKey
|
|
5741
|
+
};
|
|
5742
|
+
}
|
|
5743
|
+
function formatUserListInfo(info) {
|
|
5744
|
+
return `${info.user}${info.platformUrl ? ` [${info.platformUrl}]` : ""}${info.current ? " (current)" : ""}`;
|
|
5745
|
+
}
|
|
5200
5746
|
const listCommand$1 = defineAppCommand({
|
|
5201
5747
|
name: "list",
|
|
5202
5748
|
description: "List all users.",
|
|
@@ -5213,13 +5759,15 @@ const listCommand$1 = defineAppCommand({
|
|
|
5213
5759
|
if (jsonOutput) logger.out([]);
|
|
5214
5760
|
return;
|
|
5215
5761
|
}
|
|
5762
|
+
const currentUserKey = activeCurrentUserKey(config);
|
|
5763
|
+
const userInfos = users.map((user) => toUserListInfo(user, currentUserKey));
|
|
5216
5764
|
if (jsonOutput) {
|
|
5217
|
-
logger.out(
|
|
5765
|
+
logger.out([...new Set(userInfos.map((userInfo) => userInfo.user))]);
|
|
5218
5766
|
return;
|
|
5219
5767
|
}
|
|
5220
|
-
|
|
5221
|
-
if (
|
|
5222
|
-
else logger.log(
|
|
5768
|
+
userInfos.forEach((userInfo) => {
|
|
5769
|
+
if (userInfo.current) logger.success(formatUserListInfo(userInfo), { mode: "plain" });
|
|
5770
|
+
else logger.log(formatUserListInfo(userInfo));
|
|
5223
5771
|
});
|
|
5224
5772
|
}
|
|
5225
5773
|
});
|
|
@@ -5280,6 +5828,24 @@ function printCreatedToken(name, token, write, action) {
|
|
|
5280
5828
|
`);
|
|
5281
5829
|
}
|
|
5282
5830
|
|
|
5831
|
+
//#endregion
|
|
5832
|
+
//#region src/cli/commands/user/pat/user.ts
|
|
5833
|
+
function resolvePatUser(config) {
|
|
5834
|
+
const activeProfile = process.env.TAILOR_PLATFORM_PROFILE;
|
|
5835
|
+
if (activeProfile) return config.profiles[activeProfile]?.user ?? null;
|
|
5836
|
+
return config.current_user;
|
|
5837
|
+
}
|
|
5838
|
+
async function createPatOperatorClient() {
|
|
5839
|
+
const config = await readPlatformConfig();
|
|
5840
|
+
const activeProfile = process.env.TAILOR_PLATFORM_PROFILE;
|
|
5841
|
+
const profileEntry = activeProfile ? config.profiles[activeProfile] : void 0;
|
|
5842
|
+
if (activeProfile && !profileEntry) throw new Error(`Profile "${activeProfile}" not found`);
|
|
5843
|
+
const platformConfig = profileEntry ? platformConfigFromProfile(profileEntry) : void 0;
|
|
5844
|
+
const user = resolvePatUser(config);
|
|
5845
|
+
if (!user) throw new Error("No user logged in.\nPlease login first using 'tailor-sdk login' command.");
|
|
5846
|
+
return await initOperatorClient(await fetchLatestToken(config, user, platformConfig), platformConfig);
|
|
5847
|
+
}
|
|
5848
|
+
|
|
5283
5849
|
//#endregion
|
|
5284
5850
|
//#region src/cli/commands/user/pat/create.ts
|
|
5285
5851
|
const createCommand = defineAppCommand({
|
|
@@ -5297,12 +5863,7 @@ const createCommand = defineAppCommand({
|
|
|
5297
5863
|
}).strict(),
|
|
5298
5864
|
run: async (args) => {
|
|
5299
5865
|
await assertWritable();
|
|
5300
|
-
const
|
|
5301
|
-
if (!config.current_user) throw new Error(multiline`
|
|
5302
|
-
No user logged in.
|
|
5303
|
-
Please login first using 'tailor-sdk login' command.
|
|
5304
|
-
`);
|
|
5305
|
-
const client = await initOperatorClient(await fetchLatestToken(config, config.current_user));
|
|
5866
|
+
const client = await createPatOperatorClient();
|
|
5306
5867
|
const scopes = getScopesFromWriteFlag(args.write);
|
|
5307
5868
|
const result = await client.createPersonalAccessToken({
|
|
5308
5869
|
name: args.name,
|
|
@@ -5324,12 +5885,7 @@ const deleteCommand = defineAppCommand({
|
|
|
5324
5885
|
}) }).strict(),
|
|
5325
5886
|
run: async (args) => {
|
|
5326
5887
|
await assertWritable();
|
|
5327
|
-
|
|
5328
|
-
if (!config.current_user) throw new Error(multiline`
|
|
5329
|
-
No user logged in.
|
|
5330
|
-
Please login first using 'tailor-sdk login' command.
|
|
5331
|
-
`);
|
|
5332
|
-
await (await initOperatorClient(await fetchLatestToken(config, config.current_user))).deletePersonalAccessToken({ name: args.name });
|
|
5888
|
+
await (await createPatOperatorClient()).deletePersonalAccessToken({ name: args.name });
|
|
5333
5889
|
logger.success(`Personal access token "${args.name}" deleted successfully.`);
|
|
5334
5890
|
}
|
|
5335
5891
|
});
|
|
@@ -5342,12 +5898,7 @@ const listCommand = defineAppCommand({
|
|
|
5342
5898
|
args: z.object({ ...paginationArgs() }).strict(),
|
|
5343
5899
|
run: async (args) => {
|
|
5344
5900
|
const jsonOutput = logger.jsonMode;
|
|
5345
|
-
const
|
|
5346
|
-
if (!config.current_user) throw new Error(multiline`
|
|
5347
|
-
No user logged in.
|
|
5348
|
-
Please login first using 'tailor-sdk login' command.
|
|
5349
|
-
`);
|
|
5350
|
-
const client = await initOperatorClient(await fetchLatestToken(config, config.current_user));
|
|
5901
|
+
const client = await createPatOperatorClient();
|
|
5351
5902
|
const pageDirection = toPageDirection(args.order);
|
|
5352
5903
|
const pats = await fetchPaged(async (pageToken, pageSize) => {
|
|
5353
5904
|
const { personalAccessTokens, nextPageToken } = await client.listPersonalAccessTokens({
|
|
@@ -5395,12 +5946,7 @@ const updateCommand = defineAppCommand({
|
|
|
5395
5946
|
}).strict(),
|
|
5396
5947
|
run: async (args) => {
|
|
5397
5948
|
await assertWritable();
|
|
5398
|
-
const
|
|
5399
|
-
if (!config.current_user) throw new Error(multiline`
|
|
5400
|
-
No user logged in.
|
|
5401
|
-
Please login first using 'tailor-sdk login' command.
|
|
5402
|
-
`);
|
|
5403
|
-
const client = await initOperatorClient(await fetchLatestToken(config, config.current_user));
|
|
5949
|
+
const client = await createPatOperatorClient();
|
|
5404
5950
|
await client.deletePersonalAccessToken({ name: args.name });
|
|
5405
5951
|
const scopes = getScopesFromWriteFlag(args.write);
|
|
5406
5952
|
const result = await client.createPersonalAccessToken({
|
|
@@ -5439,11 +5985,17 @@ const switchCommand = defineAppCommand({
|
|
|
5439
5985
|
}) }).strict(),
|
|
5440
5986
|
run: async (args) => {
|
|
5441
5987
|
const config = await readPlatformConfig();
|
|
5442
|
-
|
|
5988
|
+
const activeProfileName = process.env.TAILOR_PLATFORM_PROFILE;
|
|
5989
|
+
const activeProfileEntry = activeProfileName ? config.profiles[activeProfileName] : void 0;
|
|
5990
|
+
if (activeProfileName && !activeProfileEntry) throw new Error(`Profile "${activeProfileName}" not found`);
|
|
5991
|
+
const platformConfig = activeProfileEntry ? platformConfigFromProfile(activeProfileEntry) : void 0;
|
|
5992
|
+
if (args.user.includes("|")) throw new Error(`User "${args.user}" looks like a platform-scoped token key. Pass the user name without the platform URL and select the platform with TAILOR_PLATFORM_URL or a profile.`);
|
|
5993
|
+
if (!hasUserTokenEntry(config, args.user, platformConfig)) throw new Error(multiline`
|
|
5443
5994
|
User "${args.user}" not found.
|
|
5444
5995
|
Please login first using 'tailor-sdk login' command to register this user.
|
|
5445
5996
|
`);
|
|
5446
|
-
|
|
5997
|
+
if (activeProfileEntry) activeProfileEntry.user = args.user;
|
|
5998
|
+
else config.current_user = args.user;
|
|
5447
5999
|
writePlatformConfig(config);
|
|
5448
6000
|
logger.success(`Current user set to "${args.user}" successfully.`);
|
|
5449
6001
|
}
|
|
@@ -5588,7 +6140,7 @@ runMain(mainCommand, {
|
|
|
5588
6140
|
if (isVerbose() && error.stack) logger.debug(`\nStack trace:\n${error.stack}`);
|
|
5589
6141
|
} else logger.error(`Unknown error: ${error}`);
|
|
5590
6142
|
if (!isCLIError(error) && (!(error instanceof Error) || error instanceof TypeError || error instanceof RangeError)) {
|
|
5591
|
-
const { reportCrash } = await import("../crashreport-
|
|
6143
|
+
const { reportCrash } = await import("../crashreport-BwF8cHF0.mjs");
|
|
5592
6144
|
await reportCrash(error, "handledError");
|
|
5593
6145
|
}
|
|
5594
6146
|
}
|