@tailor-platform/sdk 1.54.3 → 1.55.1
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 +36 -0
- package/dist/{actor-Cjae_LGD.d.mts → actor-J2gJ0eK5.d.mts} +2 -2
- package/dist/application-DM8q9GDI.mjs +4 -0
- package/dist/{application-BfGje3iZ.mjs → application-DzUlASfA.mjs} +333 -4
- package/dist/application-DzUlASfA.mjs.map +1 -0
- package/dist/brand-DlnJ375c.mjs.map +1 -1
- package/dist/cli/index.mjs +101 -38
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +1334 -176
- package/dist/cli/lib.mjs +3 -3
- package/dist/{client-CGO7gniI.mjs → client-DLPEPJ_s.mjs} +24 -19
- package/dist/client-DLPEPJ_s.mjs.map +1 -0
- package/dist/{client-yfFdZU9s.mjs → client-DrzwCD1W.mjs} +1 -1
- package/dist/configure/index.d.mts +5 -4
- package/dist/configure/index.mjs +47 -1
- package/dist/configure/index.mjs.map +1 -1
- package/dist/{crashreport-DGdAgX8Y.mjs → crashreport-Bm2mN5tg.mjs} +2 -2
- package/dist/{crashreport-DGdAgX8Y.mjs.map → crashreport-Bm2mN5tg.mjs.map} +1 -1
- package/dist/{crashreport-DnwIxpzF.mjs → crashreport-C5oHvHUC.mjs} +1 -1
- package/dist/{index-qQYMbkT-.d.mts → index-BE-fpxIo.d.mts} +2 -2
- package/dist/{index-DJUoIn_v.d.mts → index-BLsnrEtc.d.mts} +97 -5
- package/dist/{index-DrYHpTja.d.mts → index-D9xG-a6Y.d.mts} +2 -2
- package/dist/{index-CyyoHrPK.d.mts → index-S6-FtUpA.d.mts} +2 -2
- package/dist/{index-Cf1Lo_XT.d.mts → index-cHqh66cF.d.mts} +2 -2
- 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/seed/index.d.mts +1 -1
- package/dist/plugin/index.d.mts +2 -2
- package/dist/plugin-BuE5ZOnW.d.mts +634 -0
- package/dist/{runtime-DpbAj_8a.mjs → runtime-CgGeIoxi.mjs} +366 -164
- package/dist/runtime-CgGeIoxi.mjs.map +1 -0
- package/dist/seed-DfLyRh63.mjs.map +1 -1
- package/dist/tailordb-BlBGmQK-.d.mts +863 -0
- package/dist/utils/test/index.d.mts +3 -3
- package/dist/vitest/index.d.mts +25 -1
- package/dist/vitest/index.mjs +57 -12
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/{workflow.generated-CWi2rivQ.d.mts → workflow.generated-CQg1_Ami.d.mts} +183 -8
- package/docs/cli-reference.md +12 -0
- package/docs/services/http-adapter.md +100 -0
- package/package.json +11 -11
- package/dist/application-BfGje3iZ.mjs.map +0 -1
- package/dist/application-BsipSxp3.mjs +0 -4
- package/dist/client-CGO7gniI.mjs.map +0 -1
- package/dist/runtime-DpbAj_8a.mjs.map +0 -1
- package/dist/tailor-db-field-D0qg8s4U.d.mts +0 -1639
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
import { t as db } from "./schema-DKsNhbav.mjs";
|
|
3
|
-
import { $ as FilterSchema, A as FunctionExecution_Status, B as AuthOAuth2Client_GrantType, C as TailorDBType_Permission_Operator, D as IdPLang, E as PipelineResolver_OperationType, F as AuthConnection_Type, H as AuthSCIMAttribute_Type, I as AuthHookPoint, J as GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus, K as TenantProviderConfig_TenantProviderType, L as AuthIDPConfig_AuthType, M as ExecutorJobStatus, N as ExecutorTargetType, O as IdPPermissionOperator, P as ExecutorTriggerType, Q as Condition_Operator, R as AuthInvokerSchema, S as TailorDBGQLPermission_Permit, T as TailorDBType_PermitAction, U as AuthSCIMAttribute_Uniqueness, V as AuthSCIMAttribute_Mutability, W as AuthSCIMConfig_AuthorizationType, X as Subgraph_ServiceType, Y as ApplicationSchemaUpdateAttemptStatus, Z as ConditionSchema, _ as WorkspacePlatformUserRole, a as fetchMachineUserToken, b as TailorDBGQLPermission_Action, d as initOperatorClient, et as PageDirection, g as OperatorService, h as userAgent, i as fetchAll, k as IdPPermissionPermit, m as resolveStaticWebsiteUrls, o as fetchPaged, p as platformBaseUrl, q as UserProfileProviderConfig_UserProfileProviderType, v as WorkflowExecution_Status, w as TailorDBType_Permission_Permit, x as TailorDBGQLPermission_Operator, y as WorkflowJobExecution_Status, z as AuthOAuth2Client_ClientType } from "./client-
|
|
3
|
+
import { $ as FilterSchema, A as FunctionExecution_Status, B as AuthOAuth2Client_GrantType, C as TailorDBType_Permission_Operator, D as IdPLang, E as PipelineResolver_OperationType, F as AuthConnection_Type, H as AuthSCIMAttribute_Type, I as AuthHookPoint, J as GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus, K as TenantProviderConfig_TenantProviderType, L as AuthIDPConfig_AuthType, M as ExecutorJobStatus, N as ExecutorTargetType, O as IdPPermissionOperator, P as ExecutorTriggerType, Q as Condition_Operator, R as AuthInvokerSchema, S as TailorDBGQLPermission_Permit, T as TailorDBType_PermitAction, U as AuthSCIMAttribute_Uniqueness, V as AuthSCIMAttribute_Mutability, W as AuthSCIMConfig_AuthorizationType, X as Subgraph_ServiceType, Y as ApplicationSchemaUpdateAttemptStatus, Z as ConditionSchema, _ as WorkspacePlatformUserRole, a as fetchMachineUserToken, b as TailorDBGQLPermission_Action, d as initOperatorClient, et as PageDirection, g as OperatorService, h as userAgent, i as fetchAll, k as IdPPermissionPermit, m as resolveStaticWebsiteUrls, o as fetchPaged, p as platformBaseUrl, q as UserProfileProviderConfig_UserProfileProviderType, v as WorkflowExecution_Status, w as TailorDBType_Permission_Permit, x as TailorDBGQLPermission_Operator, y as WorkflowJobExecution_Status, z as AuthOAuth2Client_ClientType } from "./client-DLPEPJ_s.mjs";
|
|
4
4
|
import { a as parseBoolean, i as symbols, n as logger, r as styles, t as CIPromptError } from "./logger-DpJyJvNz.mjs";
|
|
5
|
-
import { C as
|
|
5
|
+
import { C as loadAccessToken, E as readPlatformConfig, T as loadWorkspaceId, _ as createBundleCache, b as loadConfig, c as createExecutorService, d as buildExecutorArgsExpr, f as buildResolverOperationHookExpr, g as loadFilesWithIgnores, h as stringifyFunction, k as writePlatformConfig, m as TailorDBTypeSchema, n as generatePluginFilesIfNeeded, p as OAuth2ClientSchema, r as loadApplication, s as HTTP_METHODS, t as defineApplication, v as getDistDir, w as loadConfigPath, y as hashFile } from "./application-DzUlASfA.mjs";
|
|
6
6
|
import { t as multiline } from "./multiline-Cf9ODpr1.mjs";
|
|
7
7
|
import { t as readPackageJson } from "./package-json-DcQApfPQ.mjs";
|
|
8
8
|
import { n as isCLIError, t as createCLIError } from "./errors-EsY4XO6O.mjs";
|
|
@@ -717,6 +717,34 @@ function coerceFieldValue(field, raw) {
|
|
|
717
717
|
}
|
|
718
718
|
return raw;
|
|
719
719
|
}
|
|
720
|
+
/**
|
|
721
|
+
* Collapse top-level body keys that address a known input field by its
|
|
722
|
+
* protobuf name (snake_case) or JSON name to the field's `localName`. protojson
|
|
723
|
+
* accepts every alias, so converging them here lets the presence checks below
|
|
724
|
+
* reason in a single namespace — otherwise a `--body` written as
|
|
725
|
+
* `{"workspace_id": ...}` slips past the camelCase check and we inject a second
|
|
726
|
+
* `workspaceId`, which the server rejects as a duplicate field. When both forms
|
|
727
|
+
* are present the canonical key wins and the alias is dropped.
|
|
728
|
+
* @param body - The parsed body object to mutate
|
|
729
|
+
* @param fields - The target endpoint's input fields
|
|
730
|
+
* @returns Whether any key was rewritten
|
|
731
|
+
*/
|
|
732
|
+
function normalizeBodyFieldKeys(body, fields) {
|
|
733
|
+
const aliasToLocal = /* @__PURE__ */ new Map();
|
|
734
|
+
for (const f of fields) {
|
|
735
|
+
aliasToLocal.set(f.name, f.localName);
|
|
736
|
+
aliasToLocal.set(f.jsonName, f.localName);
|
|
737
|
+
}
|
|
738
|
+
let changed = false;
|
|
739
|
+
for (const key of Object.keys(body)) {
|
|
740
|
+
const local = aliasToLocal.get(key);
|
|
741
|
+
if (!local || local === key) continue;
|
|
742
|
+
if (!Object.hasOwn(body, local)) body[local] = body[key];
|
|
743
|
+
delete body[key];
|
|
744
|
+
changed = true;
|
|
745
|
+
}
|
|
746
|
+
return changed;
|
|
747
|
+
}
|
|
720
748
|
const FORBIDDEN_SEGMENTS = new Set([
|
|
721
749
|
"__proto__",
|
|
722
750
|
"constructor",
|
|
@@ -833,15 +861,16 @@ Use \`--field key=value\` (repeatable) to set request body fields without writin
|
|
|
833
861
|
mutated = true;
|
|
834
862
|
}
|
|
835
863
|
if (parsedBody && method) {
|
|
864
|
+
if (normalizeBodyFieldKeys(parsedBody, method.input.fields)) mutated = true;
|
|
836
865
|
const fieldNames = method.input.fields.map((f) => f.localName);
|
|
837
|
-
if (fieldNames.includes("workspaceId") && !("workspaceId"
|
|
866
|
+
if (fieldNames.includes("workspaceId") && !Object.hasOwn(parsedBody, "workspaceId")) try {
|
|
838
867
|
parsedBody.workspaceId = await loadWorkspaceId({
|
|
839
868
|
workspaceId: args["workspace-id"],
|
|
840
869
|
profile: args.profile
|
|
841
870
|
});
|
|
842
871
|
mutated = true;
|
|
843
872
|
} catch {}
|
|
844
|
-
if (fieldNames.includes("namespaceName") && !("namespaceName"
|
|
873
|
+
if (fieldNames.includes("namespaceName") && !Object.hasOwn(parsedBody, "namespaceName")) try {
|
|
845
874
|
const { config } = await loadConfig(args.config);
|
|
846
875
|
const ns = resolveNamespaceName(methodName, config);
|
|
847
876
|
if (ns) {
|
|
@@ -1608,10 +1637,14 @@ function createChangeSet(title) {
|
|
|
1608
1637
|
print: () => {
|
|
1609
1638
|
if (isEmpty()) return;
|
|
1610
1639
|
logger.log(styles.bold(`${title}:`));
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1640
|
+
const printItem = (symbol, item) => {
|
|
1641
|
+
logger.log(` ${symbol} ${item.name}`);
|
|
1642
|
+
for (const detail of item.details ?? []) logger.log(` ${detail}`);
|
|
1643
|
+
};
|
|
1644
|
+
creates.forEach((item) => printItem(symbols.create, item));
|
|
1645
|
+
deletes.forEach((item) => printItem(symbols.delete, item));
|
|
1646
|
+
updates.forEach((item) => printItem(symbols.update, item));
|
|
1647
|
+
replaces.forEach((item) => printItem(symbols.replace, item));
|
|
1615
1648
|
}
|
|
1616
1649
|
};
|
|
1617
1650
|
}
|
|
@@ -1799,6 +1832,17 @@ function normalizeSubgraphs(subgraphs) {
|
|
|
1799
1832
|
return left.serviceNamespace.localeCompare(right.serviceNamespace);
|
|
1800
1833
|
});
|
|
1801
1834
|
}
|
|
1835
|
+
function normalizeHttpAdapters(httpAdapters) {
|
|
1836
|
+
return [...httpAdapters ?? []].map((adapter) => ({
|
|
1837
|
+
name: adapter.name ?? "",
|
|
1838
|
+
pathPattern: adapter.pathPattern ?? "",
|
|
1839
|
+
methods: sortStrings(adapter.methods),
|
|
1840
|
+
inputScript: adapter.inputScript ?? "",
|
|
1841
|
+
outputScript: adapter.outputScript ?? "",
|
|
1842
|
+
enabled: adapter.enabled ?? true,
|
|
1843
|
+
priority: adapter.priority ?? 0
|
|
1844
|
+
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
1845
|
+
}
|
|
1802
1846
|
function toComparableApplication(input) {
|
|
1803
1847
|
return {
|
|
1804
1848
|
authNamespace: input.authNamespace,
|
|
@@ -1807,10 +1851,11 @@ function toComparableApplication(input) {
|
|
|
1807
1851
|
subgraphs: [...input.subgraphs],
|
|
1808
1852
|
allowedIpAddresses: sortStrings(input.allowedIpAddresses),
|
|
1809
1853
|
disableIntrospection: input.disableIntrospection,
|
|
1810
|
-
disabled: input.disabled
|
|
1854
|
+
disabled: input.disabled,
|
|
1855
|
+
httpAdapters: [...input.httpAdapters]
|
|
1811
1856
|
};
|
|
1812
1857
|
}
|
|
1813
|
-
function normalizeComparableApplication(application, authNamespace, authIdpConfigName, cors) {
|
|
1858
|
+
function normalizeComparableApplication(application, authNamespace, authIdpConfigName, cors, httpAdapters) {
|
|
1814
1859
|
return toComparableApplication({
|
|
1815
1860
|
authNamespace: authNamespace ?? "",
|
|
1816
1861
|
authIdpConfigName: authIdpConfigName ?? "",
|
|
@@ -1818,7 +1863,8 @@ function normalizeComparableApplication(application, authNamespace, authIdpConfi
|
|
|
1818
1863
|
subgraphs: normalizeSubgraphs(application.subgraphs.map((subgraph) => protoSubgraph(subgraph))),
|
|
1819
1864
|
allowedIpAddresses: application.config.allowedIpAddresses ?? [],
|
|
1820
1865
|
disableIntrospection: application.config.disableIntrospection ?? false,
|
|
1821
|
-
disabled: false
|
|
1866
|
+
disabled: false,
|
|
1867
|
+
httpAdapters: normalizeHttpAdapters(httpAdapters)
|
|
1822
1868
|
});
|
|
1823
1869
|
}
|
|
1824
1870
|
function normalizeComparableExistingApplication(app) {
|
|
@@ -1829,7 +1875,8 @@ function normalizeComparableExistingApplication(app) {
|
|
|
1829
1875
|
subgraphs: normalizeSubgraphs(app.subgraphs),
|
|
1830
1876
|
allowedIpAddresses: app.allowedIpAddresses,
|
|
1831
1877
|
disableIntrospection: app.disableIntrospection,
|
|
1832
|
-
disabled: app.disabled
|
|
1878
|
+
disabled: app.disabled,
|
|
1879
|
+
httpAdapters: normalizeHttpAdapters(app.httpAdapters)
|
|
1833
1880
|
});
|
|
1834
1881
|
}
|
|
1835
1882
|
function areApplicationsEqual(existing, desired) {
|
|
@@ -1838,9 +1885,10 @@ function areApplicationsEqual(existing, desired) {
|
|
|
1838
1885
|
/**
|
|
1839
1886
|
* Plan application changes based on current and desired state.
|
|
1840
1887
|
* @param context - Planning context
|
|
1888
|
+
* @param httpAdapterBuildResult - Bundled HTTP adapter scripts to embed on the Application
|
|
1841
1889
|
* @returns Planned changes
|
|
1842
1890
|
*/
|
|
1843
|
-
async function planApplication(context) {
|
|
1891
|
+
async function planApplication(context, httpAdapterBuildResult) {
|
|
1844
1892
|
const { client, workspaceId, application, forRemoval } = context;
|
|
1845
1893
|
const changeSet = createChangeSet("Applications");
|
|
1846
1894
|
const existingApplications = await fetchAll(async (pageToken, maxPageSize) => {
|
|
@@ -1902,7 +1950,8 @@ async function planApplication(context) {
|
|
|
1902
1950
|
});
|
|
1903
1951
|
const expectedLocalWebsites = new Set(application.staticWebsiteServices.map((website) => website.name));
|
|
1904
1952
|
const resolvedCors = await resolveStaticWebsiteUrls(client, workspaceId, application.config.cors, "CORS", { expectedLocalNames: expectedLocalWebsites });
|
|
1905
|
-
const
|
|
1953
|
+
const httpAdapters = buildHttpAdapters(application, httpAdapterBuildResult);
|
|
1954
|
+
const desired = normalizeComparableApplication(application, authNamespace, authIdpConfigName, resolvedCors, httpAdapters);
|
|
1906
1955
|
const request = {
|
|
1907
1956
|
workspaceId,
|
|
1908
1957
|
applicationName: application.name,
|
|
@@ -1911,7 +1960,8 @@ async function planApplication(context) {
|
|
|
1911
1960
|
cors: application.config.cors,
|
|
1912
1961
|
subgraphs: application.subgraphs.map((subgraph) => protoSubgraph(subgraph)),
|
|
1913
1962
|
allowedIpAddresses: application.config.allowedIpAddresses,
|
|
1914
|
-
disableIntrospection: application.config.disableIntrospection
|
|
1963
|
+
disableIntrospection: application.config.disableIntrospection,
|
|
1964
|
+
httpAdapters
|
|
1915
1965
|
};
|
|
1916
1966
|
const existing = existingApplications.find((app) => app.name === application.name);
|
|
1917
1967
|
if (application.id) {
|
|
@@ -1935,12 +1985,20 @@ async function planApplication(context) {
|
|
|
1935
1985
|
metaRequest
|
|
1936
1986
|
};
|
|
1937
1987
|
if (isOwnedByApp(labels, application.name, application.id) && hasMatchingSdkVersion(labels, metaRequest.labels) && areApplicationsEqual(existing, desired)) changeSet.unchanged.push(update);
|
|
1938
|
-
else
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
}
|
|
1988
|
+
else {
|
|
1989
|
+
const details = diffHttpAdapterDisplay(existing.httpAdapters, httpAdapters);
|
|
1990
|
+
if (details.length > 0) update.details = details;
|
|
1991
|
+
changeSet.updates.push(update);
|
|
1992
|
+
}
|
|
1993
|
+
} else {
|
|
1994
|
+
const details = diffHttpAdapterDisplay(void 0, httpAdapters);
|
|
1995
|
+
changeSet.creates.push({
|
|
1996
|
+
name: application.name,
|
|
1997
|
+
request,
|
|
1998
|
+
metaRequest,
|
|
1999
|
+
details: details.length > 0 ? details : void 0
|
|
2000
|
+
});
|
|
2001
|
+
}
|
|
1944
2002
|
return changeSet;
|
|
1945
2003
|
}
|
|
1946
2004
|
async function fetchAppLabels(client, workspaceId, appName) {
|
|
@@ -1952,6 +2010,59 @@ async function fetchAppLabels(client, workspaceId, appName) {
|
|
|
1952
2010
|
throw error;
|
|
1953
2011
|
}
|
|
1954
2012
|
}
|
|
2013
|
+
/**
|
|
2014
|
+
* Build per-adapter diff lines for the application plan display. The platform
|
|
2015
|
+
* models HTTP adapters as an embedded Application field (no dedicated RPC), so
|
|
2016
|
+
* adapter changes surface as an Application update; these lines show which
|
|
2017
|
+
* adapter actually changed instead of just `~ <app>`.
|
|
2018
|
+
* @param existingAdapters - HTTP adapters currently deployed on the application
|
|
2019
|
+
* @param desiredAdapters - HTTP adapters built from the local config
|
|
2020
|
+
* @returns Indented diff lines (`+`/`~`/`-` per adapter), sorted by name
|
|
2021
|
+
*/
|
|
2022
|
+
function diffHttpAdapterDisplay(existingAdapters, desiredAdapters) {
|
|
2023
|
+
const existingByName = new Map((existingAdapters ?? []).map((a) => [a.name ?? "", a]));
|
|
2024
|
+
const desiredByName = new Map(desiredAdapters.map((a) => [a.name ?? "", a]));
|
|
2025
|
+
const entries = [];
|
|
2026
|
+
for (const [name, desired] of desiredByName) {
|
|
2027
|
+
const existing = existingByName.get(name);
|
|
2028
|
+
if (!existing) entries.push({
|
|
2029
|
+
name,
|
|
2030
|
+
symbol: symbols.create
|
|
2031
|
+
});
|
|
2032
|
+
else if (!areNormalizedEqual(normalizeHttpAdapters([existing])[0], normalizeHttpAdapters([desired])[0])) entries.push({
|
|
2033
|
+
name,
|
|
2034
|
+
symbol: symbols.update
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
2037
|
+
for (const name of existingByName.keys()) if (!desiredByName.has(name)) entries.push({
|
|
2038
|
+
name,
|
|
2039
|
+
symbol: symbols.delete
|
|
2040
|
+
});
|
|
2041
|
+
return entries.sort((left, right) => left.name.localeCompare(right.name)).map((entry) => `${entry.symbol} ${entry.name} (httpAdapter)`);
|
|
2042
|
+
}
|
|
2043
|
+
function buildHttpAdapters(application, httpAdapterBuildResult) {
|
|
2044
|
+
const adapters = application.httpAdapterService?.adapters ?? [];
|
|
2045
|
+
if (adapters.length === 0) return [];
|
|
2046
|
+
return adapters.map((loaded) => {
|
|
2047
|
+
const inputScript = httpAdapterBuildResult?.bundledInputs.get(loaded.adapter.name);
|
|
2048
|
+
if (!inputScript) throw new Error(`HTTP adapter "${loaded.adapter.name}" was loaded but no bundled input script is available`);
|
|
2049
|
+
let outputScript = "";
|
|
2050
|
+
if (loaded.hasOutput) {
|
|
2051
|
+
const bundled = httpAdapterBuildResult?.bundledOutputs.get(loaded.adapter.name);
|
|
2052
|
+
if (!bundled) throw new Error(`HTTP adapter "${loaded.adapter.name}" declares an output handler but no bundled output script is available`);
|
|
2053
|
+
outputScript = bundled;
|
|
2054
|
+
}
|
|
2055
|
+
return {
|
|
2056
|
+
name: loaded.adapter.name,
|
|
2057
|
+
pathPattern: loaded.adapter.pathPattern,
|
|
2058
|
+
methods: loaded.methods.map((m) => HTTP_METHODS[m]),
|
|
2059
|
+
inputScript,
|
|
2060
|
+
outputScript,
|
|
2061
|
+
enabled: loaded.adapter.enabled,
|
|
2062
|
+
priority: loaded.adapter.priority
|
|
2063
|
+
};
|
|
2064
|
+
});
|
|
2065
|
+
}
|
|
1955
2066
|
function protoSubgraph(subgraph) {
|
|
1956
2067
|
let serviceType;
|
|
1957
2068
|
switch (subgraph.Type) {
|
|
@@ -4732,6 +4843,88 @@ function normalizeAuthInvoker(authInvoker, authNamespace, context) {
|
|
|
4732
4843
|
return authInvoker;
|
|
4733
4844
|
}
|
|
4734
4845
|
|
|
4846
|
+
//#endregion
|
|
4847
|
+
//#region src/cli/commands/deploy/owned-resource.ts
|
|
4848
|
+
/**
|
|
4849
|
+
* Fetch a workspace-scoped resource list and attach SDK ownership metadata.
|
|
4850
|
+
* @template T
|
|
4851
|
+
* @param params - Resource fetch parameters
|
|
4852
|
+
* @param params.client - Operator client instance
|
|
4853
|
+
* @param params.workspaceId - Workspace ID
|
|
4854
|
+
* @param params.fetchPage - Function that fetches one resource page
|
|
4855
|
+
* @param params.getName - Function that extracts the resource name
|
|
4856
|
+
* @param params.getTrn - Function that builds the resource TRN
|
|
4857
|
+
* @returns Existing resources keyed by resource name, with SDK labels attached
|
|
4858
|
+
*/
|
|
4859
|
+
async function fetchExistingResourcesWithLabels(params) {
|
|
4860
|
+
const { client, workspaceId, fetchPage, getName, getTrn } = params;
|
|
4861
|
+
const withoutLabel = await fetchAll(async (pageToken, maxPageSize) => {
|
|
4862
|
+
try {
|
|
4863
|
+
return await fetchPage(pageToken, maxPageSize);
|
|
4864
|
+
} catch (error) {
|
|
4865
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) return [[], ""];
|
|
4866
|
+
throw error;
|
|
4867
|
+
}
|
|
4868
|
+
});
|
|
4869
|
+
const existingResources = {};
|
|
4870
|
+
await Promise.all(withoutLabel.map(async (resource) => {
|
|
4871
|
+
const name = getName(resource);
|
|
4872
|
+
if (!name) return;
|
|
4873
|
+
const { metadata } = await client.getMetadata({ trn: getTrn(workspaceId, name) });
|
|
4874
|
+
existingResources[name] = {
|
|
4875
|
+
resource,
|
|
4876
|
+
label: metadata?.labels[sdkNameLabelKey],
|
|
4877
|
+
allLabels: metadata?.labels
|
|
4878
|
+
};
|
|
4879
|
+
}));
|
|
4880
|
+
return existingResources;
|
|
4881
|
+
}
|
|
4882
|
+
/**
|
|
4883
|
+
* Determine whether a same-named existing resource is managed by this app.
|
|
4884
|
+
* Records the user-facing confirmation data when ownership does not match.
|
|
4885
|
+
* @param params - Ownership classification inputs
|
|
4886
|
+
* @param params.labels - Existing resource labels
|
|
4887
|
+
* @param params.ownerLabel - Existing `sdk-name` label, when present
|
|
4888
|
+
* @param params.appName - Current application name
|
|
4889
|
+
* @param params.appId - Current application id, when present
|
|
4890
|
+
* @param params.resourceType - Resource kind for confirmation messages
|
|
4891
|
+
* @param params.resourceName - Resource name for confirmation messages
|
|
4892
|
+
* @param params.conflicts - Conflict accumulator
|
|
4893
|
+
* @param params.unmanaged - Unmanaged-resource accumulator
|
|
4894
|
+
* @returns True when the resource is owned by the current app
|
|
4895
|
+
*/
|
|
4896
|
+
function trackDesiredResourceOwnership(params) {
|
|
4897
|
+
const { labels, ownerLabel, appName, appId, resourceType, resourceName, conflicts, unmanaged } = params;
|
|
4898
|
+
const owned = isOwnedByApp(labels, appName, appId);
|
|
4899
|
+
if (!owned) if (!ownerLabel) unmanaged.push({
|
|
4900
|
+
resourceType,
|
|
4901
|
+
resourceName
|
|
4902
|
+
});
|
|
4903
|
+
else conflicts.push({
|
|
4904
|
+
resourceType,
|
|
4905
|
+
resourceName,
|
|
4906
|
+
currentOwner: ownerLabel
|
|
4907
|
+
});
|
|
4908
|
+
return owned;
|
|
4909
|
+
}
|
|
4910
|
+
/**
|
|
4911
|
+
* Determine whether a remote-only resource is still owned by this app.
|
|
4912
|
+
* Also records other SDK owners so renamed-empty applications can be handled.
|
|
4913
|
+
* @param params - Ownership classification inputs
|
|
4914
|
+
* @param params.labels - Existing resource labels
|
|
4915
|
+
* @param params.ownerLabel - Existing `sdk-name` label, when present
|
|
4916
|
+
* @param params.appName - Current application name
|
|
4917
|
+
* @param params.appId - Current application id, when present
|
|
4918
|
+
* @param params.resourceOwners - Other-owner accumulator
|
|
4919
|
+
* @returns True when the resource is owned by the current app
|
|
4920
|
+
*/
|
|
4921
|
+
function trackRemainingResourceOwner(params) {
|
|
4922
|
+
const { labels, ownerLabel, appName, appId, resourceOwners } = params;
|
|
4923
|
+
const owned = isOwnedByApp(labels, appName, appId);
|
|
4924
|
+
if (ownerLabel && !owned) resourceOwners.add(ownerLabel);
|
|
4925
|
+
return owned;
|
|
4926
|
+
}
|
|
4927
|
+
|
|
4735
4928
|
//#endregion
|
|
4736
4929
|
//#region src/cli/commands/deploy/executor.ts
|
|
4737
4930
|
/**
|
|
@@ -4766,28 +4959,20 @@ async function planExecutor(context) {
|
|
|
4766
4959
|
const conflicts = [];
|
|
4767
4960
|
const unmanaged = [];
|
|
4768
4961
|
const resourceOwners = /* @__PURE__ */ new Set();
|
|
4769
|
-
const
|
|
4770
|
-
|
|
4962
|
+
const existingExecutors = await fetchExistingResourcesWithLabels({
|
|
4963
|
+
client,
|
|
4964
|
+
workspaceId,
|
|
4965
|
+
fetchPage: async (pageToken, pageSize) => {
|
|
4771
4966
|
const { executors, nextPageToken } = await client.listExecutorExecutors({
|
|
4772
4967
|
workspaceId,
|
|
4773
4968
|
pageToken,
|
|
4774
|
-
pageSize
|
|
4969
|
+
pageSize
|
|
4775
4970
|
});
|
|
4776
4971
|
return [executors, nextPageToken];
|
|
4777
|
-
}
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
}
|
|
4972
|
+
},
|
|
4973
|
+
getName: (resource) => resource.name,
|
|
4974
|
+
getTrn: trn$3
|
|
4781
4975
|
});
|
|
4782
|
-
const existingExecutors = {};
|
|
4783
|
-
await Promise.all(withoutLabel.map(async (resource) => {
|
|
4784
|
-
const { metadata } = await client.getMetadata({ trn: trn$3(workspaceId, resource.name) });
|
|
4785
|
-
existingExecutors[resource.name] = {
|
|
4786
|
-
resource,
|
|
4787
|
-
label: metadata?.labels[sdkNameLabelKey],
|
|
4788
|
-
allLabels: metadata?.labels
|
|
4789
|
-
};
|
|
4790
|
-
}));
|
|
4791
4976
|
const executors = forRemoval ? {} : await application.executorService?.loadExecutors() ?? {};
|
|
4792
4977
|
for (const executor of Object.values(executors)) {
|
|
4793
4978
|
const existing = existingExecutors[executor.name];
|
|
@@ -4798,17 +4983,16 @@ async function planExecutor(context) {
|
|
|
4798
4983
|
});
|
|
4799
4984
|
const desiredExecutor = protoExecutor(application, executor);
|
|
4800
4985
|
if (existing) {
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
else conflicts.push({
|
|
4986
|
+
if (trackDesiredResourceOwnership({
|
|
4987
|
+
labels: existing.allLabels,
|
|
4988
|
+
ownerLabel: existing.label,
|
|
4989
|
+
appName: application.name,
|
|
4990
|
+
appId: application.id,
|
|
4807
4991
|
resourceType: "Executor",
|
|
4808
4992
|
resourceName: executor.name,
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4993
|
+
conflicts,
|
|
4994
|
+
unmanaged
|
|
4995
|
+
}) && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && areExecutorsEqual(existing.resource, desiredExecutor)) changeSet.unchanged.push({ name: executor.name });
|
|
4812
4996
|
else changeSet.updates.push({
|
|
4813
4997
|
name: executor.name,
|
|
4814
4998
|
request: {
|
|
@@ -4830,9 +5014,13 @@ async function planExecutor(context) {
|
|
|
4830
5014
|
Object.entries(existingExecutors).forEach(([name]) => {
|
|
4831
5015
|
const entry = existingExecutors[name];
|
|
4832
5016
|
const label = entry?.label;
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
5017
|
+
if (trackRemainingResourceOwner({
|
|
5018
|
+
labels: entry?.allLabels,
|
|
5019
|
+
ownerLabel: label,
|
|
5020
|
+
appName: application.name,
|
|
5021
|
+
appId: application.id,
|
|
5022
|
+
resourceOwners
|
|
5023
|
+
})) changeSet.deletes.push({
|
|
4836
5024
|
name,
|
|
4837
5025
|
request: {
|
|
4838
5026
|
workspaceId,
|
|
@@ -5779,28 +5967,20 @@ async function planStaticWebsite(context) {
|
|
|
5779
5967
|
const conflicts = [];
|
|
5780
5968
|
const unmanaged = [];
|
|
5781
5969
|
const resourceOwners = /* @__PURE__ */ new Set();
|
|
5782
|
-
const
|
|
5783
|
-
|
|
5970
|
+
const existingWebsites = await fetchExistingResourcesWithLabels({
|
|
5971
|
+
client,
|
|
5972
|
+
workspaceId,
|
|
5973
|
+
fetchPage: async (pageToken, pageSize) => {
|
|
5784
5974
|
const { staticwebsites, nextPageToken } = await client.listStaticWebsites({
|
|
5785
5975
|
workspaceId,
|
|
5786
5976
|
pageToken,
|
|
5787
|
-
pageSize
|
|
5977
|
+
pageSize
|
|
5788
5978
|
});
|
|
5789
5979
|
return [staticwebsites, nextPageToken];
|
|
5790
|
-
}
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
}
|
|
5980
|
+
},
|
|
5981
|
+
getName: (resource) => resource.name,
|
|
5982
|
+
getTrn: trn$1
|
|
5794
5983
|
});
|
|
5795
|
-
const existingWebsites = {};
|
|
5796
|
-
await Promise.all(withoutLabel.map(async (resource) => {
|
|
5797
|
-
const { metadata } = await client.getMetadata({ trn: trn$1(workspaceId, resource.name) });
|
|
5798
|
-
existingWebsites[resource.name] = {
|
|
5799
|
-
resource,
|
|
5800
|
-
label: metadata?.labels[sdkNameLabelKey],
|
|
5801
|
-
allLabels: metadata?.labels
|
|
5802
|
-
};
|
|
5803
|
-
}));
|
|
5804
5984
|
const staticWebsiteServices = forRemoval ? [] : application.staticWebsiteServices;
|
|
5805
5985
|
for (const websiteService of staticWebsiteServices) {
|
|
5806
5986
|
const config = websiteService;
|
|
@@ -5821,17 +6001,16 @@ async function planStaticWebsite(context) {
|
|
|
5821
6001
|
}
|
|
5822
6002
|
};
|
|
5823
6003
|
if (existing) {
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
else conflicts.push({
|
|
6004
|
+
if (trackDesiredResourceOwnership({
|
|
6005
|
+
labels: existing.allLabels,
|
|
6006
|
+
ownerLabel: existing.label,
|
|
6007
|
+
appName: application.name,
|
|
6008
|
+
appId: application.id,
|
|
5830
6009
|
resourceType: "StaticWebsite",
|
|
5831
6010
|
resourceName: name,
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
6011
|
+
conflicts,
|
|
6012
|
+
unmanaged
|
|
6013
|
+
}) && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && areStaticWebsitesEqual(existing.resource, desired)) changeSet.unchanged.push({ name });
|
|
5835
6014
|
else changeSet.updates.push({
|
|
5836
6015
|
name,
|
|
5837
6016
|
request,
|
|
@@ -5847,9 +6026,13 @@ async function planStaticWebsite(context) {
|
|
|
5847
6026
|
Object.entries(existingWebsites).forEach(([name]) => {
|
|
5848
6027
|
const entry = existingWebsites[name];
|
|
5849
6028
|
const label = entry?.label;
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
6029
|
+
if (trackRemainingResourceOwner({
|
|
6030
|
+
labels: entry?.allLabels,
|
|
6031
|
+
ownerLabel: label,
|
|
6032
|
+
appName: application.name,
|
|
6033
|
+
appId: application.id,
|
|
6034
|
+
resourceOwners
|
|
6035
|
+
})) changeSet.deletes.push({
|
|
5853
6036
|
name,
|
|
5854
6037
|
request: {
|
|
5855
6038
|
workspaceId,
|
|
@@ -5939,19 +6122,11 @@ function formatDiffChange(change) {
|
|
|
5939
6122
|
case "type_removed": return ` - [Type] ${change.typeName} (removed)`;
|
|
5940
6123
|
case "type_modified": return ` ~ [Type] ${change.typeName}: ${change.reason}`;
|
|
5941
6124
|
case "field_added": {
|
|
5942
|
-
const
|
|
5943
|
-
const typeStr = formatFieldType(field);
|
|
6125
|
+
const typeStr = formatFieldType(change.after);
|
|
5944
6126
|
return ` + ${change.fieldName}: ${typeStr}`;
|
|
5945
6127
|
}
|
|
5946
|
-
case "field_removed": {
|
|
5947
|
-
|
|
5948
|
-
return ` - ${change.fieldName}: ${field.type}`;
|
|
5949
|
-
}
|
|
5950
|
-
case "field_modified": {
|
|
5951
|
-
const before = change.before;
|
|
5952
|
-
const after = change.after;
|
|
5953
|
-
return ` ~ ${change.fieldName}: ${formatFieldModification(before, after)}`;
|
|
5954
|
-
}
|
|
6128
|
+
case "field_removed": return ` - ${change.fieldName}: ${change.before.type}`;
|
|
6129
|
+
case "field_modified": return ` ~ ${change.fieldName}: ${formatFieldModification(change.before, change.after)}`;
|
|
5955
6130
|
case "index_added": return ` + [Index] ${change.indexName}`;
|
|
5956
6131
|
case "index_removed": return ` - [Index] ${change.indexName}`;
|
|
5957
6132
|
case "index_modified": return ` ~ [Index] ${change.indexName}: ${change.reason ?? "modified"}`;
|
|
@@ -5962,7 +6137,10 @@ function formatDiffChange(change) {
|
|
|
5962
6137
|
case "relationship_removed": return ` - [Relationship${change.relationshipType ? ` (${change.relationshipType})` : ""}] ${change.relationshipName}`;
|
|
5963
6138
|
case "relationship_modified": return ` ~ [Relationship${change.relationshipType ? ` (${change.relationshipType})` : ""}] ${change.relationshipName}: ${change.reason ?? "modified"}`;
|
|
5964
6139
|
case "permission_modified": return ` ~ [Permission] ${change.reason ?? "modified"}`;
|
|
5965
|
-
default:
|
|
6140
|
+
default: {
|
|
6141
|
+
const unknown = change;
|
|
6142
|
+
return ` ? ${unknown.typeName}.${unknown.fieldName ?? ""}`;
|
|
6143
|
+
}
|
|
5966
6144
|
}
|
|
5967
6145
|
}
|
|
5968
6146
|
/**
|
|
@@ -6066,6 +6244,28 @@ function formatDiffSummary(diff) {
|
|
|
6066
6244
|
return parts.length > 0 ? parts.join(", ") : "No changes";
|
|
6067
6245
|
}
|
|
6068
6246
|
|
|
6247
|
+
//#endregion
|
|
6248
|
+
//#region src/cli/commands/tailordb/migrate/migration-number.ts
|
|
6249
|
+
/**
|
|
6250
|
+
* Format migration number as 4-digit string.
|
|
6251
|
+
* @param num - Migration number
|
|
6252
|
+
* @returns 4-digit padded string
|
|
6253
|
+
*/
|
|
6254
|
+
function formatMigrationNumber(num) {
|
|
6255
|
+
return num.toString().padStart(4, "0");
|
|
6256
|
+
}
|
|
6257
|
+
|
|
6258
|
+
//#endregion
|
|
6259
|
+
//#region src/cli/commands/tailordb/migrate/snapshot-types.ts
|
|
6260
|
+
/**
|
|
6261
|
+
* Type guard: is the operand a field-reference (object) operand?
|
|
6262
|
+
* @param {SnapshotPermissionOperand} operand - Operand to test
|
|
6263
|
+
* @returns {boolean} True if operand is a field-ref (not a value operand)
|
|
6264
|
+
*/
|
|
6265
|
+
function isSnapshotFieldRefOperand(operand) {
|
|
6266
|
+
return typeof operand === "object" && operand !== null && !Array.isArray(operand);
|
|
6267
|
+
}
|
|
6268
|
+
|
|
6069
6269
|
//#endregion
|
|
6070
6270
|
//#region src/cli/commands/tailordb/migrate/snapshot.ts
|
|
6071
6271
|
/**
|
|
@@ -6121,14 +6321,6 @@ function normalizeSnapshotType(type) {
|
|
|
6121
6321
|
for (const field of Object.values(type.fields)) normalizeSnapshotField(field);
|
|
6122
6322
|
}
|
|
6123
6323
|
/**
|
|
6124
|
-
* Type guard: is the operand a field-reference (object) operand?
|
|
6125
|
-
* @param {SnapshotPermissionOperand} operand - Operand to test
|
|
6126
|
-
* @returns {boolean} True if operand is a field-ref (not a value operand)
|
|
6127
|
-
*/
|
|
6128
|
-
function isSnapshotFieldRefOperand(operand) {
|
|
6129
|
-
return typeof operand === "object" && operand !== null && !Array.isArray(operand);
|
|
6130
|
-
}
|
|
6131
|
-
/**
|
|
6132
6324
|
* Validate that a migration number follows the expected format (4-digit number)
|
|
6133
6325
|
* @param {string} numberStr - Migration number string to validate
|
|
6134
6326
|
* @returns {boolean} True if number matches expected format
|
|
@@ -6137,14 +6329,6 @@ function isValidMigrationNumber(numberStr) {
|
|
|
6137
6329
|
return MIGRATION_NUMBER_PATTERN.test(numberStr);
|
|
6138
6330
|
}
|
|
6139
6331
|
/**
|
|
6140
|
-
* Format migration number as 4-digit string
|
|
6141
|
-
* @param {number} num - Migration number
|
|
6142
|
-
* @returns {string} 4-digit padded string (e.g., "0001")
|
|
6143
|
-
*/
|
|
6144
|
-
function formatMigrationNumber(num) {
|
|
6145
|
-
return num.toString().padStart(4, "0");
|
|
6146
|
-
}
|
|
6147
|
-
/**
|
|
6148
6332
|
* Map of migration file types to their file names
|
|
6149
6333
|
*/
|
|
6150
6334
|
const MIGRATION_FILE_NAMES = {
|
|
@@ -7359,6 +7543,15 @@ const PRE_MIGRATION_FIELD_KINDS = new Set([
|
|
|
7359
7543
|
"field_removed"
|
|
7360
7544
|
]);
|
|
7361
7545
|
/**
|
|
7546
|
+
* Type guard: is the change a field-level change that needs pre-migration
|
|
7547
|
+
* schema adjustment?
|
|
7548
|
+
* @param {DiffChange} change - Diff change to test
|
|
7549
|
+
* @returns {boolean} True if the change is a field-level change
|
|
7550
|
+
*/
|
|
7551
|
+
function isPreMigrationFieldChange(change) {
|
|
7552
|
+
return PRE_MIGRATION_FIELD_KINDS.has(change.kind);
|
|
7553
|
+
}
|
|
7554
|
+
/**
|
|
7362
7555
|
* Build a map of field changes that require pre-migration schema adjustment.
|
|
7363
7556
|
* @param {PendingMigration[]} pendingMigrations - Pending migrations to scan
|
|
7364
7557
|
* @returns {PreMigrationChangesMap} Map of changes keyed by typeName/fieldName
|
|
@@ -7366,7 +7559,7 @@ const PRE_MIGRATION_FIELD_KINDS = new Set([
|
|
|
7366
7559
|
function buildPreMigrationChangesMap(pendingMigrations) {
|
|
7367
7560
|
const map = /* @__PURE__ */ new Map();
|
|
7368
7561
|
for (const migration of pendingMigrations) for (const change of migration.diff.changes) {
|
|
7369
|
-
if (!
|
|
7562
|
+
if (!isPreMigrationFieldChange(change)) continue;
|
|
7370
7563
|
if (!change.fieldName) continue;
|
|
7371
7564
|
const perType = map.get(change.typeName) ?? /* @__PURE__ */ new Map();
|
|
7372
7565
|
perType.set(change.fieldName, change);
|
|
@@ -7385,24 +7578,21 @@ function buildPreMigrationChangesMap(pendingMigrations) {
|
|
|
7385
7578
|
* - Modified fields keep the looser side of unique/required/enum.
|
|
7386
7579
|
*
|
|
7387
7580
|
* @param {Record<string, MessageInitShape<typeof TailorDBType_FieldConfigSchema>>} fields - Field map to adjust (mutated in place)
|
|
7388
|
-
* @param {Map<string,
|
|
7581
|
+
* @param {Map<string, FieldDiffChange>} typeChanges - Changes for this type, keyed by fieldName
|
|
7389
7582
|
*/
|
|
7390
7583
|
function applyPreMigrationFieldAdjustments(fields, typeChanges) {
|
|
7391
7584
|
for (const [fieldName, change] of typeChanges) {
|
|
7392
7585
|
if (change.kind === "field_removed") {
|
|
7393
|
-
|
|
7394
|
-
if (before) fields[fieldName] = convertFieldConfigToProto(before);
|
|
7586
|
+
if (change.before) fields[fieldName] = convertFieldConfigToProto(change.before);
|
|
7395
7587
|
continue;
|
|
7396
7588
|
}
|
|
7397
7589
|
const field = fields[fieldName];
|
|
7398
7590
|
if (!field) continue;
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
if (change.kind === "field_added" && after?.required) {
|
|
7402
|
-
field.required = false;
|
|
7591
|
+
if (change.kind === "field_added") {
|
|
7592
|
+
if (change.after?.required) field.required = false;
|
|
7403
7593
|
continue;
|
|
7404
7594
|
}
|
|
7405
|
-
|
|
7595
|
+
const { before, after } = change;
|
|
7406
7596
|
if (!before?.required && after?.required) field.required = false;
|
|
7407
7597
|
if (!(before?.unique ?? false) && (after?.unique ?? false)) field.unique = false;
|
|
7408
7598
|
if (before?.allowedValues && after?.allowedValues) {
|
|
@@ -9403,23 +9593,20 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
9403
9593
|
const unmanaged = [];
|
|
9404
9594
|
const resourceOwners = /* @__PURE__ */ new Set();
|
|
9405
9595
|
const unchangedWorkflowJobNames = /* @__PURE__ */ new Set();
|
|
9406
|
-
const
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
9410
|
-
|
|
9411
|
-
|
|
9412
|
-
|
|
9596
|
+
const existingWorkflows = await fetchExistingResourcesWithLabels({
|
|
9597
|
+
client,
|
|
9598
|
+
workspaceId,
|
|
9599
|
+
fetchPage: async (pageToken, pageSize) => {
|
|
9600
|
+
const response = await client.listWorkflows({
|
|
9601
|
+
workspaceId,
|
|
9602
|
+
pageToken,
|
|
9603
|
+
pageSize
|
|
9604
|
+
});
|
|
9605
|
+
return [response.workflows, response.nextPageToken];
|
|
9606
|
+
},
|
|
9607
|
+
getName: (resource) => resource.name,
|
|
9608
|
+
getTrn: workflowTrn$1
|
|
9413
9609
|
});
|
|
9414
|
-
const existingWorkflows = {};
|
|
9415
|
-
await Promise.all(withoutLabel.map(async (resource) => {
|
|
9416
|
-
const { metadata } = await client.getMetadata({ trn: workflowTrn$1(workspaceId, resource.name) });
|
|
9417
|
-
existingWorkflows[resource.name] = {
|
|
9418
|
-
resource,
|
|
9419
|
-
label: metadata?.labels[sdkNameLabelKey],
|
|
9420
|
-
allLabels: metadata?.labels
|
|
9421
|
-
};
|
|
9422
|
-
}));
|
|
9423
9610
|
for (const workflow of Object.values(workflows)) {
|
|
9424
9611
|
const existing = existingWorkflows[workflow.name];
|
|
9425
9612
|
const metaRequest = await buildMetaRequest({
|
|
@@ -9430,17 +9617,16 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
9430
9617
|
const usedJobNames = mainJobDeps[workflow.mainJob.name];
|
|
9431
9618
|
if (!usedJobNames) throw new Error(`Job "${workflow.mainJob.name}" (mainJob of workflow "${workflow.name}") was not found.\n\nPossible causes:\n - The job is not exported as a named export\n - The file containing the job is not included in workflow.files glob pattern\n\nSolution:\n export const ${workflow.mainJob.name} = createWorkflowJob({ name: "${workflow.mainJob.name}", ... })`);
|
|
9432
9619
|
if (existing) {
|
|
9433
|
-
|
|
9434
|
-
|
|
9435
|
-
|
|
9436
|
-
|
|
9437
|
-
|
|
9438
|
-
else conflicts.push({
|
|
9620
|
+
if (trackDesiredResourceOwnership({
|
|
9621
|
+
labels: existing.allLabels,
|
|
9622
|
+
ownerLabel: existing.label,
|
|
9623
|
+
appName,
|
|
9624
|
+
appId,
|
|
9439
9625
|
resourceType: "Workflow",
|
|
9440
9626
|
resourceName: workflow.name,
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
9627
|
+
conflicts,
|
|
9628
|
+
unmanaged
|
|
9629
|
+
}) && hasMatchingSdkVersion(existing.allLabels, metaRequest.labels) && canTreatWorkflowAsUnchanged(existing.resource, workflow, usedJobNames, unchangedJobFunctions)) {
|
|
9444
9630
|
changeSet.unchanged.push({ name: workflow.name });
|
|
9445
9631
|
for (const jobName of usedJobNames) unchangedWorkflowJobNames.add(jobName);
|
|
9446
9632
|
} else changeSet.updates.push({
|
|
@@ -9461,10 +9647,13 @@ async function planWorkflow(client, workspaceId, appName, appId, workflows, main
|
|
|
9461
9647
|
}
|
|
9462
9648
|
Object.values(existingWorkflows).forEach((existing) => {
|
|
9463
9649
|
if (!existing) return;
|
|
9464
|
-
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
|
|
9650
|
+
if (trackRemainingResourceOwner({
|
|
9651
|
+
labels: existing.allLabels,
|
|
9652
|
+
ownerLabel: existing.label,
|
|
9653
|
+
appName,
|
|
9654
|
+
appId,
|
|
9655
|
+
resourceOwners
|
|
9656
|
+
})) changeSet.deletes.push({
|
|
9468
9657
|
name: existing.resource.name,
|
|
9469
9658
|
workspaceId,
|
|
9470
9659
|
workflowId: existing.resource.id,
|
|
@@ -9754,7 +9943,7 @@ function summarizePlanResults(results, displayEntries, serviceActions) {
|
|
|
9754
9943
|
async function deploy(options) {
|
|
9755
9944
|
return withSpan("deploy", async (rootSpan) => {
|
|
9756
9945
|
rootSpan.setAttribute("deploy.dry_run", options?.dryRun ?? false);
|
|
9757
|
-
const { config, application, workflowBuildResult, bundledScripts, buildOnly } = await withSpan("build", async () => {
|
|
9946
|
+
const { config, application, workflowBuildResult, httpAdapterBuildResult, bundledScripts, buildOnly } = await withSpan("build", async () => {
|
|
9758
9947
|
const dryRun = options?.dryRun ?? false;
|
|
9759
9948
|
const buildOnly = options?.buildOnly ?? parseBoolean(process.env.TAILOR_PLATFORM_SDK_BUILD_ONLY) === true;
|
|
9760
9949
|
const { config, plugins } = await withSpan("build.loadConfig", async () => {
|
|
@@ -9791,6 +9980,7 @@ async function deploy(options) {
|
|
|
9791
9980
|
}));
|
|
9792
9981
|
let application;
|
|
9793
9982
|
let workflowBuildResult;
|
|
9983
|
+
let httpAdapterBuildResult;
|
|
9794
9984
|
let bundledScripts;
|
|
9795
9985
|
try {
|
|
9796
9986
|
const result = await withSpan("build.loadApplication", () => loadApplication({
|
|
@@ -9800,6 +9990,7 @@ async function deploy(options) {
|
|
|
9800
9990
|
}));
|
|
9801
9991
|
application = result.application;
|
|
9802
9992
|
workflowBuildResult = result.workflowBuildResult;
|
|
9993
|
+
httpAdapterBuildResult = result.httpAdapterBuildResult;
|
|
9803
9994
|
bundledScripts = result.bundledScripts;
|
|
9804
9995
|
} finally {
|
|
9805
9996
|
cacheManager.finalize();
|
|
@@ -9809,6 +10000,7 @@ async function deploy(options) {
|
|
|
9809
10000
|
plugins,
|
|
9810
10001
|
application,
|
|
9811
10002
|
workflowBuildResult,
|
|
10003
|
+
httpAdapterBuildResult,
|
|
9812
10004
|
bundledScripts,
|
|
9813
10005
|
dryRun,
|
|
9814
10006
|
buildOnly
|
|
@@ -9850,7 +10042,7 @@ async function deploy(options) {
|
|
|
9850
10042
|
withSpan("plan.idp", () => planIdP(ctx)),
|
|
9851
10043
|
withSpan("plan.auth", () => planAuth(ctx)),
|
|
9852
10044
|
withSpan("plan.pipeline", () => planPipeline(ctx)),
|
|
9853
|
-
withSpan("plan.application", () => planApplication(ctx)),
|
|
10045
|
+
withSpan("plan.application", () => planApplication(ctx, httpAdapterBuildResult)),
|
|
9854
10046
|
withSpan("plan.executor", () => planExecutor(ctx)),
|
|
9855
10047
|
withSpan("plan.workflow", () => planWorkflow(client, workspaceId, application.name, application.id, workflowService?.workflows ?? {}, workflowBuildResult?.mainJobDeps ?? {}, unchangedWorkflowJobs)),
|
|
9856
10048
|
withSpan("plan.secretManager", () => planSecretManager(ctx))
|
|
@@ -10972,10 +11164,11 @@ const startCommand = defineAppCommand({
|
|
|
10972
11164
|
configPath: args.config,
|
|
10973
11165
|
interval: parseDuration(args.interval)
|
|
10974
11166
|
});
|
|
11167
|
+
const jsonOutput = logger.jsonMode;
|
|
10975
11168
|
logger.info(`Execution ID: ${executionId}`, { mode: "stream" });
|
|
10976
11169
|
if (args.wait) {
|
|
10977
|
-
const result = await wait({ showProgress:
|
|
10978
|
-
if (args.logs && !
|
|
11170
|
+
const result = await wait({ showProgress: !jsonOutput });
|
|
11171
|
+
if (args.logs && !jsonOutput) {
|
|
10979
11172
|
const { execution } = await getWorkflowExecution({
|
|
10980
11173
|
executionId,
|
|
10981
11174
|
workspaceId: args["workspace-id"],
|
|
@@ -11406,6 +11599,7 @@ const listCommand$9 = defineAppCommand({
|
|
|
11406
11599
|
...paginationArgs()
|
|
11407
11600
|
}).strict(),
|
|
11408
11601
|
run: async (args) => {
|
|
11602
|
+
const jsonOutput = logger.jsonMode;
|
|
11409
11603
|
const executors = await listExecutors({
|
|
11410
11604
|
workspaceId: args["workspace-id"],
|
|
11411
11605
|
profile: args.profile,
|
|
@@ -11414,10 +11608,11 @@ const listCommand$9 = defineAppCommand({
|
|
|
11414
11608
|
});
|
|
11415
11609
|
if (executors.length === 0) {
|
|
11416
11610
|
logger.info("No executors found.");
|
|
11611
|
+
if (jsonOutput) logger.out([]);
|
|
11417
11612
|
return;
|
|
11418
11613
|
}
|
|
11419
11614
|
logger.out(executors, { display: { disabled: (v) => v ? styles.warning("true") : styles.dim("false") } });
|
|
11420
|
-
if (!
|
|
11615
|
+
if (!jsonOutput) {
|
|
11421
11616
|
if (executors.some((e) => e.triggerType === "webhook")) logger.info("To see webhook URLs, run: tailor-sdk executor webhook list");
|
|
11422
11617
|
}
|
|
11423
11618
|
}
|
|
@@ -11674,6 +11869,7 @@ const listWebhookCommand = defineAppCommand({
|
|
|
11674
11869
|
...paginationArgs()
|
|
11675
11870
|
}).strict(),
|
|
11676
11871
|
run: async (args) => {
|
|
11872
|
+
const jsonOutput = logger.jsonMode;
|
|
11677
11873
|
const executors = await listWebhookExecutors({
|
|
11678
11874
|
workspaceId: args["workspace-id"],
|
|
11679
11875
|
profile: args.profile,
|
|
@@ -11682,10 +11878,11 @@ const listWebhookCommand = defineAppCommand({
|
|
|
11682
11878
|
});
|
|
11683
11879
|
if (executors.length === 0) {
|
|
11684
11880
|
logger.info("No webhook executors found.");
|
|
11881
|
+
if (jsonOutput) logger.out([]);
|
|
11685
11882
|
return;
|
|
11686
11883
|
}
|
|
11687
11884
|
logger.out(executors, { display: { disabled: (v) => v ? styles.warning("true") : styles.dim("false") } });
|
|
11688
|
-
if (!
|
|
11885
|
+
if (!jsonOutput) logger.info("To test a webhook, run: tailor-sdk executor trigger <name> -d '{\"key\":\"value\"}'");
|
|
11689
11886
|
}
|
|
11690
11887
|
});
|
|
11691
11888
|
const webhookCommand = defineCommand({
|
|
@@ -11833,13 +12030,14 @@ const listCommand$8 = defineAppCommand({
|
|
|
11833
12030
|
...paginationArgs()
|
|
11834
12031
|
}).strict(),
|
|
11835
12032
|
run: async (args) => {
|
|
12033
|
+
const jsonOutput = logger.jsonMode;
|
|
11836
12034
|
const registries = await listFunctionRegistries({
|
|
11837
12035
|
workspaceId: args["workspace-id"],
|
|
11838
12036
|
profile: args.profile,
|
|
11839
12037
|
order: args.order,
|
|
11840
12038
|
limit: args.limit
|
|
11841
12039
|
});
|
|
11842
|
-
const formatted =
|
|
12040
|
+
const formatted = jsonOutput ? registries : registries.map(({ createdAt, updatedAt, ...rest }) => ({
|
|
11843
12041
|
...rest,
|
|
11844
12042
|
createdAt: humanizeRelativeTime(createdAt),
|
|
11845
12043
|
updatedAt: humanizeRelativeTime(updatedAt)
|
|
@@ -13752,8 +13950,7 @@ function extractBreakingChangeFields(diff) {
|
|
|
13752
13950
|
const addedRequiredFields = /* @__PURE__ */ new Map();
|
|
13753
13951
|
const enumValueChanges = /* @__PURE__ */ new Map();
|
|
13754
13952
|
for (const change of diff.changes) if (change.kind === "field_modified" && change.fieldName) {
|
|
13755
|
-
const before = change
|
|
13756
|
-
const after = change.after;
|
|
13953
|
+
const { before, after } = change;
|
|
13757
13954
|
if (before && after && !before.required && after.required) {
|
|
13758
13955
|
if (!optionalToRequired.has(change.typeName)) optionalToRequired.set(change.typeName, /* @__PURE__ */ new Set());
|
|
13759
13956
|
optionalToRequired.get(change.typeName).add(change.fieldName);
|
|
@@ -13772,7 +13969,7 @@ function extractBreakingChangeFields(diff) {
|
|
|
13772
13969
|
}
|
|
13773
13970
|
}
|
|
13774
13971
|
} else if (change.kind === "field_added" && change.fieldName) {
|
|
13775
|
-
const after = change
|
|
13972
|
+
const { after } = change;
|
|
13776
13973
|
if (after && after.required) {
|
|
13777
13974
|
if (!addedRequiredFields.has(change.typeName)) addedRequiredFields.set(change.typeName, /* @__PURE__ */ new Map());
|
|
13778
13975
|
addedRequiredFields.get(change.typeName).set(change.fieldName, after);
|
|
@@ -14127,8 +14324,7 @@ function generateChangeScript(change) {
|
|
|
14127
14324
|
return null;
|
|
14128
14325
|
}
|
|
14129
14326
|
if (change.kind !== "field_modified") return null;
|
|
14130
|
-
const before = change
|
|
14131
|
-
const after = change.after;
|
|
14327
|
+
const { before, after } = change;
|
|
14132
14328
|
if (!before.required && after.required) return ` // Set ${change.fieldName} for ${change.typeName} records where it is null
|
|
14133
14329
|
await trx
|
|
14134
14330
|
.updateTable("${change.typeName}")
|
|
@@ -14160,8 +14356,8 @@ function generateChangeScript(change) {
|
|
|
14160
14356
|
}
|
|
14161
14357
|
}`;
|
|
14162
14358
|
if (before.type === "enum" && after.type === "enum") {
|
|
14163
|
-
const beforeValues = before.allowedValues ?? [];
|
|
14164
|
-
const afterValues = after.allowedValues ?? [];
|
|
14359
|
+
const beforeValues = (before.allowedValues ?? []).map((v) => v.value);
|
|
14360
|
+
const afterValues = (after.allowedValues ?? []).map((v) => v.value);
|
|
14165
14361
|
const removedValues = beforeValues.filter((v) => !afterValues.includes(v));
|
|
14166
14362
|
if (removedValues.length > 0) {
|
|
14167
14363
|
const defaultValue = afterValues[0] ?? "NEW_VALUE";
|
|
@@ -14258,7 +14454,7 @@ async function generate(options) {
|
|
|
14258
14454
|
if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
|
|
14259
14455
|
let pluginManager;
|
|
14260
14456
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
14261
|
-
const { defineApplication } = await import("./application-
|
|
14457
|
+
const { defineApplication } = await import("./application-DM8q9GDI.mjs");
|
|
14262
14458
|
const application = defineApplication({
|
|
14263
14459
|
config,
|
|
14264
14460
|
pluginManager
|
|
@@ -14665,15 +14861,16 @@ const listCommand$3 = defineAppCommand({
|
|
|
14665
14861
|
...paginationArgs()
|
|
14666
14862
|
}).strict(),
|
|
14667
14863
|
run: async (args) => {
|
|
14864
|
+
const jsonOutput = logger.jsonMode;
|
|
14668
14865
|
const workflows = await listWorkflows({
|
|
14669
14866
|
workspaceId: args["workspace-id"],
|
|
14670
14867
|
profile: args.profile,
|
|
14671
14868
|
order: args.order,
|
|
14672
14869
|
limit: args.limit
|
|
14673
14870
|
});
|
|
14674
|
-
if (workflows.length === 0
|
|
14871
|
+
if (workflows.length === 0) {
|
|
14675
14872
|
logger.info("No workflows found.");
|
|
14676
|
-
return;
|
|
14873
|
+
if (!jsonOutput) return;
|
|
14677
14874
|
}
|
|
14678
14875
|
logger.out(workflows);
|
|
14679
14876
|
}
|
|
@@ -14898,13 +15095,14 @@ const listCommand$2 = defineAppCommand({
|
|
|
14898
15095
|
...paginationArgs()
|
|
14899
15096
|
}).strict(),
|
|
14900
15097
|
run: async (args) => {
|
|
15098
|
+
const jsonOutput = logger.jsonMode;
|
|
14901
15099
|
const apps = await listApps({
|
|
14902
15100
|
workspaceId: args["workspace-id"],
|
|
14903
15101
|
profile: args.profile,
|
|
14904
15102
|
order: args.order,
|
|
14905
15103
|
limit: args.limit
|
|
14906
15104
|
});
|
|
14907
|
-
const formattedApps =
|
|
15105
|
+
const formattedApps = jsonOutput ? apps : apps.map(({ updatedAt: _, createdAt, ...rest }) => ({
|
|
14908
15106
|
...rest,
|
|
14909
15107
|
createdAt: humanizeRelativeTime(createdAt)
|
|
14910
15108
|
}));
|
|
@@ -15862,9 +16060,13 @@ async function loadTypeFieldOrder(config, namespace) {
|
|
|
15862
16060
|
return fieldOrder;
|
|
15863
16061
|
}
|
|
15864
16062
|
|
|
16063
|
+
//#endregion
|
|
16064
|
+
//#region src/cli/query/types.ts
|
|
16065
|
+
const queryEngines = ["sql", "gql"];
|
|
16066
|
+
|
|
15865
16067
|
//#endregion
|
|
15866
16068
|
//#region src/cli/query/index.ts
|
|
15867
|
-
const queryEngineSchema = z.enum(
|
|
16069
|
+
const queryEngineSchema = z.enum(queryEngines);
|
|
15868
16070
|
const queryBaseOptionsSchema = z.object({
|
|
15869
16071
|
workspaceId: z.string().optional(),
|
|
15870
16072
|
profile: z.string().optional(),
|
|
@@ -16444,5 +16646,5 @@ function isDeno() {
|
|
|
16444
16646
|
}
|
|
16445
16647
|
|
|
16446
16648
|
//#endregion
|
|
16447
|
-
export { listCommand$5 as $, compareSnapshots as $t, truncate as A, workspaceArgs as An, startCommand as At, logBetaWarning as B, getExecutor as Bt, listCommand$2 as C, configArg as Cn, triggerExecutor as Ct, resumeWorkflow as D, pagedLogArgs as Dn, jobsCommand as Dt, resumeCommand as E, isVerbose as En, getExecutorJob as Et, writeDbTypesFile as F, getWorkflowExecution as Ft, organizationTree as G, parseMigrationLabelNumber as Gt, removeCommand$1 as H, executeScript as Ht, getConfiguredEditorCommand as I, listWorkflowExecutions as It, listOrganizations as J, DIFF_FILE_NAME as Jt, treeCommand as K, bundleMigrationScript as Kt, openInConfiguredEditor as L, functionExecutionStatusToString as Lt, generate as M, getCommand$5 as Mt, generateCommand as N, getWorkflow as Nt, listCommand$3 as O, paginationArgs as On, listExecutorJobs as Ot, generateMigrationScript as P, executionsCommand as Pt, updateFolder as Q, compareLocalTypesWithSnapshot as Qt, show as R, formatKeyValueTable as Rt, listApps as S, commonArgs as Sn, triggerCommand as St, healthCommand as T, deploymentArgs as Tn, listExecutors as Tt, updateCommand$1 as U, waitForExecution$1 as Ut, remove as V, deploy as Vt, updateOrganization as W, MIGRATION_LABEL_KEY as Wt, getOrganization as X, MIGRATE_FILE_NAME as Xt, getCommand$1 as Y, INITIAL_SCHEMA_NUMBER as Yt, updateCommand$2 as Z, SCHEMA_FILE_NAME as Zt, getWorkspace as _, prompt as _n, listFunctionRegistries as _t, updateUser as a,
|
|
16448
|
-
//# sourceMappingURL=runtime-
|
|
16649
|
+
export { listCommand$5 as $, compareSnapshots as $t, truncate as A, workspaceArgs as An, startCommand as At, logBetaWarning as B, getExecutor as Bt, listCommand$2 as C, configArg as Cn, triggerExecutor as Ct, resumeWorkflow as D, pagedLogArgs as Dn, jobsCommand as Dt, resumeCommand as E, isVerbose as En, getExecutorJob as Et, writeDbTypesFile as F, getWorkflowExecution as Ft, organizationTree as G, parseMigrationLabelNumber as Gt, removeCommand$1 as H, executeScript as Ht, getConfiguredEditorCommand as I, listWorkflowExecutions as It, listOrganizations as J, DIFF_FILE_NAME as Jt, treeCommand as K, bundleMigrationScript as Kt, openInConfiguredEditor as L, functionExecutionStatusToString as Lt, generate as M, getCommand$5 as Mt, generateCommand as N, getWorkflow as Nt, listCommand$3 as O, paginationArgs as On, listExecutorJobs as Ot, generateMigrationScript as P, executionsCommand as Pt, updateFolder as Q, compareLocalTypesWithSnapshot as Qt, show as R, formatKeyValueTable as Rt, listApps as S, commonArgs as Sn, triggerCommand as St, healthCommand as T, deploymentArgs as Tn, listExecutors as Tt, updateCommand$1 as U, waitForExecution$1 as Ut, remove as V, deploy as Vt, updateOrganization as W, MIGRATION_LABEL_KEY as Wt, getOrganization as X, MIGRATE_FILE_NAME as Xt, getCommand$1 as Y, INITIAL_SCHEMA_NUMBER as Yt, updateCommand$2 as Z, SCHEMA_FILE_NAME as Zt, getWorkspace as _, prompt as _n, listFunctionRegistries as _t, updateUser as a, getNextMigrationNumber as an, createCommand$1 as at, createCommand as b, assertWritable as bn, listWebhookExecutors as bt, listCommand as c, reconstructSnapshotFromMigrations as cn, listOAuth2Clients as ct, inviteUser as d, formatMigrationDiff as dn, getMachineUserToken as dt, createSnapshotFromLocalTypes as en, listFolders as et, restoreCommand as f, hasChanges as fn, tokenCommand as ft, getCommand as g, generateUserTypes as gn, listCommand$8 as gt, listWorkspaces as h, trnPrefix as hn, generate$1 as ht, updateCommand as i, getMigrationFiles as in, deleteFolder as it, truncateCommand as j, startWorkflow as jt, listWorkflows as k, toPageDirection as kn, watchExecutorJob as kt, listUsers as l, formatMigrationNumber as ln, getCommand$3 as lt, listCommand$1 as m, sdkNameLabelKey as mn, listMachineUsers as mt, query as n, getMigrationDirPath as nn, getFolder as nt, removeCommand as o, isValidMigrationNumber as on, createFolder as ot, restoreWorkspace as p, getNamespacesWithMigrations as pn, listCommand$7 as pt, listCommand$4 as q, DB_TYPES_FILE_NAME as qt, queryCommand as r, getMigrationFilePath as rn, deleteCommand$1 as rt, removeUser as s, loadDiff as sn, listCommand$6 as st, isNativeTypeScriptRuntime as t, getLatestMigrationNumber as tn, getCommand$2 as tt, inviteCommand as u, formatDiffSummary as un, getOAuth2Client as ut, deleteCommand as v, apiCommand as vn, getCommand$4 as vt, getAppHealth as w, confirmationArgs as wn, listCommand$9 as wt, createWorkspace as x, defineAppCommand as xn, webhookCommand as xt, deleteWorkspace as y, apiCall as yn, getFunctionRegistry as yt, showCommand as z, getCommand$6 as zt };
|
|
16650
|
+
//# sourceMappingURL=runtime-CgGeIoxi.mjs.map
|