@kaelen-ai/cli 0.1.17 → 0.1.19

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/dist/index.js CHANGED
@@ -837,6 +837,7 @@ var BINDING_SCOPES = /* @__PURE__ */ new Set(["project", "principal"]);
837
837
  var CREDENTIAL_SOURCES = /* @__PURE__ */ new Set(["none", "platform", "secret_bundle"]);
838
838
  var TARGET_EXECUTION_KEYS = /* @__PURE__ */ new Set([
839
839
  "applications",
840
+ "application_bindings",
840
841
  "endpoints",
841
842
  "secret_names",
842
843
  "timeout_ms",
@@ -860,6 +861,16 @@ var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
860
861
  ]);
861
862
  var HTTP_LIKE_KINDS = /* @__PURE__ */ new Set(["http", "graphql", "httpApi", "graphqlApi"]);
862
863
  var OP_RESOURCE_KINDS = /* @__PURE__ */ new Set(["httpApi", "graphqlApi"]);
864
+ var PRINCIPAL_RESOLUTION_MATCHES = /* @__PURE__ */ new Set(["principal_id", "external_id"]);
865
+ var WEBHOOK_PRINCIPAL_SOURCES = /* @__PURE__ */ new Set(["body", "headers", "query"]);
866
+ var QUEUE_PRINCIPAL_SOURCES = /* @__PURE__ */ new Set(["message", "attributes"]);
867
+ var PRINCIPAL_BOUND_QUEUE_KINDS = /* @__PURE__ */ new Set([
868
+ "kafka",
869
+ "rabbitmq",
870
+ "redis",
871
+ "pubsub",
872
+ "sqs"
873
+ ]);
863
874
  function countPlaceholders(format) {
864
875
  let count = 0;
865
876
  let idx = 0;
@@ -1057,6 +1068,51 @@ function validateHttpLikeConfig(appName, resourceName, resourceKind, config, sec
1057
1068
  }
1058
1069
  }
1059
1070
  }
1071
+ function validatePrincipalResolution(appName, resourceName, resourceKind, signals2, config, errors) {
1072
+ const requiresPrincipalResolution = resourceKind === "webhook" || PRINCIPAL_BOUND_QUEUE_KINDS.has(resourceKind) && signals2.length > 0;
1073
+ if (!requiresPrincipalResolution) return;
1074
+ const owner = `resource "${appName}/${resourceName}"`;
1075
+ if (!isRecord2(config)) {
1076
+ errors.push(`${owner} config must be an object with principal_resolution`);
1077
+ return;
1078
+ }
1079
+ const rule = config.principal_resolution;
1080
+ if (!isRecord2(rule)) {
1081
+ errors.push(`${owner} config.principal_resolution is required`);
1082
+ return;
1083
+ }
1084
+ const from = stringField2(rule, "from");
1085
+ const match = stringField2(rule, "match");
1086
+ const allowedSources = resourceKind === "webhook" ? WEBHOOK_PRINCIPAL_SOURCES : QUEUE_PRINCIPAL_SOURCES;
1087
+ if (!from || !allowedSources.has(from)) {
1088
+ errors.push(
1089
+ `${owner} principal_resolution.from must be one of ${Array.from(
1090
+ allowedSources
1091
+ ).join(", ")}`
1092
+ );
1093
+ }
1094
+ if (!match || !PRINCIPAL_RESOLUTION_MATCHES.has(match)) {
1095
+ errors.push(
1096
+ `${owner} principal_resolution.match must be principal_id or external_id`
1097
+ );
1098
+ }
1099
+ if (from === "body" || from === "query" || from === "message") {
1100
+ if (!stringField2(rule, "path")) {
1101
+ errors.push(`${owner} principal_resolution.path is required for ${from}`);
1102
+ }
1103
+ if (rule.name !== void 0) {
1104
+ errors.push(`${owner} principal_resolution.name is not valid for ${from}`);
1105
+ }
1106
+ }
1107
+ if (from === "headers" || from === "attributes") {
1108
+ if (!stringField2(rule, "name")) {
1109
+ errors.push(`${owner} principal_resolution.name is required for ${from}`);
1110
+ }
1111
+ if (rule.path !== void 0) {
1112
+ errors.push(`${owner} principal_resolution.path is not valid for ${from}`);
1113
+ }
1114
+ }
1115
+ }
1060
1116
  function isRecord2(value) {
1061
1117
  return !!value && typeof value === "object" && !Array.isArray(value);
1062
1118
  }
@@ -1129,6 +1185,13 @@ function validateTargetExecution(target, declaredApps, declaredEndpoints, errors
1129
1185
  errors.push(`${owner} references undeclared application "${ref}"`);
1130
1186
  }
1131
1187
  }
1188
+ validateApplicationBindings(
1189
+ owner,
1190
+ executionRecord.application_bindings,
1191
+ applicationRefs,
1192
+ declaredApps,
1193
+ errors
1194
+ );
1132
1195
  const endpointRefs = validateScopeList(
1133
1196
  owner,
1134
1197
  "execution.endpoints",
@@ -1161,6 +1224,60 @@ function validateTargetExecution(target, declaredApps, declaredEndpoints, errors
1161
1224
  errors.push(`${owner} endpoints is no longer supported; use execution.endpoints`);
1162
1225
  }
1163
1226
  }
1227
+ function validateApplicationBindings(owner, value, applicationRefs, declaredApps, errors) {
1228
+ if (value === void 0) {
1229
+ if (applicationRefs.length > 0) {
1230
+ errors.push(`${owner} execution.application_bindings is required when execution.applications is set`);
1231
+ }
1232
+ return;
1233
+ }
1234
+ if (!Array.isArray(value)) {
1235
+ errors.push(`${owner} execution.application_bindings must be an array`);
1236
+ return;
1237
+ }
1238
+ const applicationRefSet = new Set(applicationRefs);
1239
+ const boundApplicationNames = /* @__PURE__ */ new Set();
1240
+ const seenAliases = /* @__PURE__ */ new Set();
1241
+ for (const entry of value) {
1242
+ if (!isRecord2(entry)) {
1243
+ errors.push(`${owner} execution.application_bindings entry must be an object`);
1244
+ continue;
1245
+ }
1246
+ for (const key of Object.keys(entry)) {
1247
+ if (key !== "application_name" && key !== "application_alias") {
1248
+ errors.push(
1249
+ `${owner} execution.application_bindings entry contains unsupported key "${key}"`
1250
+ );
1251
+ }
1252
+ }
1253
+ const applicationName = stringField2(entry, "application_name");
1254
+ const applicationAlias = stringField2(entry, "application_alias");
1255
+ if (!applicationName) {
1256
+ errors.push(`${owner} execution.application_bindings entry application_name is required`);
1257
+ continue;
1258
+ }
1259
+ if (!applicationAlias) {
1260
+ errors.push(`${owner} execution.application_bindings entry application_alias is required`);
1261
+ continue;
1262
+ }
1263
+ if (!declaredApps.has(applicationName)) {
1264
+ errors.push(`${owner} execution.application_bindings references undeclared application "${applicationName}"`);
1265
+ }
1266
+ if (!applicationRefSet.has(applicationName)) {
1267
+ errors.push(`${owner} execution.application_bindings references application "${applicationName}" not present in execution.applications`);
1268
+ }
1269
+ if (seenAliases.has(applicationAlias)) {
1270
+ errors.push(`${owner} execution.application_bindings duplicates application_alias "${applicationAlias}"`);
1271
+ }
1272
+ seenAliases.add(applicationAlias);
1273
+ boundApplicationNames.add(applicationName);
1274
+ }
1275
+ for (const ref of applicationRefs) {
1276
+ if (!boundApplicationNames.has(ref)) {
1277
+ errors.push(`${owner} execution.application_bindings is missing application "${ref}"`);
1278
+ }
1279
+ }
1280
+ }
1164
1281
  function validateRateBudget(owner, value, errors) {
1165
1282
  if (value === void 0) return;
1166
1283
  if (!isRecord2(value)) {
@@ -1364,6 +1481,14 @@ function validateManifest(manifest) {
1364
1481
  validateResourceCapability(appName, resourceName, capability, errors);
1365
1482
  }
1366
1483
  const resourceKindForConfig = stringField2(resource, "kind") ?? "";
1484
+ validatePrincipalResolution(
1485
+ appName,
1486
+ resourceName,
1487
+ resourceKindForConfig,
1488
+ signals2,
1489
+ resource.config,
1490
+ errors
1491
+ );
1367
1492
  validateHttpLikeConfig(
1368
1493
  appName,
1369
1494
  resourceName,
@@ -2471,18 +2596,11 @@ ${stdout || "(empty)"}`
2471
2596
 
2472
2597
  // src/build/manifest.ts
2473
2598
  async function generateManifest(input) {
2474
- const entrypoints = {};
2475
- for (const b of input.behaviorBundles) {
2476
- entrypoints[b.name] = `behaviors/${b.name}.js`;
2477
- }
2478
- for (const c of input.conversationBundles) {
2479
- entrypoints[c.name] = `conversations/${c.name}.js`;
2480
- }
2481
2599
  const m = await evaluateAndEmitManifest({
2482
2600
  cwd: input.cwd,
2483
2601
  outDir: input.outDir,
2484
2602
  userFiles: input.userFiles,
2485
- entrypoints
2603
+ entrypoints: input.entrypoints
2486
2604
  });
2487
2605
  await writeFile(
2488
2606
  join(input.outDir, "manifest.json"),
@@ -2946,7 +3064,6 @@ var INTERNAL_RUN = "__io_cli_compiled_run";
2946
3064
  var INTERNAL_ON_START = "__io_cli_compiled_on_start";
2947
3065
  var INTERNAL_ON_MESSAGE = "__io_cli_compiled_on_message";
2948
3066
  var INTERNAL_ON_END = "__io_cli_compiled_on_end";
2949
- var INTERNAL_APPLICATIONS = "__io_cli_compiled_applications";
2950
3067
  function conversationChannel(name) {
2951
3068
  return `session:${name}`;
2952
3069
  }
@@ -3048,13 +3165,6 @@ function functionSourceFromProperty(source, prop, label) {
3048
3165
  }
3049
3166
  return source.slice(value.start, value.end);
3050
3167
  }
3051
- function expressionSourceFromProperty(source, prop, label) {
3052
- const value = prop.value;
3053
- if (!value) {
3054
- throw new BuildError(`compiled target is missing ${label} value`);
3055
- }
3056
- return source.slice(value.start, value.end);
3057
- }
3058
3168
  function replaceRange(source, start, end, text) {
3059
3169
  return `${source.slice(0, start)}${text}${source.slice(end)}`;
3060
3170
  }
@@ -3392,8 +3502,6 @@ function buildBehaviorReplacement(source, spec, behavior) {
3392
3502
  }
3393
3503
  const execution = compactExecution(behavior.execution);
3394
3504
  const runSource = functionSourceFromProperty(source, run, "run");
3395
- const applications = findProperty(spec, "applications");
3396
- const applicationsSource = applications ? expressionSourceFromProperty(source, applications, "applications") : void 0;
3397
3505
  const configEntries = [
3398
3506
  `kind: "behavior"`,
3399
3507
  `name: ${JSON.stringify(behavior.name)}`,
@@ -3402,13 +3510,9 @@ function buildBehaviorReplacement(source, spec, behavior) {
3402
3510
  if (execution) {
3403
3511
  configEntries.push(`execution: ${JSON.stringify(execution)}`);
3404
3512
  }
3405
- if (applicationsSource) {
3406
- configEntries.push(`applications: ${INTERNAL_APPLICATIONS}`);
3407
- }
3408
3513
  const configSource = `Object.freeze({ ${configEntries.join(", ")} })`;
3409
3514
  return {
3410
3515
  replacement: [
3411
- ...applicationsSource ? [`const ${INTERNAL_APPLICATIONS} = ${applicationsSource};`] : [],
3412
3516
  `const ${INTERNAL_CONFIG} = ${configSource};`,
3413
3517
  `const ${INTERNAL_RUN} = ${runSource};`,
3414
3518
  `export { ${INTERNAL_CONFIG} as config, ${INTERNAL_RUN} as run };`
@@ -3416,9 +3520,7 @@ function buildBehaviorReplacement(source, spec, behavior) {
3416
3520
  refs: /* @__PURE__ */ new Set([
3417
3521
  INTERNAL_CONFIG,
3418
3522
  INTERNAL_RUN,
3419
- ...applicationsSource ? [INTERNAL_APPLICATIONS] : [],
3420
- ...refsFromExpressionSource(runSource),
3421
- ...applicationsSource ? refsFromExpressionSource(applicationsSource) : []
3523
+ ...refsFromExpressionSource(runSource)
3422
3524
  ])
3423
3525
  };
3424
3526
  }
@@ -3433,11 +3535,9 @@ function buildConversationReplacement(source, spec, conversation) {
3433
3535
  const execution = compactExecution(conversation.execution);
3434
3536
  const onStart = findProperty(spec, "onStart");
3435
3537
  const onEnd = findProperty(spec, "onEnd");
3436
- const applications = findProperty(spec, "applications");
3437
3538
  const onMessageSource = functionSourceFromProperty(source, onMessage, "onMessage");
3438
3539
  const onStartSource = onStart ? functionSourceFromProperty(source, onStart, "onStart") : void 0;
3439
3540
  const onEndSource = onEnd ? functionSourceFromProperty(source, onEnd, "onEnd") : void 0;
3440
- const applicationsSource = applications ? expressionSourceFromProperty(source, applications, "applications") : void 0;
3441
3541
  const configEntries = [
3442
3542
  `kind: "conversation"`,
3443
3543
  `name: ${JSON.stringify(conversation.name)}`,
@@ -3447,24 +3547,18 @@ function buildConversationReplacement(source, spec, conversation) {
3447
3547
  if (execution) {
3448
3548
  configEntries.push(`execution: ${JSON.stringify(execution)}`);
3449
3549
  }
3450
- if (applicationsSource) {
3451
- configEntries.push(`applications: ${INTERNAL_APPLICATIONS}`);
3452
- }
3453
3550
  const configSource = `Object.freeze({ ${configEntries.join(", ")} })`;
3454
3551
  const refs = /* @__PURE__ */ new Set([
3455
3552
  INTERNAL_CONFIG,
3456
3553
  INTERNAL_ON_START,
3457
3554
  INTERNAL_ON_MESSAGE,
3458
3555
  INTERNAL_ON_END,
3459
- ...applicationsSource ? [INTERNAL_APPLICATIONS] : [],
3460
3556
  ...refsFromExpressionSource(onMessageSource),
3461
3557
  ...onStartSource ? refsFromExpressionSource(onStartSource) : [],
3462
- ...onEndSource ? refsFromExpressionSource(onEndSource) : [],
3463
- ...applicationsSource ? refsFromExpressionSource(applicationsSource) : []
3558
+ ...onEndSource ? refsFromExpressionSource(onEndSource) : []
3464
3559
  ]);
3465
3560
  return {
3466
3561
  replacement: [
3467
- ...applicationsSource ? [`const ${INTERNAL_APPLICATIONS} = ${applicationsSource};`] : [],
3468
3562
  `const ${INTERNAL_CONFIG} = ${configSource};`,
3469
3563
  `const ${INTERNAL_ON_START} = ${onStartSource ?? "undefined"};`,
3470
3564
  `const ${INTERNAL_ON_MESSAGE} = ${onMessageSource};`,
@@ -3549,12 +3643,17 @@ async function buildPipeline(config, cwd = process.cwd(), minify = false, buildD
3549
3643
  bundleAll(allBehaviorSources, outDir, "behaviors", minify),
3550
3644
  bundleAll(allConversationSources, outDir, "conversations", minify)
3551
3645
  ]);
3646
+ const entrypoints = Object.fromEntries(
3647
+ [...behaviorBundles, ...conversationBundles].map((bundle) => [
3648
+ bundle.name,
3649
+ relative(outDir, bundle.outFile).split("\\").join("/")
3650
+ ])
3651
+ );
3552
3652
  const manifest = await generateManifest({
3553
3653
  cwd,
3554
3654
  userFiles: files,
3555
3655
  outDir,
3556
- behaviorBundles,
3557
- conversationBundles
3656
+ entrypoints
3558
3657
  });
3559
3658
  validateManifest(manifest);
3560
3659
  const { catalog: catalog2, warnings } = generateCatalog(manifest);
@@ -6681,7 +6780,7 @@ async function catalogShowCommand(options) {
6681
6780
 
6682
6781
  // src/index.ts
6683
6782
  var program = new Command();
6684
- program.name("io").description("IO CLI \u2014 build and deploy behaviors").version("0.1.17");
6783
+ program.name("io").description("IO CLI \u2014 build and deploy behaviors").version("0.1.19");
6685
6784
  program.command("init").description("Initialize io.config.json for the current project").option("--yes", "Overwrite existing config without prompting").action(initCommand);
6686
6785
  program.command("build").description("Build behaviors from the io/ directory").option("--dir <path>", "Source directory", "io").option("--minify", "Minify bundles", false).action(buildCommand);
6687
6786
  program.command("deploy").description("Build and package for deployment").option("--dir <path>", "Source directory", "io").option("--no-minify", "Skip minification").option("--yes", "Skip confirmation prompt").option("--watch", "Tail deployment status until it reaches a terminal state").action(deployCommand);