@tailor-platform/sdk 1.14.2 → 1.15.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 +25 -0
- package/dist/{application-DhwHYQ3H.mjs → application-DPunZ4lc.mjs} +2 -2
- package/dist/{application-DhwHYQ3H.mjs.map → application-DPunZ4lc.mjs.map} +1 -1
- package/dist/application-JwJ_-_PQ.mjs +4 -0
- package/dist/cli/index.mjs +3 -3
- package/dist/cli/lib.d.mts +53 -6
- package/dist/cli/lib.mjs +2 -2
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/configure/index.d.mts +4 -4
- package/dist/configure/index.mjs +0 -7
- package/dist/configure/index.mjs.map +1 -1
- package/dist/{index-q3n7wQOs.d.mts → index-Bs9AsQb2.d.mts} +27 -11
- package/dist/{index-YzESrtj0.d.mts → index-DomkP6gz.d.mts} +2 -2
- package/dist/plugin/index.d.mts +1 -1
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/{types-DbvONSS-.d.mts → types-Db1oxr0U.d.mts} +26 -67
- package/dist/{update-Dm8ERWHJ.mjs → update-C_ZTRB63.mjs} +354 -361
- package/dist/update-C_ZTRB63.mjs.map +1 -0
- package/dist/utils/test/index.d.mts +3 -3
- package/docs/plugin/custom.md +62 -45
- package/package.json +1 -1
- package/dist/application-BznueWxG.mjs +0 -4
- package/dist/update-Dm8ERWHJ.mjs.map +0 -1
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { t as isPluginGeneratedType } from "./types-b-ig8nW_.mjs";
|
|
2
2
|
import { t as db } from "./schema-DRYB-nzA.mjs";
|
|
3
|
-
import { a as ExecutorSchema, c as
|
|
3
|
+
import { a as ExecutorSchema, c as functionSchema, d as loadFilesWithIgnores, f as logger, i as createExecutorService, l as stringifyFunction, m as symbols, n as WorkflowJobSchema, o as OAuth2ClientSchema, p as styles, r as WorkflowSchema, s as ResolverSchema, t as defineApplication, u as tailorUserMap } from "./application-DPunZ4lc.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
|
-
import { cloneDeep } from "es-toolkit";
|
|
6
5
|
import { arg, defineCommand, runCommand } from "politty";
|
|
7
6
|
import { z } from "zod";
|
|
8
7
|
import * as fs$2 from "node:fs";
|
|
@@ -29,6 +28,7 @@ import { glob } from "node:fs/promises";
|
|
|
29
28
|
import * as rolldown from "rolldown";
|
|
30
29
|
import { parseSync } from "oxc-parser";
|
|
31
30
|
import { create, fromJson, toJson } from "@bufbuild/protobuf";
|
|
31
|
+
import * as crypto from "node:crypto";
|
|
32
32
|
import ora from "ora";
|
|
33
33
|
import { setTimeout as setTimeout$1 } from "timers/promises";
|
|
34
34
|
import { spawn } from "node:child_process";
|
|
@@ -2685,143 +2685,21 @@ function createGeneratorConfigSchema(builtinGenerators$1) {
|
|
|
2685
2685
|
|
|
2686
2686
|
//#endregion
|
|
2687
2687
|
//#region src/parser/plugin-config/schema.ts
|
|
2688
|
-
const unauthenticatedTailorUser$1 = {
|
|
2689
|
-
id: "00000000-0000-0000-0000-000000000000",
|
|
2690
|
-
type: "",
|
|
2691
|
-
workspaceId: "00000000-0000-0000-0000-000000000000",
|
|
2692
|
-
attributes: null,
|
|
2693
|
-
attributeList: []
|
|
2694
|
-
};
|
|
2695
|
-
const PluginGeneratedTypeSchema = z.object({
|
|
2696
|
-
name: z.string(),
|
|
2697
|
-
fields: z.record(z.string(), z.unknown())
|
|
2698
|
-
});
|
|
2699
|
-
const PluginGeneratedResolverSchema = z.object({
|
|
2700
|
-
name: z.string(),
|
|
2701
|
-
operation: z.enum(["query", "mutation"]),
|
|
2702
|
-
inputFields: z.record(z.string(), z.unknown()).optional(),
|
|
2703
|
-
outputFields: z.record(z.string(), z.unknown()),
|
|
2704
|
-
body: z.string()
|
|
2705
|
-
});
|
|
2706
|
-
const PluginTriggerConfigSchema = z.object({
|
|
2707
|
-
kind: z.enum([
|
|
2708
|
-
"recordCreated",
|
|
2709
|
-
"recordUpdated",
|
|
2710
|
-
"recordDeleted",
|
|
2711
|
-
"schedule",
|
|
2712
|
-
"incomingWebhook"
|
|
2713
|
-
]),
|
|
2714
|
-
type: z.string().optional(),
|
|
2715
|
-
schedule: z.string().optional()
|
|
2716
|
-
});
|
|
2717
|
-
const PluginOperationConfigSchema = z.object({
|
|
2718
|
-
kind: z.enum([
|
|
2719
|
-
"function",
|
|
2720
|
-
"webhook",
|
|
2721
|
-
"graphql",
|
|
2722
|
-
"workflow"
|
|
2723
|
-
]),
|
|
2724
|
-
body: z.string().optional(),
|
|
2725
|
-
url: z.string().optional(),
|
|
2726
|
-
query: z.string().optional()
|
|
2727
|
-
});
|
|
2728
|
-
const PluginGeneratedExecutorSchema = z.object({
|
|
2729
|
-
name: z.string(),
|
|
2730
|
-
description: z.string().optional(),
|
|
2731
|
-
trigger: PluginTriggerConfigSchema,
|
|
2732
|
-
operation: PluginOperationConfigSchema
|
|
2733
|
-
});
|
|
2734
|
-
z.object({
|
|
2735
|
-
types: z.array(PluginGeneratedTypeSchema).optional(),
|
|
2736
|
-
resolvers: z.array(PluginGeneratedResolverSchema).optional(),
|
|
2737
|
-
executors: z.array(PluginGeneratedExecutorSchema).optional()
|
|
2738
|
-
});
|
|
2739
|
-
const tailorAnyFieldSchema = z.custom((val) => TailorFieldSchema.safeParse(val).success);
|
|
2740
2688
|
const CustomPluginSchema = z.object({
|
|
2741
2689
|
id: z.string(),
|
|
2742
2690
|
description: z.string(),
|
|
2743
2691
|
importPath: z.string(),
|
|
2744
|
-
configSchema: tailorAnyFieldSchema.optional(),
|
|
2745
|
-
pluginConfigSchema: tailorAnyFieldSchema.optional(),
|
|
2746
2692
|
pluginConfig: z.unknown().optional(),
|
|
2747
2693
|
processType: functionSchema.optional(),
|
|
2748
2694
|
processNamespace: functionSchema.optional(),
|
|
2749
|
-
typeConfigRequired: z.union([z.boolean(), functionSchema]).optional()
|
|
2750
|
-
configTypeTemplate: z.string().optional()
|
|
2751
|
-
}).superRefine((plugin, ctx) => {
|
|
2752
|
-
if (plugin.processType && !plugin.configSchema) ctx.addIssue({
|
|
2753
|
-
code: z.ZodIssueCode.custom,
|
|
2754
|
-
message: "processType requires configSchema to be defined.",
|
|
2755
|
-
path: ["configSchema"]
|
|
2756
|
-
});
|
|
2695
|
+
typeConfigRequired: z.union([z.boolean(), functionSchema]).optional()
|
|
2757
2696
|
}).passthrough();
|
|
2758
|
-
function normalizePluginConfigSchema(schema) {
|
|
2759
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2760
|
-
const stack = [schema];
|
|
2761
|
-
while (stack.length > 0) {
|
|
2762
|
-
const field = stack.pop();
|
|
2763
|
-
if (!field || seen.has(field)) continue;
|
|
2764
|
-
seen.add(field);
|
|
2765
|
-
const requiredExplicit = field._metadata.requiredExplicit === true;
|
|
2766
|
-
field._metadata.required = requiredExplicit;
|
|
2767
|
-
for (const nestedField of Object.values(field.fields)) stack.push(nestedField);
|
|
2768
|
-
}
|
|
2769
|
-
return schema;
|
|
2770
|
-
}
|
|
2771
|
-
function clonePluginConfigSchema(schema) {
|
|
2772
|
-
return cloneDeep(schema);
|
|
2773
|
-
}
|
|
2774
|
-
function normalizePlugin(plugin) {
|
|
2775
|
-
let normalized = plugin;
|
|
2776
|
-
if (normalized.configSchema) {
|
|
2777
|
-
const clonedConfigSchema = clonePluginConfigSchema(normalized.configSchema);
|
|
2778
|
-
normalizePluginConfigSchema(clonedConfigSchema);
|
|
2779
|
-
normalized = {
|
|
2780
|
-
...normalized,
|
|
2781
|
-
configSchema: clonedConfigSchema
|
|
2782
|
-
};
|
|
2783
|
-
}
|
|
2784
|
-
if (normalized.pluginConfigSchema) {
|
|
2785
|
-
const pluginConfigSchema = clonePluginConfigSchema(normalized.pluginConfigSchema);
|
|
2786
|
-
normalizePluginConfigSchema(pluginConfigSchema);
|
|
2787
|
-
normalized = {
|
|
2788
|
-
...normalized,
|
|
2789
|
-
pluginConfigSchema
|
|
2790
|
-
};
|
|
2791
|
-
if (normalized.pluginConfig !== void 0) {
|
|
2792
|
-
const validationErrors = validatePluginConfig$1(normalized.pluginConfig, pluginConfigSchema);
|
|
2793
|
-
if (validationErrors.length > 0) {
|
|
2794
|
-
const errorDetails = validationErrors.map((e) => e.field ? `${e.field}: ${e.message}` : e.message).join("; ");
|
|
2795
|
-
throw new Error(`Invalid pluginConfig for plugin "${normalized.id}": ${errorDetails}`);
|
|
2796
|
-
}
|
|
2797
|
-
}
|
|
2798
|
-
}
|
|
2799
|
-
return normalized;
|
|
2800
|
-
}
|
|
2801
|
-
/**
|
|
2802
|
-
* Validate plugin config against its schema
|
|
2803
|
-
* @param config - The config object to validate
|
|
2804
|
-
* @param schema - The schema defining expected fields
|
|
2805
|
-
* @returns Array of validation errors (empty if valid)
|
|
2806
|
-
*/
|
|
2807
|
-
function validatePluginConfig$1(config, schema) {
|
|
2808
|
-
const result = schema.parse({
|
|
2809
|
-
value: config,
|
|
2810
|
-
data: config,
|
|
2811
|
-
user: unauthenticatedTailorUser$1
|
|
2812
|
-
});
|
|
2813
|
-
if ("issues" in result && result.issues) return result.issues.map((issue) => ({
|
|
2814
|
-
field: Array.isArray(issue.path) ? issue.path.join(".") : "",
|
|
2815
|
-
message: issue.message
|
|
2816
|
-
}));
|
|
2817
|
-
return [];
|
|
2818
|
-
}
|
|
2819
2697
|
/**
|
|
2820
2698
|
* Creates a PluginConfigSchema for custom plugins
|
|
2821
2699
|
* @returns Plugin config schema that validates and transforms Plugin instances
|
|
2822
2700
|
*/
|
|
2823
2701
|
function createPluginConfigSchema() {
|
|
2824
|
-
return CustomPluginSchema.transform((plugin) =>
|
|
2702
|
+
return CustomPluginSchema.transform((plugin) => plugin).brand("Plugin");
|
|
2825
2703
|
}
|
|
2826
2704
|
|
|
2827
2705
|
//#endregion
|
|
@@ -5017,10 +4895,9 @@ function extractAttributesFromConfig(config) {
|
|
|
5017
4895
|
* @param attributeMap - Attribute map configuration
|
|
5018
4896
|
* @param attributeList - Attribute list configuration
|
|
5019
4897
|
* @param env - Environment configuration
|
|
5020
|
-
* @param pluginConfigs - Plugin configuration entries for PluginConfigs interface
|
|
5021
4898
|
* @returns Generated type definition source
|
|
5022
4899
|
*/
|
|
5023
|
-
function generateTypeDefinition(attributeMap, attributeList, env
|
|
4900
|
+
function generateTypeDefinition(attributeMap, attributeList, env) {
|
|
5024
4901
|
const mapFields = attributeMap ? Object.entries(attributeMap).map(([key, value]) => ` ${key}: ${value};`).join("\n") : "";
|
|
5025
4902
|
const mapBody = !attributeMap || Object.keys(attributeMap).length === 0 ? "{}" : `{
|
|
5026
4903
|
${mapFields}
|
|
@@ -5041,7 +4918,7 @@ declare module "@tailor-platform/sdk" {
|
|
|
5041
4918
|
interface AttributeList ${listBody}
|
|
5042
4919
|
interface Env ${!env || Object.keys(env).length === 0 ? "{}" : `{
|
|
5043
4920
|
${envFields}
|
|
5044
|
-
}`}
|
|
4921
|
+
}`}
|
|
5045
4922
|
}
|
|
5046
4923
|
|
|
5047
4924
|
export {};
|
|
@@ -5104,7 +4981,7 @@ function resolveTypeDefinitionPath(configPath) {
|
|
|
5104
4981
|
* @returns Promise that resolves when types are generated
|
|
5105
4982
|
*/
|
|
5106
4983
|
async function generateUserTypes(options) {
|
|
5107
|
-
const { config, configPath
|
|
4984
|
+
const { config, configPath } = options;
|
|
5108
4985
|
try {
|
|
5109
4986
|
const { attributeMap, attributeList } = extractAttributesFromConfig(config);
|
|
5110
4987
|
if (!attributeMap && !attributeList) logger.info("No attributes found in configuration", { mode: "plain" });
|
|
@@ -5112,14 +4989,7 @@ async function generateUserTypes(options) {
|
|
|
5112
4989
|
if (attributeList) logger.debug(`Extracted AttributeList: ${JSON.stringify(attributeList)}`);
|
|
5113
4990
|
const env = config.env;
|
|
5114
4991
|
if (env) logger.debug(`Extracted Env: ${JSON.stringify(env)}`);
|
|
5115
|
-
const
|
|
5116
|
-
id: p.id,
|
|
5117
|
-
configSchema: p.configSchema,
|
|
5118
|
-
configTypeTemplate: p.configTypeTemplate,
|
|
5119
|
-
typeConfigRequired: isTypeConfigRequired(p)
|
|
5120
|
-
}));
|
|
5121
|
-
if (pluginConfigs && pluginConfigs.length > 0) logger.debug(`Extracted PluginConfigs: ${pluginConfigs.map((p) => p.id).join(", ")}`);
|
|
5122
|
-
const typeDefContent = generateTypeDefinition(attributeMap, attributeList, env, pluginConfigs);
|
|
4992
|
+
const typeDefContent = generateTypeDefinition(attributeMap, attributeList, env);
|
|
5123
4993
|
const outputPath = resolveTypeDefinitionPath(configPath);
|
|
5124
4994
|
fs$2.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
5125
4995
|
fs$2.writeFileSync(outputPath, typeDefContent);
|
|
@@ -5148,116 +5018,9 @@ function resolvePackageDirectory(startDir) {
|
|
|
5148
5018
|
return null;
|
|
5149
5019
|
}
|
|
5150
5020
|
}
|
|
5151
|
-
/**
|
|
5152
|
-
* Convert a ConfigSchemaField to its TypeScript type string representation.
|
|
5153
|
-
* @param field - The field to convert
|
|
5154
|
-
* @param indent - Current indentation level
|
|
5155
|
-
* @returns TypeScript type string
|
|
5156
|
-
*/
|
|
5157
|
-
function fieldToTypeString(field, indent = 0) {
|
|
5158
|
-
const indentStr = " ".repeat(indent);
|
|
5159
|
-
const metadata = field.metadata;
|
|
5160
|
-
let baseType;
|
|
5161
|
-
switch (field.type) {
|
|
5162
|
-
case "string":
|
|
5163
|
-
case "uuid":
|
|
5164
|
-
case "date":
|
|
5165
|
-
case "datetime":
|
|
5166
|
-
case "time":
|
|
5167
|
-
baseType = "string";
|
|
5168
|
-
break;
|
|
5169
|
-
case "integer":
|
|
5170
|
-
case "float":
|
|
5171
|
-
baseType = "number";
|
|
5172
|
-
break;
|
|
5173
|
-
case "boolean":
|
|
5174
|
-
baseType = "boolean";
|
|
5175
|
-
break;
|
|
5176
|
-
case "enum":
|
|
5177
|
-
if (metadata.allowedValues && metadata.allowedValues.length > 0) baseType = metadata.allowedValues.map((v) => `"${v.value}"`).join(" | ");
|
|
5178
|
-
else baseType = "string";
|
|
5179
|
-
break;
|
|
5180
|
-
case "nested": {
|
|
5181
|
-
const fieldEntries = Object.entries(field.fields);
|
|
5182
|
-
if (fieldEntries.length === 0) baseType = "Record<string, unknown>";
|
|
5183
|
-
else baseType = `{\n${fieldEntries.map(([name, nestedField]) => {
|
|
5184
|
-
const nestedType = fieldToTypeString(nestedField, indent + 1);
|
|
5185
|
-
return `${indentStr} ${name}${!nestedField.metadata.required ? "?" : ""}: ${nestedType};`;
|
|
5186
|
-
}).join("\n")}\n${indentStr}}`;
|
|
5187
|
-
break;
|
|
5188
|
-
}
|
|
5189
|
-
default: baseType = "unknown";
|
|
5190
|
-
}
|
|
5191
|
-
if (metadata.array) baseType = `(${baseType})[]`;
|
|
5192
|
-
return baseType;
|
|
5193
|
-
}
|
|
5194
|
-
function isTypeConfigRequired(plugin) {
|
|
5195
|
-
const required = plugin.typeConfigRequired;
|
|
5196
|
-
if (typeof required === "function") return required(plugin.pluginConfig);
|
|
5197
|
-
return required === true;
|
|
5198
|
-
}
|
|
5199
|
-
/**
|
|
5200
|
-
* Generate PluginConfigs interface extension for user-defined.d.ts
|
|
5201
|
-
* @param plugins - Array of plugin configurations
|
|
5202
|
-
* @returns TypeScript interface extension string, or empty string if no plugins
|
|
5203
|
-
*/
|
|
5204
|
-
function generatePluginConfigsDefinition(plugins) {
|
|
5205
|
-
if (plugins.length === 0) return "";
|
|
5206
|
-
return ` interface PluginConfigs<Fields extends string> {
|
|
5207
|
-
${plugins.map((plugin) => {
|
|
5208
|
-
const typeString = plugin.configTypeTemplate ?? fieldToTypeString(plugin.configSchema, 2);
|
|
5209
|
-
const optionalMarker = plugin.typeConfigRequired ? "" : "?";
|
|
5210
|
-
return ` "${plugin.id}"${optionalMarker}: ${typeString};`;
|
|
5211
|
-
}).join("\n")}
|
|
5212
|
-
}`;
|
|
5213
|
-
}
|
|
5214
|
-
/**
|
|
5215
|
-
* Generate TailorDBType.plugin() method overload for IDE completion.
|
|
5216
|
-
* This adds an overload that uses `keyof Fields` directly for field-aware types,
|
|
5217
|
-
* enabling IDE autocompletion for field names in plugin configs.
|
|
5218
|
-
* @param plugins - Array of plugin configurations
|
|
5219
|
-
* @returns TypeScript interface extension string
|
|
5220
|
-
*/
|
|
5221
|
-
function generatePluginMethodOverload(plugins) {
|
|
5222
|
-
return ` // Overload for .plugin() method to enable IDE completion for field names
|
|
5223
|
-
interface TailorDBType<Fields, User> {
|
|
5224
|
-
plugin(config: {
|
|
5225
|
-
${plugins.map((plugin) => {
|
|
5226
|
-
const typeString = (plugin.configTypeTemplate ?? fieldToTypeString(plugin.configSchema, 3)).replace(/\bFields\b/g, "keyof Fields & string");
|
|
5227
|
-
const optionalMarker = plugin.typeConfigRequired ? "" : "?";
|
|
5228
|
-
return ` "${plugin.id}"${optionalMarker}: ${typeString};`;
|
|
5229
|
-
}).join("\n")}
|
|
5230
|
-
}): this;
|
|
5231
|
-
}`;
|
|
5232
|
-
}
|
|
5233
5021
|
|
|
5234
5022
|
//#endregion
|
|
5235
5023
|
//#region src/plugin/manager.ts
|
|
5236
|
-
const unauthenticatedTailorUser = {
|
|
5237
|
-
id: "00000000-0000-0000-0000-000000000000",
|
|
5238
|
-
type: "",
|
|
5239
|
-
workspaceId: "00000000-0000-0000-0000-000000000000",
|
|
5240
|
-
attributes: null,
|
|
5241
|
-
attributeList: []
|
|
5242
|
-
};
|
|
5243
|
-
/**
|
|
5244
|
-
* Validate plugin config against its schema
|
|
5245
|
-
* @param config - The config object to validate
|
|
5246
|
-
* @param schema - The schema defining expected fields
|
|
5247
|
-
* @returns Array of validation errors (empty if valid)
|
|
5248
|
-
*/
|
|
5249
|
-
function validatePluginConfig(config, schema) {
|
|
5250
|
-
const result = schema.parse({
|
|
5251
|
-
value: config,
|
|
5252
|
-
data: config,
|
|
5253
|
-
user: unauthenticatedTailorUser
|
|
5254
|
-
});
|
|
5255
|
-
if ("issues" in result && result.issues) return result.issues.map((issue) => ({
|
|
5256
|
-
field: Array.isArray(issue.path) ? issue.path.join(".") : "",
|
|
5257
|
-
message: issue.message
|
|
5258
|
-
}));
|
|
5259
|
-
return [];
|
|
5260
|
-
}
|
|
5261
5024
|
/**
|
|
5262
5025
|
* Manages plugin registration and processing
|
|
5263
5026
|
*/
|
|
@@ -5290,16 +5053,6 @@ var PluginManager = class {
|
|
|
5290
5053
|
success: false,
|
|
5291
5054
|
error: `Plugin "${plugin.id}" requires typeConfig, but none was provided for type "${context.type.name}".`
|
|
5292
5055
|
};
|
|
5293
|
-
if (plugin.configSchema) {
|
|
5294
|
-
const validationErrors = validatePluginConfig(context.typeConfig, plugin.configSchema);
|
|
5295
|
-
if (validationErrors.length > 0) {
|
|
5296
|
-
const errorDetails = validationErrors.map((e) => e.field ? `${e.field}: ${e.message}` : e.message).join("; ");
|
|
5297
|
-
return {
|
|
5298
|
-
success: false,
|
|
5299
|
-
error: `Invalid typeConfig for plugin "${plugin.id}" on type "${context.type.name}": ${errorDetails}`
|
|
5300
|
-
};
|
|
5301
|
-
}
|
|
5302
|
-
}
|
|
5303
5056
|
if (!plugin.processType) return {
|
|
5304
5057
|
success: false,
|
|
5305
5058
|
error: `Plugin "${plugin.id}" does not support type-attached processing (missing processType method). Use processNamespace via definePlugins() instead.`
|
|
@@ -5353,21 +5106,6 @@ var PluginManager = class {
|
|
|
5353
5106
|
for (const [pluginId, plugin] of this.plugins) {
|
|
5354
5107
|
if (!plugin.processNamespace) continue;
|
|
5355
5108
|
const config = plugin.pluginConfig;
|
|
5356
|
-
if (plugin.pluginConfigSchema && config !== void 0) {
|
|
5357
|
-
const validationErrors = validatePluginConfig(config, plugin.pluginConfigSchema);
|
|
5358
|
-
if (validationErrors.length > 0) {
|
|
5359
|
-
const errorDetails = validationErrors.map((e) => e.field ? `${e.field}: ${e.message}` : e.message).join("; ");
|
|
5360
|
-
results.push({
|
|
5361
|
-
pluginId,
|
|
5362
|
-
config,
|
|
5363
|
-
result: {
|
|
5364
|
-
success: false,
|
|
5365
|
-
error: `Invalid pluginConfig for plugin "${plugin.id}": ${errorDetails}`
|
|
5366
|
-
}
|
|
5367
|
-
});
|
|
5368
|
-
continue;
|
|
5369
|
-
}
|
|
5370
|
-
}
|
|
5371
5109
|
const context = {
|
|
5372
5110
|
pluginConfig: config,
|
|
5373
5111
|
namespace
|
|
@@ -6982,6 +6720,245 @@ async function confirmImportantResourceDeletion(resources, yes) {
|
|
|
6982
6720
|
`);
|
|
6983
6721
|
}
|
|
6984
6722
|
|
|
6723
|
+
//#endregion
|
|
6724
|
+
//#region src/cli/apply/services/function-registry.ts
|
|
6725
|
+
const CHUNK_SIZE = 64 * 1024;
|
|
6726
|
+
/**
|
|
6727
|
+
* Compute SHA-256 content hash for a script string.
|
|
6728
|
+
* @param content - Script content to hash
|
|
6729
|
+
* @returns Hex-encoded SHA-256 hash
|
|
6730
|
+
*/
|
|
6731
|
+
function computeContentHash(content) {
|
|
6732
|
+
return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
|
|
6733
|
+
}
|
|
6734
|
+
function functionRegistryTrn(workspaceId, name) {
|
|
6735
|
+
return `trn:v1:workspace:${workspaceId}:function_registry:${name}`;
|
|
6736
|
+
}
|
|
6737
|
+
/**
|
|
6738
|
+
* Build a function registry name for a resolver.
|
|
6739
|
+
* @param namespace - Resolver namespace
|
|
6740
|
+
* @param resolverName - Resolver name
|
|
6741
|
+
* @returns Function registry name
|
|
6742
|
+
*/
|
|
6743
|
+
function resolverFunctionName(namespace, resolverName) {
|
|
6744
|
+
return `resolver--${namespace}--${resolverName}`;
|
|
6745
|
+
}
|
|
6746
|
+
/**
|
|
6747
|
+
* Build a function registry name for an executor.
|
|
6748
|
+
* @param executorName - Executor name
|
|
6749
|
+
* @returns Function registry name
|
|
6750
|
+
*/
|
|
6751
|
+
function executorFunctionName(executorName) {
|
|
6752
|
+
return `executor--${executorName}`;
|
|
6753
|
+
}
|
|
6754
|
+
/**
|
|
6755
|
+
* Build a function registry name for a workflow job.
|
|
6756
|
+
* @param jobName - Workflow job name
|
|
6757
|
+
* @returns Function registry name
|
|
6758
|
+
*/
|
|
6759
|
+
function workflowJobFunctionName(jobName) {
|
|
6760
|
+
return `workflow--${jobName}`;
|
|
6761
|
+
}
|
|
6762
|
+
/**
|
|
6763
|
+
* Collect all function entries from bundled scripts for all services.
|
|
6764
|
+
* @param application - Application definition
|
|
6765
|
+
* @param workflowJobs - Collected workflow jobs from config
|
|
6766
|
+
* @returns Array of function entries to register
|
|
6767
|
+
*/
|
|
6768
|
+
function collectFunctionEntries(application, workflowJobs) {
|
|
6769
|
+
const entries = [];
|
|
6770
|
+
const distDir = getDistDir();
|
|
6771
|
+
for (const app of application.applications) for (const pipeline of app.resolverServices) for (const resolver of Object.values(pipeline.getResolvers())) {
|
|
6772
|
+
const scriptPath = path.join(distDir, "resolvers", `${resolver.name}.js`);
|
|
6773
|
+
try {
|
|
6774
|
+
const content = fs$2.readFileSync(scriptPath, "utf-8");
|
|
6775
|
+
entries.push({
|
|
6776
|
+
name: resolverFunctionName(pipeline.namespace, resolver.name),
|
|
6777
|
+
scriptContent: content,
|
|
6778
|
+
contentHash: computeContentHash(content),
|
|
6779
|
+
description: `Resolver: ${pipeline.namespace}/${resolver.name}`
|
|
6780
|
+
});
|
|
6781
|
+
} catch {
|
|
6782
|
+
logger.warn(`Function file not found: ${scriptPath}`);
|
|
6783
|
+
}
|
|
6784
|
+
}
|
|
6785
|
+
if (application.executorService) {
|
|
6786
|
+
const executors = application.executorService.getExecutors();
|
|
6787
|
+
for (const executor of Object.values(executors)) if (executor.operation.kind === "function" || executor.operation.kind === "jobFunction") {
|
|
6788
|
+
const scriptPath = path.join(distDir, "executors", `${executor.name}.js`);
|
|
6789
|
+
try {
|
|
6790
|
+
const content = fs$2.readFileSync(scriptPath, "utf-8");
|
|
6791
|
+
entries.push({
|
|
6792
|
+
name: executorFunctionName(executor.name),
|
|
6793
|
+
scriptContent: content,
|
|
6794
|
+
contentHash: computeContentHash(content),
|
|
6795
|
+
description: `Executor: ${executor.name}`
|
|
6796
|
+
});
|
|
6797
|
+
} catch {
|
|
6798
|
+
logger.warn(`Function file not found: ${scriptPath}`);
|
|
6799
|
+
}
|
|
6800
|
+
}
|
|
6801
|
+
}
|
|
6802
|
+
for (const job of workflowJobs) {
|
|
6803
|
+
const scriptPath = path.join(distDir, "workflow-jobs", `${job.name}.js`);
|
|
6804
|
+
try {
|
|
6805
|
+
const content = fs$2.readFileSync(scriptPath, "utf-8");
|
|
6806
|
+
entries.push({
|
|
6807
|
+
name: workflowJobFunctionName(job.name),
|
|
6808
|
+
scriptContent: content,
|
|
6809
|
+
contentHash: computeContentHash(content),
|
|
6810
|
+
description: `Workflow job: ${job.name}`
|
|
6811
|
+
});
|
|
6812
|
+
} catch {
|
|
6813
|
+
logger.warn(`Function file not found: ${scriptPath}`);
|
|
6814
|
+
}
|
|
6815
|
+
}
|
|
6816
|
+
return entries;
|
|
6817
|
+
}
|
|
6818
|
+
/**
|
|
6819
|
+
* Plan function registry changes based on current and desired state.
|
|
6820
|
+
* @param client - Operator client instance
|
|
6821
|
+
* @param workspaceId - Workspace ID
|
|
6822
|
+
* @param appName - Application name
|
|
6823
|
+
* @param entries - Desired function entries
|
|
6824
|
+
* @returns Planned changes
|
|
6825
|
+
*/
|
|
6826
|
+
async function planFunctionRegistry(client, workspaceId, appName, entries) {
|
|
6827
|
+
const changeSet = createChangeSet("Function registry");
|
|
6828
|
+
const conflicts = [];
|
|
6829
|
+
const unmanaged = [];
|
|
6830
|
+
const resourceOwners = /* @__PURE__ */ new Set();
|
|
6831
|
+
const existingFunctions = await fetchAll(async (pageToken) => {
|
|
6832
|
+
try {
|
|
6833
|
+
const response = await client.listFunctionRegistries({
|
|
6834
|
+
workspaceId,
|
|
6835
|
+
pageToken
|
|
6836
|
+
});
|
|
6837
|
+
return [response.functions.map((f) => ({
|
|
6838
|
+
name: f.name,
|
|
6839
|
+
contentHash: f.contentHash
|
|
6840
|
+
})), response.nextPageToken];
|
|
6841
|
+
} catch (error) {
|
|
6842
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) return [[], ""];
|
|
6843
|
+
throw error;
|
|
6844
|
+
}
|
|
6845
|
+
});
|
|
6846
|
+
const existingMap = {};
|
|
6847
|
+
await Promise.all(existingFunctions.map(async (func) => {
|
|
6848
|
+
const { metadata } = await client.getMetadata({ trn: functionRegistryTrn(workspaceId, func.name) });
|
|
6849
|
+
existingMap[func.name] = {
|
|
6850
|
+
resource: func,
|
|
6851
|
+
label: metadata?.labels[sdkNameLabelKey]
|
|
6852
|
+
};
|
|
6853
|
+
}));
|
|
6854
|
+
for (const entry of entries) {
|
|
6855
|
+
const existing = existingMap[entry.name];
|
|
6856
|
+
const metaRequest = await buildMetaRequest(functionRegistryTrn(workspaceId, entry.name), appName);
|
|
6857
|
+
if (existing) {
|
|
6858
|
+
if (!existing.label) unmanaged.push({
|
|
6859
|
+
resourceType: "Function registry",
|
|
6860
|
+
resourceName: entry.name
|
|
6861
|
+
});
|
|
6862
|
+
else if (existing.label !== appName) conflicts.push({
|
|
6863
|
+
resourceType: "Function registry",
|
|
6864
|
+
resourceName: entry.name,
|
|
6865
|
+
currentOwner: existing.label
|
|
6866
|
+
});
|
|
6867
|
+
changeSet.updates.push({
|
|
6868
|
+
name: entry.name,
|
|
6869
|
+
entry,
|
|
6870
|
+
metaRequest
|
|
6871
|
+
});
|
|
6872
|
+
delete existingMap[entry.name];
|
|
6873
|
+
} else changeSet.creates.push({
|
|
6874
|
+
name: entry.name,
|
|
6875
|
+
entry,
|
|
6876
|
+
metaRequest
|
|
6877
|
+
});
|
|
6878
|
+
}
|
|
6879
|
+
for (const [name, existing] of Object.entries(existingMap)) {
|
|
6880
|
+
if (!existing) continue;
|
|
6881
|
+
const label = existing.label;
|
|
6882
|
+
if (label && label !== appName) resourceOwners.add(label);
|
|
6883
|
+
if (label === appName) changeSet.deletes.push({
|
|
6884
|
+
name,
|
|
6885
|
+
workspaceId
|
|
6886
|
+
});
|
|
6887
|
+
}
|
|
6888
|
+
changeSet.print();
|
|
6889
|
+
return {
|
|
6890
|
+
changeSet,
|
|
6891
|
+
conflicts,
|
|
6892
|
+
unmanaged,
|
|
6893
|
+
resourceOwners
|
|
6894
|
+
};
|
|
6895
|
+
}
|
|
6896
|
+
/**
|
|
6897
|
+
* Upload a function script to the function registry using client streaming.
|
|
6898
|
+
* @param client - Operator client instance
|
|
6899
|
+
* @param workspaceId - Workspace ID
|
|
6900
|
+
* @param entry - Function entry to upload
|
|
6901
|
+
* @param isCreate - Whether this is a create (true) or update (false)
|
|
6902
|
+
*/
|
|
6903
|
+
async function uploadFunctionScript(client, workspaceId, entry, isCreate) {
|
|
6904
|
+
const buffer = Buffer.from(entry.scriptContent, "utf-8");
|
|
6905
|
+
const info = {
|
|
6906
|
+
workspaceId,
|
|
6907
|
+
name: entry.name,
|
|
6908
|
+
description: entry.description,
|
|
6909
|
+
sizeBytes: BigInt(buffer.length),
|
|
6910
|
+
contentHash: entry.contentHash
|
|
6911
|
+
};
|
|
6912
|
+
if (isCreate) {
|
|
6913
|
+
async function* createStream() {
|
|
6914
|
+
yield { payload: {
|
|
6915
|
+
case: "info",
|
|
6916
|
+
value: info
|
|
6917
|
+
} };
|
|
6918
|
+
for (let i = 0; i < buffer.length; i += CHUNK_SIZE) yield { payload: {
|
|
6919
|
+
case: "chunk",
|
|
6920
|
+
value: buffer.subarray(i, Math.min(i + CHUNK_SIZE, buffer.length))
|
|
6921
|
+
} };
|
|
6922
|
+
}
|
|
6923
|
+
await client.createFunctionRegistry(createStream());
|
|
6924
|
+
} else {
|
|
6925
|
+
async function* updateStream() {
|
|
6926
|
+
yield { payload: {
|
|
6927
|
+
case: "info",
|
|
6928
|
+
value: info
|
|
6929
|
+
} };
|
|
6930
|
+
for (let i = 0; i < buffer.length; i += CHUNK_SIZE) yield { payload: {
|
|
6931
|
+
case: "chunk",
|
|
6932
|
+
value: buffer.subarray(i, Math.min(i + CHUNK_SIZE, buffer.length))
|
|
6933
|
+
} };
|
|
6934
|
+
}
|
|
6935
|
+
await client.updateFunctionRegistry(updateStream());
|
|
6936
|
+
}
|
|
6937
|
+
}
|
|
6938
|
+
/**
|
|
6939
|
+
* Apply function registry changes for the given phase.
|
|
6940
|
+
* @param client - Operator client instance
|
|
6941
|
+
* @param workspaceId
|
|
6942
|
+
* @param result - Planned function registry changes
|
|
6943
|
+
* @param phase - Apply phase
|
|
6944
|
+
*/
|
|
6945
|
+
async function applyFunctionRegistry(client, workspaceId, result, phase = "create-update") {
|
|
6946
|
+
const { changeSet } = result;
|
|
6947
|
+
if (phase === "create-update") {
|
|
6948
|
+
for (const create$1 of changeSet.creates) {
|
|
6949
|
+
await uploadFunctionScript(client, workspaceId, create$1.entry, true);
|
|
6950
|
+
await client.setMetadata(create$1.metaRequest);
|
|
6951
|
+
}
|
|
6952
|
+
for (const update of changeSet.updates) {
|
|
6953
|
+
await uploadFunctionScript(client, workspaceId, update.entry, false);
|
|
6954
|
+
await client.setMetadata(update.metaRequest);
|
|
6955
|
+
}
|
|
6956
|
+
} else if (phase === "delete") await Promise.all(changeSet.deletes.map((del) => client.deleteFunctionRegistry({
|
|
6957
|
+
workspaceId: del.workspaceId,
|
|
6958
|
+
name: del.name
|
|
6959
|
+
})));
|
|
6960
|
+
}
|
|
6961
|
+
|
|
6985
6962
|
//#endregion
|
|
6986
6963
|
//#region src/cli/apply/services/executor.ts
|
|
6987
6964
|
/**
|
|
@@ -7226,22 +7203,19 @@ function protoExecutor(appName, executor, env) {
|
|
|
7226
7203
|
} };
|
|
7227
7204
|
break;
|
|
7228
7205
|
case "function":
|
|
7229
|
-
case "jobFunction":
|
|
7206
|
+
case "jobFunction":
|
|
7230
7207
|
if (target.kind === "function") targetType = ExecutorTargetType.FUNCTION;
|
|
7231
7208
|
else targetType = ExecutorTargetType.JOB_FUNCTION;
|
|
7232
|
-
const scriptPath = path.join(getDistDir(), "executors", `${executor.name}.js`);
|
|
7233
|
-
const script = fs$2.readFileSync(scriptPath, "utf-8");
|
|
7234
7209
|
targetConfig = { config: {
|
|
7235
7210
|
case: "function",
|
|
7236
7211
|
value: {
|
|
7237
|
-
name:
|
|
7238
|
-
|
|
7212
|
+
name: "operation",
|
|
7213
|
+
scriptRef: executorFunctionName(executor.name),
|
|
7239
7214
|
variables: { expr: argsExpr },
|
|
7240
7215
|
invoker: target.authInvoker ?? void 0
|
|
7241
7216
|
}
|
|
7242
7217
|
} };
|
|
7243
7218
|
break;
|
|
7244
|
-
}
|
|
7245
7219
|
case "workflow":
|
|
7246
7220
|
targetType = ExecutorTargetType.WORKFLOW;
|
|
7247
7221
|
targetConfig = { config: {
|
|
@@ -7459,7 +7433,7 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
|
|
|
7459
7433
|
request: {
|
|
7460
7434
|
workspaceId,
|
|
7461
7435
|
namespaceName: pipeline.namespace,
|
|
7462
|
-
pipelineResolver: processResolver(resolver, executorUsedResolvers, env)
|
|
7436
|
+
pipelineResolver: processResolver(pipeline.namespace, resolver, executorUsedResolvers, env)
|
|
7463
7437
|
}
|
|
7464
7438
|
});
|
|
7465
7439
|
existingNameSet.delete(resolver.name);
|
|
@@ -7468,7 +7442,7 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
|
|
|
7468
7442
|
request: {
|
|
7469
7443
|
workspaceId,
|
|
7470
7444
|
namespaceName: pipeline.namespace,
|
|
7471
|
-
pipelineResolver: processResolver(resolver, executorUsedResolvers, env)
|
|
7445
|
+
pipelineResolver: processResolver(pipeline.namespace, resolver, executorUsedResolvers, env)
|
|
7472
7446
|
}
|
|
7473
7447
|
});
|
|
7474
7448
|
existingNameSet.forEach((name) => {
|
|
@@ -7494,20 +7468,13 @@ async function planResolvers(client, workspaceId, pipelines, executors, deletedS
|
|
|
7494
7468
|
});
|
|
7495
7469
|
return changeSet;
|
|
7496
7470
|
}
|
|
7497
|
-
function processResolver(resolver, executorUsedResolvers, env) {
|
|
7498
|
-
const functionPath = path.join(getDistDir(), "resolvers", `${resolver.name}.js`);
|
|
7499
|
-
let functionCode = "";
|
|
7500
|
-
try {
|
|
7501
|
-
functionCode = fs$2.readFileSync(functionPath, "utf-8");
|
|
7502
|
-
} catch {
|
|
7503
|
-
logger.warn(`Function file not found: ${functionPath}`);
|
|
7504
|
-
}
|
|
7471
|
+
function processResolver(namespace, resolver, executorUsedResolvers, env) {
|
|
7505
7472
|
const pipelines = [{
|
|
7506
7473
|
name: "body",
|
|
7507
7474
|
operationName: "body",
|
|
7508
7475
|
description: `${resolver.name} function body`,
|
|
7509
7476
|
operationType: PipelineResolver_OperationType.FUNCTION,
|
|
7510
|
-
|
|
7477
|
+
operationSourceRef: resolverFunctionName(namespace, resolver.name),
|
|
7511
7478
|
operationHook: { expr: `({ ...context.pipeline, input: context.args, user: ${tailorUserMap}, env: ${JSON.stringify(env)} });` },
|
|
7512
7479
|
postScript: `args.body`
|
|
7513
7480
|
}];
|
|
@@ -8594,7 +8561,7 @@ function compareFiles(ctx, typeName, oldFiles, newFiles) {
|
|
|
8594
8561
|
* Compare type-level relationships
|
|
8595
8562
|
* @param {DiffContext} ctx - Diff context
|
|
8596
8563
|
* @param {string} typeName - Type name
|
|
8597
|
-
* @param relationshipType
|
|
8564
|
+
* @param {"forward" | "backward"} relationshipType - Relationship direction to compare
|
|
8598
8565
|
* @param {Record<string, SnapshotRelationship> | undefined} oldRelationships - Previous relationships
|
|
8599
8566
|
* @param {Record<string, SnapshotRelationship> | undefined} newRelationships - Current relationships
|
|
8600
8567
|
* @returns {void}
|
|
@@ -9987,11 +9954,7 @@ function generateTailorDBTypeManifest(type, executorUsedTypes, namespaceGqlOpera
|
|
|
9987
9954
|
type: fieldType,
|
|
9988
9955
|
allowedValues: fieldType === "enum" ? fieldConfig.allowedValues || [] : [],
|
|
9989
9956
|
description: fieldConfig.description || "",
|
|
9990
|
-
validate: (fieldConfig
|
|
9991
|
-
action: TailorDBType_PermitAction.DENY,
|
|
9992
|
-
errorMessage: val.errorMessage || "",
|
|
9993
|
-
...val.script && { script: { expr: val.script.expr ? `!${val.script.expr}` : "" } }
|
|
9994
|
-
})),
|
|
9957
|
+
validate: toProtoFieldValidate(fieldConfig),
|
|
9995
9958
|
array: fieldConfig.array || false,
|
|
9996
9959
|
index: fieldConfig.index || false,
|
|
9997
9960
|
unique: fieldConfig.unique || false,
|
|
@@ -10000,10 +9963,7 @@ function generateTailorDBTypeManifest(type, executorUsedTypes, namespaceGqlOpera
|
|
|
10000
9963
|
foreignKeyField: fieldConfig.foreignKeyField,
|
|
10001
9964
|
required: fieldConfig.required !== false,
|
|
10002
9965
|
vector: fieldConfig.vector || false,
|
|
10003
|
-
...fieldConfig
|
|
10004
|
-
create: fieldConfig.hooks?.create ? { expr: fieldConfig.hooks.create.expr || "" } : void 0,
|
|
10005
|
-
update: fieldConfig.hooks?.update ? { expr: fieldConfig.hooks.update.expr || "" } : void 0
|
|
10006
|
-
} },
|
|
9966
|
+
...toProtoFieldHooks(fieldConfig),
|
|
10007
9967
|
...fieldConfig.serial && { serial: {
|
|
10008
9968
|
start: fieldConfig.serial.start,
|
|
10009
9969
|
...fieldConfig.serial.maxValue && { maxValue: fieldConfig.serial.maxValue },
|
|
@@ -10060,6 +10020,20 @@ function generateTailorDBTypeManifest(type, executorUsedTypes, namespaceGqlOpera
|
|
|
10060
10020
|
}
|
|
10061
10021
|
};
|
|
10062
10022
|
}
|
|
10023
|
+
function toProtoFieldValidate(fieldConfig) {
|
|
10024
|
+
return (fieldConfig.validate || []).map((val) => ({
|
|
10025
|
+
action: TailorDBType_PermitAction.DENY,
|
|
10026
|
+
errorMessage: val.errorMessage || "",
|
|
10027
|
+
...val.script && { script: { expr: val.script.expr ? `!${val.script.expr}` : "" } }
|
|
10028
|
+
}));
|
|
10029
|
+
}
|
|
10030
|
+
function toProtoFieldHooks(fieldConfig) {
|
|
10031
|
+
if (!fieldConfig.hooks) return {};
|
|
10032
|
+
return { hooks: {
|
|
10033
|
+
create: fieldConfig.hooks.create ? { expr: fieldConfig.hooks.create.expr || "" } : void 0,
|
|
10034
|
+
update: fieldConfig.hooks.update ? { expr: fieldConfig.hooks.update.expr || "" } : void 0
|
|
10035
|
+
} };
|
|
10036
|
+
}
|
|
10063
10037
|
function processNestedFields(fields) {
|
|
10064
10038
|
const nestedFields = {};
|
|
10065
10039
|
Object.entries(fields).forEach(([nestedFieldName, nestedFieldConfig]) => {
|
|
@@ -10070,26 +10044,28 @@ function processNestedFields(fields) {
|
|
|
10070
10044
|
type: "nested",
|
|
10071
10045
|
allowedValues: nestedFieldConfig.allowedValues || [],
|
|
10072
10046
|
description: nestedFieldConfig.description || "",
|
|
10073
|
-
validate:
|
|
10047
|
+
validate: toProtoFieldValidate(nestedFieldConfig),
|
|
10074
10048
|
required: nestedFieldConfig.required ?? true,
|
|
10075
10049
|
array: nestedFieldConfig.array ?? false,
|
|
10076
10050
|
index: false,
|
|
10077
10051
|
unique: false,
|
|
10078
10052
|
foreignKey: false,
|
|
10079
10053
|
vector: false,
|
|
10054
|
+
...toProtoFieldHooks(nestedFieldConfig),
|
|
10080
10055
|
fields: deepNestedFields
|
|
10081
10056
|
};
|
|
10082
10057
|
} else nestedFields[nestedFieldName] = {
|
|
10083
10058
|
type: nestedType,
|
|
10084
10059
|
allowedValues: nestedType === "enum" ? nestedFieldConfig.allowedValues || [] : [],
|
|
10085
10060
|
description: nestedFieldConfig.description || "",
|
|
10086
|
-
validate:
|
|
10061
|
+
validate: toProtoFieldValidate(nestedFieldConfig),
|
|
10087
10062
|
required: nestedFieldConfig.required ?? true,
|
|
10088
10063
|
array: nestedFieldConfig.array ?? false,
|
|
10089
10064
|
index: false,
|
|
10090
10065
|
unique: false,
|
|
10091
10066
|
foreignKey: false,
|
|
10092
10067
|
vector: false,
|
|
10068
|
+
...toProtoFieldHooks(nestedFieldConfig),
|
|
10093
10069
|
...nestedFieldConfig.serial && { serial: {
|
|
10094
10070
|
start: nestedFieldConfig.serial.start,
|
|
10095
10071
|
...nestedFieldConfig.serial.maxValue && { maxValue: nestedFieldConfig.serial.maxValue },
|
|
@@ -10448,7 +10424,7 @@ async function registerJobFunctions(client, changeSet, appName) {
|
|
|
10448
10424
|
const jobFunctionVersions = {};
|
|
10449
10425
|
const firstWorkflow = changeSet.creates[0] || changeSet.updates[0];
|
|
10450
10426
|
if (!firstWorkflow) return jobFunctionVersions;
|
|
10451
|
-
const { workspaceId
|
|
10427
|
+
const { workspaceId } = firstWorkflow;
|
|
10452
10428
|
const allUsedJobNames = /* @__PURE__ */ new Set();
|
|
10453
10429
|
for (const item of [...changeSet.creates, ...changeSet.updates]) for (const jobName of item.usedJobNames) allUsedJobNames.add(jobName);
|
|
10454
10430
|
const existingJobFunctions = await fetchAll(async (pageToken) => {
|
|
@@ -10460,16 +10436,14 @@ async function registerJobFunctions(client, changeSet, appName) {
|
|
|
10460
10436
|
});
|
|
10461
10437
|
const existingJobNamesSet = new Set(existingJobFunctions);
|
|
10462
10438
|
const results = await Promise.all(Array.from(allUsedJobNames).map(async (jobName) => {
|
|
10463
|
-
const script = scripts.get(jobName);
|
|
10464
|
-
if (!script) throw new Error(`No bundled script found for job "${jobName}". Please run "generate" command before "apply".`);
|
|
10465
10439
|
const response = existingJobNamesSet.has(jobName) ? await client.updateWorkflowJobFunction({
|
|
10466
10440
|
workspaceId,
|
|
10467
10441
|
jobFunctionName: jobName,
|
|
10468
|
-
|
|
10442
|
+
scriptRef: workflowJobFunctionName(jobName)
|
|
10469
10443
|
}) : await client.createWorkflowJobFunction({
|
|
10470
10444
|
workspaceId,
|
|
10471
10445
|
jobFunctionName: jobName,
|
|
10472
|
-
|
|
10446
|
+
scriptRef: workflowJobFunctionName(jobName)
|
|
10473
10447
|
});
|
|
10474
10448
|
await client.setMetadata(await buildMetaRequest(jobFunctionTrn(workspaceId, jobName), appName));
|
|
10475
10449
|
return {
|
|
@@ -10526,7 +10500,6 @@ async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps
|
|
|
10526
10500
|
label: metadata?.labels[sdkNameLabelKey]
|
|
10527
10501
|
};
|
|
10528
10502
|
}));
|
|
10529
|
-
const allScripts = await loadWorkflowScripts();
|
|
10530
10503
|
for (const workflow of Object.values(workflows)) {
|
|
10531
10504
|
const existing = existingWorkflows[workflow.name];
|
|
10532
10505
|
const metaRequest = await buildMetaRequest(workflowTrn(workspaceId, workflow.name), appName);
|
|
@@ -10546,7 +10519,6 @@ async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps
|
|
|
10546
10519
|
name: workflow.name,
|
|
10547
10520
|
workspaceId,
|
|
10548
10521
|
workflow,
|
|
10549
|
-
scripts: allScripts,
|
|
10550
10522
|
usedJobNames,
|
|
10551
10523
|
metaRequest
|
|
10552
10524
|
});
|
|
@@ -10555,7 +10527,6 @@ async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps
|
|
|
10555
10527
|
name: workflow.name,
|
|
10556
10528
|
workspaceId,
|
|
10557
10529
|
workflow,
|
|
10558
|
-
scripts: allScripts,
|
|
10559
10530
|
usedJobNames,
|
|
10560
10531
|
metaRequest
|
|
10561
10532
|
});
|
|
@@ -10578,19 +10549,6 @@ async function planWorkflow(client, workspaceId, appName, workflows, mainJobDeps
|
|
|
10578
10549
|
appName
|
|
10579
10550
|
};
|
|
10580
10551
|
}
|
|
10581
|
-
async function loadWorkflowScripts() {
|
|
10582
|
-
const scripts = /* @__PURE__ */ new Map();
|
|
10583
|
-
const jobsDir = path.join(getDistDir(), "workflow-jobs");
|
|
10584
|
-
if (!fs$2.existsSync(jobsDir)) return scripts;
|
|
10585
|
-
const files = fs$2.readdirSync(jobsDir);
|
|
10586
|
-
for (const file of files) if (/^[^.]+\.js$/.test(file)) {
|
|
10587
|
-
const jobName = file.replace(/\.js$/, "");
|
|
10588
|
-
const scriptPath = path.join(jobsDir, file);
|
|
10589
|
-
const script = fs$2.readFileSync(scriptPath, "utf-8");
|
|
10590
|
-
scripts.set(jobName, script);
|
|
10591
|
-
}
|
|
10592
|
-
return scripts;
|
|
10593
|
-
}
|
|
10594
10552
|
|
|
10595
10553
|
//#endregion
|
|
10596
10554
|
//#region src/cli/apply/index.ts
|
|
@@ -10608,8 +10566,7 @@ async function apply(options) {
|
|
|
10608
10566
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
10609
10567
|
await generateUserTypes({
|
|
10610
10568
|
config,
|
|
10611
|
-
configPath: config.path
|
|
10612
|
-
plugins
|
|
10569
|
+
configPath: config.path
|
|
10613
10570
|
});
|
|
10614
10571
|
const application = defineApplication({
|
|
10615
10572
|
config,
|
|
@@ -10678,6 +10635,7 @@ async function apply(options) {
|
|
|
10678
10635
|
}
|
|
10679
10636
|
if (workflowResult) printLoadedWorkflows(workflowResult);
|
|
10680
10637
|
logger.newline();
|
|
10638
|
+
const functionEntries = collectFunctionEntries(application, workflowResult?.jobs ?? []);
|
|
10681
10639
|
const ctx = {
|
|
10682
10640
|
client,
|
|
10683
10641
|
workspaceId,
|
|
@@ -10686,6 +10644,7 @@ async function apply(options) {
|
|
|
10686
10644
|
config,
|
|
10687
10645
|
noSchemaCheck: options?.noSchemaCheck
|
|
10688
10646
|
};
|
|
10647
|
+
const functionRegistry = await planFunctionRegistry(client, workspaceId, application.name, functionEntries);
|
|
10689
10648
|
const tailorDB = await planTailorDB(ctx);
|
|
10690
10649
|
const staticWebsite = await planStaticWebsite(ctx);
|
|
10691
10650
|
const idp = await planIdP(ctx);
|
|
@@ -10695,6 +10654,7 @@ async function apply(options) {
|
|
|
10695
10654
|
const executor = await planExecutor(ctx);
|
|
10696
10655
|
const workflow = await planWorkflow(client, workspaceId, application.name, workflowResult?.workflows ?? {}, workflowBuildResult?.mainJobDeps ?? {});
|
|
10697
10656
|
const allConflicts = [
|
|
10657
|
+
...functionRegistry.conflicts,
|
|
10698
10658
|
...tailorDB.conflicts,
|
|
10699
10659
|
...staticWebsite.conflicts,
|
|
10700
10660
|
...idp.conflicts,
|
|
@@ -10705,6 +10665,7 @@ async function apply(options) {
|
|
|
10705
10665
|
];
|
|
10706
10666
|
await confirmOwnerConflict(allConflicts, application.name, yes);
|
|
10707
10667
|
await confirmUnmanagedResources([
|
|
10668
|
+
...functionRegistry.unmanaged,
|
|
10708
10669
|
...tailorDB.unmanaged,
|
|
10709
10670
|
...staticWebsite.unmanaged,
|
|
10710
10671
|
...idp.unmanaged,
|
|
@@ -10732,6 +10693,7 @@ async function apply(options) {
|
|
|
10732
10693
|
});
|
|
10733
10694
|
await confirmImportantResourceDeletion(importantDeletions, yes);
|
|
10734
10695
|
const resourceOwners = new Set([
|
|
10696
|
+
...functionRegistry.resourceOwners,
|
|
10735
10697
|
...tailorDB.resourceOwners,
|
|
10736
10698
|
...staticWebsite.resourceOwners,
|
|
10737
10699
|
...idp.resourceOwners,
|
|
@@ -10752,6 +10714,7 @@ async function apply(options) {
|
|
|
10752
10714
|
logger.info("Dry run enabled. No changes applied.");
|
|
10753
10715
|
return;
|
|
10754
10716
|
}
|
|
10717
|
+
await applyFunctionRegistry(client, workspaceId, functionRegistry, "create-update");
|
|
10755
10718
|
await applyStaticWebsite(client, staticWebsite, "create-update");
|
|
10756
10719
|
await applyIdP(client, idp, "create-update");
|
|
10757
10720
|
await applyAuth(client, auth, "create-update");
|
|
@@ -10771,6 +10734,7 @@ async function apply(options) {
|
|
|
10771
10734
|
await applyAuth(client, auth, "delete-services");
|
|
10772
10735
|
await applyIdP(client, idp, "delete-services");
|
|
10773
10736
|
await applyTailorDB(client, tailorDB, "delete-services");
|
|
10737
|
+
await applyFunctionRegistry(client, workspaceId, functionRegistry, "delete");
|
|
10774
10738
|
logger.success("Successfully applied changes.");
|
|
10775
10739
|
}
|
|
10776
10740
|
async function buildPipeline(namespace, config, triggerContext) {
|
|
@@ -11706,32 +11670,11 @@ function getRunningJobs(execution) {
|
|
|
11706
11670
|
function isTerminalStatus(status) {
|
|
11707
11671
|
return status === WorkflowExecution_Status.SUCCESS || status === WorkflowExecution_Status.FAILED || status === WorkflowExecution_Status.PENDING_RESUME;
|
|
11708
11672
|
}
|
|
11709
|
-
|
|
11710
|
-
|
|
11711
|
-
* @param options - Start options
|
|
11712
|
-
* @returns Start result with wait helper
|
|
11713
|
-
*/
|
|
11714
|
-
async function startWorkflow(options) {
|
|
11715
|
-
const client = await initOperatorClient(await loadAccessToken({
|
|
11716
|
-
useProfile: true,
|
|
11717
|
-
profile: options.profile
|
|
11718
|
-
}));
|
|
11719
|
-
const workspaceId = loadWorkspaceId({
|
|
11720
|
-
workspaceId: options.workspaceId,
|
|
11721
|
-
profile: options.profile
|
|
11722
|
-
});
|
|
11723
|
-
const { config } = await loadConfig(options.configPath);
|
|
11724
|
-
const { application } = await client.getApplication({
|
|
11725
|
-
workspaceId,
|
|
11726
|
-
applicationName: config.name
|
|
11727
|
-
});
|
|
11728
|
-
if (!application?.authNamespace) throw new Error(`Application ${config.name} does not have an auth configuration.`);
|
|
11673
|
+
async function startWorkflowCore(options) {
|
|
11674
|
+
const { client, workspaceId, workflowName } = options;
|
|
11729
11675
|
try {
|
|
11730
|
-
const workflow = await resolveWorkflow(client, workspaceId,
|
|
11731
|
-
const authInvoker = create(AuthInvokerSchema,
|
|
11732
|
-
namespace: application.authNamespace,
|
|
11733
|
-
machineUserName: options.machineUser
|
|
11734
|
-
});
|
|
11676
|
+
const workflow = await resolveWorkflow(client, workspaceId, workflowName);
|
|
11677
|
+
const authInvoker = create(AuthInvokerSchema, options.authInvoker);
|
|
11735
11678
|
const arg$1 = options.arg === void 0 ? void 0 : typeof options.arg === "string" ? options.arg : JSON.stringify(options.arg);
|
|
11736
11679
|
const { executionId } = await client.testStartWorkflow({
|
|
11737
11680
|
workspaceId,
|
|
@@ -11751,10 +11694,54 @@ async function startWorkflow(options) {
|
|
|
11751
11694
|
})
|
|
11752
11695
|
};
|
|
11753
11696
|
} catch (error) {
|
|
11754
|
-
if (error instanceof ConnectError && error.code === Code.NotFound) throw new Error(`Workflow '${
|
|
11697
|
+
if (error instanceof ConnectError && error.code === Code.NotFound) throw new Error(`Workflow '${workflowName}' not found.`);
|
|
11755
11698
|
throw error;
|
|
11756
11699
|
}
|
|
11757
11700
|
}
|
|
11701
|
+
async function startWorkflowByName(options) {
|
|
11702
|
+
const client = await initOperatorClient(await loadAccessToken({
|
|
11703
|
+
useProfile: true,
|
|
11704
|
+
profile: options.profile
|
|
11705
|
+
}));
|
|
11706
|
+
const workspaceId = loadWorkspaceId({
|
|
11707
|
+
workspaceId: options.workspaceId,
|
|
11708
|
+
profile: options.profile
|
|
11709
|
+
});
|
|
11710
|
+
const { config } = await loadConfig(options.configPath);
|
|
11711
|
+
const { application } = await client.getApplication({
|
|
11712
|
+
workspaceId,
|
|
11713
|
+
applicationName: config.name
|
|
11714
|
+
});
|
|
11715
|
+
if (!application?.authNamespace) throw new Error(`Application ${config.name} does not have an auth configuration.`);
|
|
11716
|
+
return await startWorkflowCore({
|
|
11717
|
+
client,
|
|
11718
|
+
workspaceId,
|
|
11719
|
+
workflowName: options.name,
|
|
11720
|
+
authInvoker: {
|
|
11721
|
+
namespace: application.authNamespace,
|
|
11722
|
+
machineUserName: options.machineUser
|
|
11723
|
+
},
|
|
11724
|
+
arg: options.arg,
|
|
11725
|
+
interval: options.interval
|
|
11726
|
+
});
|
|
11727
|
+
}
|
|
11728
|
+
async function startWorkflow(options) {
|
|
11729
|
+
if ("name" in options) return await startWorkflowByName(options);
|
|
11730
|
+
return await startWorkflowCore({
|
|
11731
|
+
client: await initOperatorClient(await loadAccessToken({
|
|
11732
|
+
useProfile: true,
|
|
11733
|
+
profile: options.profile
|
|
11734
|
+
})),
|
|
11735
|
+
workspaceId: loadWorkspaceId({
|
|
11736
|
+
workspaceId: options.workspaceId,
|
|
11737
|
+
profile: options.profile
|
|
11738
|
+
}),
|
|
11739
|
+
workflowName: options.workflow.name,
|
|
11740
|
+
authInvoker: options.authInvoker,
|
|
11741
|
+
arg: options.arg,
|
|
11742
|
+
interval: options.interval
|
|
11743
|
+
});
|
|
11744
|
+
}
|
|
11758
11745
|
const startCommand = defineCommand({
|
|
11759
11746
|
name: "start",
|
|
11760
11747
|
description: "Start a workflow execution.",
|
|
@@ -11774,7 +11761,7 @@ const startCommand = defineCommand({
|
|
|
11774
11761
|
...waitArgs
|
|
11775
11762
|
}),
|
|
11776
11763
|
run: withCommonArgs(async (args) => {
|
|
11777
|
-
const { executionId, wait } = await
|
|
11764
|
+
const { executionId, wait } = await startWorkflowByName({
|
|
11778
11765
|
name: args.name,
|
|
11779
11766
|
machineUser: args.machineuser,
|
|
11780
11767
|
arg: args.arg,
|
|
@@ -12265,12 +12252,7 @@ const headerArg = z.string().superRefine((val, ctx) => {
|
|
|
12265
12252
|
value: val.slice(colonIndex + 1).trim()
|
|
12266
12253
|
};
|
|
12267
12254
|
}).refine((h) => h.key.length > 0, { message: "Header name cannot be empty" });
|
|
12268
|
-
|
|
12269
|
-
* Trigger an executor and return the job ID.
|
|
12270
|
-
* @param options - Options for triggering executor
|
|
12271
|
-
* @returns Result containing the job ID if available
|
|
12272
|
-
*/
|
|
12273
|
-
async function triggerExecutor(options) {
|
|
12255
|
+
async function triggerExecutorByName(options) {
|
|
12274
12256
|
const client = await initOperatorClient(await loadAccessToken({
|
|
12275
12257
|
useProfile: true,
|
|
12276
12258
|
profile: options.profile
|
|
@@ -12291,6 +12273,16 @@ async function triggerExecutor(options) {
|
|
|
12291
12273
|
throw error;
|
|
12292
12274
|
}
|
|
12293
12275
|
}
|
|
12276
|
+
async function triggerExecutor(options) {
|
|
12277
|
+
if ("executorName" in options) return await triggerExecutorByName(options);
|
|
12278
|
+
if (options.executor.trigger.kind !== "incomingWebhook" && options.payload !== void 0) throw new Error(`Executor '${options.executor.name}' has '${options.executor.trigger.kind}' trigger type. The payload is only available for 'incomingWebhook' trigger type.`);
|
|
12279
|
+
return await triggerExecutorByName({
|
|
12280
|
+
executorName: options.executor.name,
|
|
12281
|
+
payload: options.payload,
|
|
12282
|
+
workspaceId: options.workspaceId,
|
|
12283
|
+
profile: options.profile
|
|
12284
|
+
});
|
|
12285
|
+
}
|
|
12294
12286
|
const triggerCommand = defineCommand({
|
|
12295
12287
|
name: "trigger",
|
|
12296
12288
|
description: "Trigger an executor manually.",
|
|
@@ -12384,7 +12376,7 @@ The \`--logs\` option displays logs from the downstream execution when available
|
|
|
12384
12376
|
body: body ?? {},
|
|
12385
12377
|
headers
|
|
12386
12378
|
};
|
|
12387
|
-
const result = await
|
|
12379
|
+
const result = await triggerExecutorByName({
|
|
12388
12380
|
executorName: args.executorName,
|
|
12389
12381
|
payload,
|
|
12390
12382
|
workspaceId: args["workspace-id"],
|
|
@@ -13227,8 +13219,7 @@ async function generate$1(options) {
|
|
|
13227
13219
|
const watch$1 = options?.watch ?? false;
|
|
13228
13220
|
await generateUserTypes({
|
|
13229
13221
|
config,
|
|
13230
|
-
configPath: config.path
|
|
13231
|
-
plugins
|
|
13222
|
+
configPath: config.path
|
|
13232
13223
|
});
|
|
13233
13224
|
const manager = createGenerationManager(config, generators, plugins, config.path);
|
|
13234
13225
|
await manager.generate(watch$1);
|
|
@@ -13570,7 +13561,8 @@ async function execRemove(client, workspaceId, application, config, confirm) {
|
|
|
13570
13561
|
const app = await planApplication(ctx);
|
|
13571
13562
|
const executor = await planExecutor(ctx);
|
|
13572
13563
|
const workflow = await planWorkflow(client, workspaceId, application.name, {}, {});
|
|
13573
|
-
|
|
13564
|
+
const functionRegistry = await planFunctionRegistry(client, workspaceId, application.name, []);
|
|
13565
|
+
if (tailorDB.changeSet.service.deletes.length === 0 && staticWebsite.changeSet.deletes.length === 0 && idp.changeSet.service.deletes.length === 0 && auth.changeSet.service.deletes.length === 0 && pipeline.changeSet.service.deletes.length === 0 && app.deletes.length === 0 && executor.changeSet.deletes.length === 0 && workflow.changeSet.deletes.length === 0 && functionRegistry.changeSet.deletes.length === 0) return;
|
|
13574
13566
|
if (confirm) await confirm();
|
|
13575
13567
|
await applyWorkflow(client, workflow, "delete");
|
|
13576
13568
|
await applyExecutor(client, executor, "delete");
|
|
@@ -13584,6 +13576,7 @@ async function execRemove(client, workspaceId, application, config, confirm) {
|
|
|
13584
13576
|
await applyIdP(client, idp, "delete-services");
|
|
13585
13577
|
await applyTailorDB(client, tailorDB, "delete-resources");
|
|
13586
13578
|
await applyTailorDB(client, tailorDB, "delete-services");
|
|
13579
|
+
await applyFunctionRegistry(client, workspaceId, functionRegistry, "delete");
|
|
13587
13580
|
}
|
|
13588
13581
|
/**
|
|
13589
13582
|
* Remove all resources managed by the current application.
|
|
@@ -14205,7 +14198,7 @@ async function generate(options) {
|
|
|
14205
14198
|
if (options.init) await handleInitOption(namespacesWithMigrations, options.yes);
|
|
14206
14199
|
let pluginManager;
|
|
14207
14200
|
if (plugins.length > 0) pluginManager = new PluginManager(plugins);
|
|
14208
|
-
const { defineApplication: defineApplication$1 } = await import("./application-
|
|
14201
|
+
const { defineApplication: defineApplication$1 } = await import("./application-JwJ_-_PQ.mjs");
|
|
14209
14202
|
const application = defineApplication$1({
|
|
14210
14203
|
config,
|
|
14211
14204
|
pluginManager
|
|
@@ -15416,4 +15409,4 @@ const updateCommand = defineCommand({
|
|
|
15416
15409
|
|
|
15417
15410
|
//#endregion
|
|
15418
15411
|
export { jobsCommand as $, initOperatorClient as $t, generateCommand as A, getMigrationFiles as At, getMachineUserToken as B, generateUserTypes as Bt, resumeCommand as C, compareLocalTypesWithSnapshot as Ct, truncate as D, getLatestMigrationNumber as Dt, listWorkflows as E, formatMigrationNumber as Et, removeCommand$1 as F, formatDiffSummary as Ft, generateCommand$1 as G, fetchLatestToken as Gt, listCommand$5 as H, getDistDir as Ht, listCommand$4 as I, formatMigrationDiff as It, triggerCommand as J, readPlatformConfig as Jt, listWebhookExecutors as K, loadAccessToken as Kt, listOAuth2Clients as L, hasChanges as Lt, show as M, isValidMigrationNumber as Mt, showCommand as N, loadDiff as Nt, truncateCommand as O, getMigrationDirPath as Ot, remove as P, reconstructSnapshotFromMigrations as Pt, getExecutorJob as Q, initOAuth2Client as Qt, getCommand$1 as R, getNamespacesWithMigrations as Rt, healthCommand as S, SCHEMA_FILE_NAME as St, listCommand$3 as T, createSnapshotFromLocalTypes as Tt, listMachineUsers as U, apiCall as Ut, tokenCommand as V, loadConfig as Vt, generate$1 as W, apiCommand as Wt, listCommand$6 as X, fetchAll as Xt, triggerExecutor as Y, writePlatformConfig as Yt, listExecutors as Z, fetchUserInfo as Zt, createCommand as _, bundleMigrationScript as _t, listCommand as a, jsonArgs as an, getWorkflow as at, listCommand$2 as b, INITIAL_SCHEMA_NUMBER as bt, inviteUser as c, listWorkflowExecutions as ct, listCommand$1 as d, apply as dt, readPackageJson as en, listExecutorJobs as et, listWorkspaces as f, applyCommand as ft, deleteWorkspace as g, parseMigrationLabelNumber as gt, deleteCommand as h, MIGRATION_LABEL_KEY as ht, removeUser as i, deploymentArgs as in, getCommand$2 as it, logBetaWarning as j, getNextMigrationNumber as jt, generate as k, getMigrationFilePath as kt, restoreCommand as l, getCommand$3 as lt, getWorkspace as m, waitForExecution$1 as mt, updateUser as n, commonArgs as nn, startCommand as nt, listUsers as o, withCommonArgs as on, executionsCommand as ot, getCommand as p, executeScript as pt, webhookCommand as q, loadWorkspaceId as qt, removeCommand as r, confirmationArgs as rn, startWorkflow as rt, inviteCommand as s, workspaceArgs as sn, getWorkflowExecution as st, updateCommand as t, PATScope as tn, watchExecutorJob as tt, restoreWorkspace as u, getExecutor as ut, createWorkspace as v, DB_TYPES_FILE_NAME as vt, resumeWorkflow as w, compareSnapshots as wt, getAppHealth as x, MIGRATE_FILE_NAME as xt, listApps as y, DIFF_FILE_NAME as yt, getOAuth2Client as z, trnPrefix as zt };
|
|
15419
|
-
//# sourceMappingURL=update-
|
|
15412
|
+
//# sourceMappingURL=update-C_ZTRB63.mjs.map
|