@cargo-ai/cdk 1.0.7 → 1.0.9

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.
Files changed (40) hide show
  1. package/README.md +0 -43
  2. package/build/src/cli/auth.d.ts.map +1 -1
  3. package/build/src/cli/auth.js +16 -12
  4. package/build/src/cli/commands/deploy.d.ts.map +1 -1
  5. package/build/src/cli/commands/deploy.js +81 -107
  6. package/build/src/cli/commands/from.d.ts.map +1 -1
  7. package/build/src/cli/commands/from.js +18 -8
  8. package/build/src/cli/commands/init.d.ts.map +1 -1
  9. package/build/src/cli/commands/init.js +13 -8
  10. package/build/src/cli/commands/inputTypes.d.ts +8 -0
  11. package/build/src/cli/commands/inputTypes.d.ts.map +1 -1
  12. package/build/src/cli/commands/inputTypes.js +117 -13
  13. package/build/src/cli/commands/types.d.ts.map +1 -1
  14. package/build/src/cli/commands/types.js +32 -13
  15. package/build/src/cli/io.js +2 -2
  16. package/build/src/cli/version.d.ts.map +1 -1
  17. package/build/src/cli/version.js +10 -6
  18. package/build/src/deploy/apply.d.ts.map +1 -1
  19. package/build/src/deploy/apply.js +37 -30
  20. package/build/src/deploy/compile.d.ts.map +1 -1
  21. package/build/src/deploy/compile.js +7 -5
  22. package/build/src/deploy/destroy.d.ts.map +1 -1
  23. package/build/src/deploy/destroy.js +24 -14
  24. package/build/src/deploy/executors.live.d.ts.map +1 -1
  25. package/build/src/deploy/executors.live.js +202 -173
  26. package/build/src/deploy/import.js +2 -2
  27. package/build/src/deploy/index.js +1 -1
  28. package/build/src/deploy/lock.d.ts.map +1 -1
  29. package/build/src/deploy/lock.js +13 -10
  30. package/build/src/deploy/readers.live.d.ts.map +1 -1
  31. package/build/src/deploy/readers.live.js +27 -15
  32. package/build/src/deploy/refresh.d.ts.map +1 -1
  33. package/build/src/deploy/refresh.js +20 -18
  34. package/build/src/refs.d.ts.map +1 -1
  35. package/build/src/refs.js +5 -1
  36. package/build/src/resources/actions.d.ts +1 -1
  37. package/build/src/resources/actions.d.ts.map +1 -1
  38. package/build/src/resources/actions.js +3 -2
  39. package/build/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +3 -3
@@ -1,17 +1,19 @@
1
- // TypeScript input-type printers for `cargo-ai workflow sync` codegen.
1
+ // TypeScript type printers for `cargo-ai workflow sync` codegen.
2
2
  //
3
- // Three sources of truth, three printers:
3
+ // Sources of truth:
4
4
  // - Integration actions expose their config as JSON Schema on
5
- // `connection.integration.list` (`action.config.schema`).
5
+ // `connection.integration.list` (`action.config.schema`), and — for
6
+ // actions with a static output — their output as `action.output.schema`.
6
7
  // - Workspace tools expose their input as `formFields` on the tool
7
8
  // workflow's deployed release (`orchestration.release.getDeployed`).
8
9
  // - Agent nodes accept a single global shape (`{ prompt, output? }`) —
9
10
  // the engine validates every agent node against `AiUtils.agentConfig`.
10
11
  //
11
- // All printers run in "input mode": each top-level property is widened to
12
- // `Ref<T> | T` so callers can pass either a builder Ref or a literal.
13
- // Anything unrecognized falls back to `unknown` codegen must never abort
14
- // on a schema edge case.
12
+ // Input printers run in "input mode": each top-level property is widened to
13
+ // `Ref<T> | T` so callers can pass either a builder Ref or a literal. The
14
+ // output printer emits plain types (outputs come back as a `Ref` the caller
15
+ // dot-accesses). Anything unrecognized falls back to `unknown` — codegen must
16
+ // never abort on a schema edge case.
15
17
  //
16
18
  // Mirrors `packages/workflow-sdk/scripts/lib/jsonSchemaToTs.ts` (which is a
17
19
  // build-time-only script the CLI can't import).
@@ -47,6 +49,22 @@ export function printJsonSchemaType(schema) {
47
49
  const printed = printSchema(schema, false, true);
48
50
  return printed === "unknown" ? "Record<string, unknown>" : printed;
49
51
  }
52
+ /**
53
+ * Print an integration action's static output JSON Schema as a plain TS type —
54
+ * no `Ref<T> | T` widening and no `EncryptionRef`. Returns `undefined` when
55
+ * the schema is missing or too loose to be useful; the caller falls back to
56
+ * `any`, which stays usable everywhere a nested `Ref<Record<string, unknown>>`
57
+ * would not.
58
+ */
59
+ export function printJsonSchemaOutput(schema) {
60
+ if (schema === null || typeof schema !== "object") {
61
+ return undefined;
62
+ }
63
+ const printed = printSchema(schema, false, false);
64
+ return printed === "unknown" || printed === "Record<string, unknown>"
65
+ ? undefined
66
+ : printed;
67
+ }
50
68
  // The platform's shared `encryption` schema definition: an object with a `type`
51
69
  // const/enum of "encryption" plus `isEncrypted` and `value`. In CDK config types
52
70
  // these positions become `EncryptionRef` (see printObject).
@@ -65,6 +83,10 @@ function isEncryptionSchema(schema) {
65
83
  }
66
84
  function printSchema(schema, topLevel, encRef) {
67
85
  if (Array.isArray(schema.type)) {
86
+ // zod's `z.any()` lowers to the full list of JSON types; print `unknown`
87
+ // instead of a noisy 7-member union.
88
+ if (isAnyTypeList(schema.type))
89
+ return "unknown";
68
90
  return uniqueUnion(schema.type.map((t) => printPrimitive(t, schema, false, encRef)));
69
91
  }
70
92
  if (schema.enum !== undefined && schema.enum.length > 0) {
@@ -83,16 +105,37 @@ function printSchema(schema, topLevel, encRef) {
83
105
  // Connectors model "pick an auth method, then its fields" as an object with
84
106
  // a discriminant property plus `allOf: [{ if, then, else }]`. Expand that to
85
107
  // a discriminated union (e.g. HubSpot → `{ method: "privateApp"; … } | { …
86
- // "oauth"; … }`); otherwise fall back to rendering the head.
108
+ // "oauth"; … }`).
87
109
  const conditional = printConditionalObject(schema, topLevel, encRef);
88
110
  if (conditional !== undefined)
89
111
  return conditional;
112
+ // General case: expand the `allOf` into the distinct object shapes it allows
113
+ // (see `flattenAllOf`) and render them as a union — e.g. Slack postMessage →
114
+ // `{ channelId; … format: "markdown"; body } | { … format: "blockKit";
115
+ // blocks }`. This keeps the base props AND the variant members instead of
116
+ // dropping either.
117
+ const shapes = flattenAllOf(schema);
118
+ if (shapes.length > 0) {
119
+ return uniqueUnion(shapes.map((s) => printObjectShape(s, topLevel, encRef)));
120
+ }
121
+ // Last resort: render the head (never abort codegen on an odd schema).
90
122
  return printSchema(schema.allOf[0], topLevel, encRef);
91
123
  }
92
124
  if (typeof schema.type !== "string")
93
125
  return "unknown";
94
126
  return printPrimitive(schema.type, schema, topLevel, encRef);
95
127
  }
128
+ const ANY_TYPE_LIST = [
129
+ "string",
130
+ "number",
131
+ "boolean",
132
+ "object",
133
+ "array",
134
+ "null",
135
+ ];
136
+ function isAnyTypeList(types) {
137
+ return ANY_TYPE_LIST.every((t) => types.includes(t));
138
+ }
96
139
  function printPrimitive(type, schema, topLevel, encRef) {
97
140
  switch (type) {
98
141
  case "string":
@@ -120,10 +163,14 @@ function printConditionalObject(schema, topLevel, encRef) {
120
163
  if (props === undefined || schema.allOf === undefined)
121
164
  return undefined;
122
165
  const block = schema.allOf.find((a) => a.if !== undefined);
123
- if (block === undefined || block.if?.properties === undefined)
166
+ if (block === undefined)
124
167
  return undefined;
168
+ const blockIf = block.if;
169
+ if (blockIf === undefined || blockIf.properties === undefined) {
170
+ return undefined;
171
+ }
125
172
  // The discriminant: the single property the `if` tests, and its `const` value.
126
- const ifEntries = Object.entries(block.if.properties);
173
+ const ifEntries = Object.entries(blockIf.properties);
127
174
  if (ifEntries.length !== 1)
128
175
  return undefined;
129
176
  const [discKey, discCond] = ifEntries[0];
@@ -143,11 +190,11 @@ function printConditionalObject(schema, topLevel, encRef) {
143
190
  ...props,
144
191
  [discKey]: { const: value },
145
192
  };
146
- if (extra?.properties !== undefined) {
193
+ if (extra !== undefined && extra.properties !== undefined) {
147
194
  Object.assign(branchProps, extra.properties);
148
195
  }
149
196
  const required = new Set(baseRequired);
150
- if (Array.isArray(extra?.required)) {
197
+ if (extra !== undefined && Array.isArray(extra.required)) {
151
198
  for (const r of extra.required)
152
199
  required.add(r);
153
200
  }
@@ -162,7 +209,7 @@ function discriminantValues(schema) {
162
209
  return [schema.const];
163
210
  if (Array.isArray(schema.enum))
164
211
  return schema.enum;
165
- const variants = schema.oneOf ?? schema.anyOf;
212
+ const variants = schema.oneOf !== undefined ? schema.oneOf : schema.anyOf;
166
213
  if (Array.isArray(variants)) {
167
214
  const consts = variants.map((v) => v.const).filter((v) => v !== undefined);
168
215
  if (consts.length > 0)
@@ -170,6 +217,63 @@ function discriminantValues(schema) {
170
217
  }
171
218
  return [];
172
219
  }
220
+ function flattenAllOf(schema) {
221
+ const { allOf = [] } = schema;
222
+ const base = objectShapeOf(schema);
223
+ const seed = base === undefined ? emptyShape() : base;
224
+ return allOf.map(shapesOf).reduce(crossMerge, [seed]);
225
+ }
226
+ // The object shape(s) a single allOf member contributes: one for a plain object,
227
+ // several for an `anyOf`/`oneOf`, or a nested `allOf`'s result. Empty when the
228
+ // member (or any `anyOf`/`oneOf` variant) isn't object-shaped.
229
+ function shapesOf(member) {
230
+ const { allOf, anyOf, oneOf } = member;
231
+ if (allOf !== undefined && allOf.length > 0) {
232
+ return flattenAllOf(member);
233
+ }
234
+ const variants = anyOf !== undefined ? anyOf : oneOf;
235
+ if (variants !== undefined && variants.length > 0) {
236
+ const shapes = variants
237
+ .map(objectShapeOf)
238
+ .filter((shape) => shape !== undefined);
239
+ // A non-object variant drops out above; if any did, the union is incomplete
240
+ // so give up on the whole member rather than emit a narrower type.
241
+ return shapes.length === variants.length ? shapes : [];
242
+ }
243
+ const shape = objectShapeOf(member);
244
+ return shape === undefined ? [] : [shape];
245
+ }
246
+ // Every current shape merged with every option: {a} × [{b}, {c}] → [{ab}, {ac}].
247
+ function crossMerge(shapes, options) {
248
+ return shapes.flatMap((shape) => options.map((option) => mergeShapes(shape, option)));
249
+ }
250
+ // Read a schema as an object shape (its properties + required), or undefined
251
+ // when it isn't object-shaped.
252
+ function objectShapeOf(schema) {
253
+ const { properties, type, required } = schema;
254
+ if (properties === undefined && type !== "object")
255
+ return undefined;
256
+ return {
257
+ properties: { ...properties },
258
+ required: new Set(Array.isArray(required) ? required : []),
259
+ };
260
+ }
261
+ function mergeShapes(a, b) {
262
+ return {
263
+ properties: { ...a.properties, ...b.properties },
264
+ required: new Set([...a.required, ...b.required]),
265
+ };
266
+ }
267
+ function emptyShape() {
268
+ return { properties: {}, required: new Set() };
269
+ }
270
+ function printObjectShape(shape, topLevel, encRef) {
271
+ return printObject({
272
+ type: "object",
273
+ properties: shape.properties,
274
+ required: [...shape.required],
275
+ }, topLevel, encRef);
276
+ }
173
277
  function printArray(schema, encRef) {
174
278
  if (schema.items === undefined)
175
279
  return "unknown[]";
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiHzC,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI,CAgE7E"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwHzC,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI,CAgE7E"}
@@ -1,7 +1,7 @@
1
1
  import { mkdirSync, writeFileSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
  import { handleApiCall, info, success } from "../io.js";
4
- import { printJsonSchemaInput, printJsonSchemaType } from "./inputTypes.js";
4
+ import { printJsonSchemaInput, printJsonSchemaOutput, printJsonSchemaType, } from "./inputTypes.js";
5
5
  // Composite natives surfaced via dedicated SDK syntax / scope helpers —
6
6
  // excluded so we don't double-register them. Mirrors the codegen exclusion
7
7
  // list in `packages/workflow-sdk/scripts/generateNativeIntegration.ts`
@@ -97,7 +97,9 @@ async function fetchWorkspaceSurface(api) {
97
97
  function collectConnectorConfigs(integrations) {
98
98
  const out = [];
99
99
  for (const integration of integrations) {
100
- const schema = integration.connector?.config?.schema;
100
+ const { connector } = integration;
101
+ const connectorConfig = connector !== undefined ? connector.config : undefined;
102
+ const schema = connectorConfig !== undefined ? connectorConfig.schema : undefined;
101
103
  if (schema === undefined)
102
104
  continue;
103
105
  const typeSrc = printJsonSchemaType(schema);
@@ -118,7 +120,10 @@ function collectConnectorConfigs(integrations) {
118
120
  function collectAgentTriggerConfigs(integrations) {
119
121
  const out = [];
120
122
  for (const integration of integrations) {
121
- const schema = integration.agent?.trigger?.config?.schema;
123
+ const { agent } = integration;
124
+ const trigger = agent !== undefined ? agent.trigger : undefined;
125
+ const triggerConfig = trigger !== undefined ? trigger.config : undefined;
126
+ const schema = triggerConfig !== undefined ? triggerConfig.schema : undefined;
122
127
  if (schema === undefined)
123
128
  continue;
124
129
  const typeSrc = printJsonSchemaType(schema);
@@ -139,8 +144,10 @@ function collectExtractorConfigs(integrations) {
139
144
  const out = [];
140
145
  for (const integration of integrations) {
141
146
  const extractors = [];
142
- for (const [slug, extractor] of Object.entries(integration.extractors ?? {}).sort(([a], [b]) => a.localeCompare(b))) {
143
- const schema = extractor.config?.schema;
147
+ const { extractors: rawExtractors = {} } = integration;
148
+ for (const [slug, extractor] of Object.entries(rawExtractors).sort(([a], [b]) => a.localeCompare(b))) {
149
+ const { config } = extractor;
150
+ const schema = config !== undefined ? config.schema : undefined;
144
151
  if (schema === undefined)
145
152
  continue;
146
153
  const typeSrc = printJsonSchemaType(schema);
@@ -161,7 +168,8 @@ function collectExtractorConfigs(integrations) {
161
168
  function collectExtractorSlugs(integrations) {
162
169
  const out = [];
163
170
  for (const integration of integrations) {
164
- const slugs = Object.keys(integration.extractors ?? {}).sort((a, b) => a.localeCompare(b));
171
+ const { extractors = {} } = integration;
172
+ const slugs = Object.keys(extractors).sort((a, b) => a.localeCompare(b));
165
173
  if (slugs.length === 0)
166
174
  continue;
167
175
  out.push({ integrationSlug: integration.slug, slugs });
@@ -172,16 +180,19 @@ function collectExtractorSlugs(integrations) {
172
180
  function collectIntegrations(integrations) {
173
181
  const out = [];
174
182
  for (const integration of integrations) {
175
- const actionEntries = Object.entries(integration.actions ?? {}).sort(([a], [b]) => a.localeCompare(b));
183
+ const { actions: rawActions = {} } = integration;
184
+ const actionEntries = Object.entries(rawActions).sort(([a], [b]) => a.localeCompare(b));
176
185
  if (actionEntries.length === 0)
177
186
  continue;
178
187
  const actions = actionEntries.map(([slug, raw]) => {
179
188
  const meta = raw;
189
+ const { config, output } = meta;
180
190
  return {
181
191
  slug,
182
192
  name: trimOrUndefined(meta.name),
183
193
  description: trimOrUndefined(meta.description),
184
- inputTypeSrc: printJsonSchemaInput(meta.config?.schema),
194
+ inputTypeSrc: printJsonSchemaInput(config !== undefined ? config.schema : undefined),
195
+ outputTypeSrc: printJsonSchemaOutput(output !== undefined ? output.schema : undefined),
185
196
  };
186
197
  });
187
198
  out.push({
@@ -231,7 +242,10 @@ function renderTypes(payload) {
231
242
  if (payload.connectorConfigs.length > 0) {
232
243
  cdkLines.push(` interface ConnectorConfigs {`);
233
244
  for (const c of payload.connectorConfigs) {
234
- const doc = formatJsDoc({ name: c.name ?? c.slug, updatedAt: GENERATED_AT }, " ");
245
+ const doc = formatJsDoc({
246
+ name: c.name !== undefined ? c.name : c.slug,
247
+ updatedAt: GENERATED_AT,
248
+ }, " ");
235
249
  if (doc !== "")
236
250
  cdkLines.push(doc.trimEnd());
237
251
  cdkLines.push(` ${jsonKey(c.slug)}: ${c.typeSrc};`);
@@ -260,7 +274,10 @@ function renderTypes(payload) {
260
274
  if (payload.agentTriggerConfigs.length > 0) {
261
275
  cdkLines.push(` interface AgentTriggerConfigs {`);
262
276
  for (const t of payload.agentTriggerConfigs) {
263
- const doc = formatJsDoc({ name: t.name ?? t.slug, updatedAt: GENERATED_AT }, " ");
277
+ const doc = formatJsDoc({
278
+ name: t.name !== undefined ? t.name : t.slug,
279
+ updatedAt: GENERATED_AT,
280
+ }, " ");
264
281
  if (doc !== "")
265
282
  cdkLines.push(doc.trimEnd());
266
283
  cdkLines.push(` ${jsonKey(t.slug)}: ${t.typeSrc};`);
@@ -276,7 +293,7 @@ function renderTypes(payload) {
276
293
  wfLines.push(` interface Integrations {`);
277
294
  for (const c of payload.integrations) {
278
295
  const intDoc = formatJsDoc({
279
- name: c.name ?? c.slug,
296
+ name: c.name !== undefined ? c.name : c.slug,
280
297
  description: c.description,
281
298
  updatedAt: GENERATED_AT,
282
299
  }, " ");
@@ -292,10 +309,12 @@ function renderTypes(payload) {
292
309
  }, " ");
293
310
  if (actionDoc !== "")
294
311
  wfLines.push(actionDoc.trimEnd());
295
- // Action outputs aren't schema-typed, so `any` (not `Record<string,
312
+ // Actions with a static output schema get a real output type; the rest
313
+ // (dynamic or absent outputs) fall back to `any` (not `Record<string,
296
314
  // unknown>`, which lowers to an unusable nested `Ref`) — the result is
297
315
  // then usable as a string, an object, or in any typed slot.
298
- wfLines.push(` ${jsonKey(action.slug)}: IntegrationAction<${action.inputTypeSrc}, any>;`);
316
+ const outputSrc = action.outputTypeSrc !== undefined ? action.outputTypeSrc : "any";
317
+ wfLines.push(` ${jsonKey(action.slug)}: IntegrationAction<${action.inputTypeSrc}, ${outputSrc}>;`);
299
318
  }
300
319
  wfLines.push(` };`);
301
320
  }
@@ -14,7 +14,7 @@ const useColor = process.stderr.isTTY === true &&
14
14
  process.env["NO_COLOR"] === undefined &&
15
15
  process.env["CI"] !== "true";
16
16
  const colorize = (text, code) => {
17
- if (useColor !== true) {
17
+ if (useColor === false) {
18
18
  return text;
19
19
  }
20
20
  return `\x1B[${code}m${text}\x1B[0m`;
@@ -114,7 +114,7 @@ export function startSpinner(message) {
114
114
  process.stderr.write(`\r\x1B[K${line}\n`);
115
115
  },
116
116
  stop: () => {
117
- if (stopped) {
117
+ if (stopped === true) {
118
118
  return;
119
119
  }
120
120
  stopped = true;
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/cli/version.ts"],"names":[],"mappings":"AAOA,wBAAgB,cAAc,IAAI,MAAM,CAkBvC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/cli/version.ts"],"names":[],"mappings":"AAOA,wBAAgB,cAAc,IAAI,MAAM,CAevC"}
@@ -5,8 +5,8 @@ import { fileURLToPath } from "node:url";
5
5
  // package.json — a walk (not a fixed relative path) so it's independent of build
6
6
  // layout depth.
7
7
  export function packageVersion() {
8
- let cursor = dirname(fileURLToPath(import.meta.url));
9
- for (let i = 0; i < 8; i += 1) {
8
+ const start = dirname(fileURLToPath(import.meta.url));
9
+ for (const cursor of ancestorDirs(start, 8)) {
10
10
  try {
11
11
  const pkg = JSON.parse(readFileSync(join(cursor, "package.json"), "utf-8"));
12
12
  if (pkg.name === "@cargo-ai/cdk" && typeof pkg.version === "string") {
@@ -16,10 +16,14 @@ export function packageVersion() {
16
16
  catch {
17
17
  // no package.json here (or unreadable) — keep walking up
18
18
  }
19
- const parent = dirname(cursor);
20
- if (parent === cursor)
21
- break;
22
- cursor = parent;
23
19
  }
24
20
  return "0.0.0";
25
21
  }
22
+ // The directory chain from `start` walking up to `max` levels, stopping at the
23
+ // filesystem root — so the package root can be found independent of build depth.
24
+ function ancestorDirs(start, max) {
25
+ const parent = dirname(start);
26
+ if (max <= 1 || parent === start)
27
+ return [start];
28
+ return [start, ...ancestorDirs(parent, max - 1)];
29
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/deploy/apply.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/deploy/apply.ts"],"names":[],"mappings":"AAgBA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,KAAK,EACV,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAK7C,MAAM,MAAM,SAAS,GAAG;IACtB,SAAS,CACP,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5D,KAAK,CACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,KAAK,CACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,IAAI,CACF,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,IAAI,CACF,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,SAAS,CACP,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,MAAM,CACJ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,IAAI,CACF,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,iBAAiB,CACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,MAAM,CACJ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,GAAG,CACD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,OAAO,CACL,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,QAAQ,CACN,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,SAAS,CACP,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,OAAO,CACL,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvC,YAAY,CACV,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,UAAU,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB,CAAC;AAMF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAwBF,wBAAsB,KAAK,CACzB,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,SAAS,EACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,EAChC,OAAO,CAAC,EAAE,WAAW,EACrB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAC1C,OAAO,CAAC,WAAW,CAAC,CAuHtB"}
@@ -36,16 +36,18 @@ export async function apply(input, executors, persist, readers, onProgress) {
36
36
  throw new Error(`apply aborted — fix plan errors first: ${detail}`);
37
37
  }
38
38
  const byId = new Map(input.nodes.map((n) => [n.id, n]));
39
+ const priorState = input.state;
40
+ const priorResources = priorState === undefined ? {} : priorState.resources;
39
41
  // Resolved outputs by resource id, seeded from prior state so unchanged
40
42
  // ("noop") dependencies still resolve for their dependents.
41
43
  const outputs = new Map();
42
- for (const [id, entry] of Object.entries(input.state?.resources ?? {})) {
44
+ for (const [id, entry] of Object.entries(priorResources)) {
43
45
  outputs.set(id, entry.outputs);
44
46
  }
45
47
  const state = {
46
- version: input.state?.version ?? 1,
47
- workspaceUuid: input.state?.workspaceUuid ?? "",
48
- resources: { ...(input.state?.resources ?? {}) },
48
+ version: priorState === undefined ? 1 : priorState.version,
49
+ workspaceUuid: priorState === undefined ? "" : priorState.workspaceUuid,
50
+ resources: { ...priorResources },
49
51
  };
50
52
  const applied = [];
51
53
  const skipped = [];
@@ -61,8 +63,7 @@ export async function apply(input, executors, persist, readers, onProgress) {
61
63
  const node = byId.get(entry.id);
62
64
  if (node === undefined)
63
65
  continue; // delete entries — handled by destroy
64
- let change = entry.change;
65
- if (change === "noop") {
66
+ if (entry.change === "noop") {
66
67
  // A noop's own spec hash is unchanged, but if one of its dependencies
67
68
  // produced a NEW output identity this run, the tokens in this spec now
68
69
  // resolve to different values than its live config holds (e.g. it still
@@ -70,50 +71,41 @@ export async function apply(input, executors, persist, readers, onProgress) {
70
71
  // re-points at the new value; otherwise it silently dangles.
71
72
  const deps = dependenciesOf(node.spec);
72
73
  const stale = Array.from(deps).some((d) => changedOutputs.has(d));
73
- if (!stale) {
74
+ if (stale === false) {
74
75
  skipped.push(entry);
75
76
  continue;
76
77
  }
77
- change = "update";
78
78
  total += 1; // a noop promoted to a re-apply — count it
79
79
  }
80
- index += 1;
81
80
  // `change` is create|update here (noop was skipped/promoted above; delete
82
- // entries have no node and were `continue`d). `index`/`total` are fixed for
83
- // this resource, so the start/done events share one payload.
81
+ // entries have no node and were `continue`d).
82
+ const change = entry.change === "noop" ? "update" : entry.change;
83
+ index += 1;
84
+ // `index`/`total` are fixed for this resource, so the start/done events
85
+ // share one payload.
84
86
  const progress = {
85
87
  id: node.id,
86
88
  change: change,
87
89
  index,
88
90
  total,
89
91
  };
90
- onProgress?.({ phase: "start", ...progress });
92
+ if (onProgress !== undefined)
93
+ onProgress({ phase: "start", ...progress });
91
94
  // tokens (deferred outputs) then secrets (deferred env reads) — both resolve
92
95
  // to real values here, at apply, just before the executor runs.
93
96
  const resolved = resolveSecrets(resolveTokens(node.spec, outputs));
94
97
  assertNoPlaceholders(node.id, resolved);
95
- const prior = input.state?.resources[node.id];
96
- let produced;
97
- try {
98
- produced = await runExecutor(node, resolved, prior, executors);
99
- }
100
- catch (error) {
101
- // Tag the failure with the resource that failed and surface the API's
102
- // structured detail — executors throw `@cargo-ai/api` FetcherErrors whose
103
- // bare `message` is often a terse "Invalid configuration", with the
104
- // actionable bits (reason, status, which field) on `reason`/`status`/`data`.
105
- throw new Error(`${node.id}: ${describeExecutorError(error)}`, {
106
- cause: error,
107
- });
108
- }
98
+ const prior = priorState === undefined ? undefined : priorState.resources[node.id];
99
+ const produced = await runExecutorTagged(node, resolved, prior, executors);
100
+ const priorOutputs = prior === undefined ? undefined : prior.outputs;
109
101
  // Carry the "adopted" marker forward across updates so destroy keeps
110
102
  // releasing (not deleting) a resource the CDK adopted or imported, even for
111
103
  // kinds whose executor doesn't echo it back.
112
- if (prior?.outputs["adopted"] === "true" &&
113
- produced["adopted"] === undefined) {
104
+ const priorAdopted = priorOutputs === undefined ? undefined : priorOutputs["adopted"];
105
+ if (priorAdopted === "true" && produced["adopted"] === undefined) {
114
106
  produced["adopted"] = "true";
115
107
  }
116
- if (outputsChanged(prior?.outputs, produced)) {
108
+ if (outputsChanged(priorOutputs, produced)) {
117
109
  changedOutputs.add(node.id);
118
110
  }
119
111
  outputs.set(node.id, produced);
@@ -139,7 +131,8 @@ export async function apply(input, executors, persist, readers, onProgress) {
139
131
  }
140
132
  if (persist !== undefined)
141
133
  persist(state);
142
- onProgress?.({ phase: "done", ...progress });
134
+ if (onProgress !== undefined)
135
+ onProgress({ phase: "done", ...progress });
143
136
  applied.push(change === entry.change ? entry : { ...entry, change });
144
137
  }
145
138
  return { state, applied, skipped };
@@ -191,6 +184,20 @@ function outputsChanged(prior, produced) {
191
184
  }
192
185
  return false;
193
186
  }
187
+ // Run the executor, tagging any failure with the resource that failed and the
188
+ // API's structured detail — executors throw `@cargo-ai/api` FetcherErrors whose
189
+ // bare `message` is often a terse "Invalid configuration", with the actionable
190
+ // bits (reason, status, which field) on `reason`/`status`/`data`.
191
+ async function runExecutorTagged(node, resolved, prior, executors) {
192
+ try {
193
+ return await runExecutor(node, resolved, prior, executors);
194
+ }
195
+ catch (error) {
196
+ throw new Error(`${node.id}: ${describeExecutorError(error)}`, {
197
+ cause: error,
198
+ });
199
+ }
200
+ }
194
201
  function runExecutor(node, resolved, prior, executors) {
195
202
  switch (node.kind) {
196
203
  case "connector":
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/deploy/compile.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,YAAY,EAElB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEjE,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IAIb,IAAI,EAAE,MAAM,CAAC;IAGb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAIhC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAKhB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AACF,MAAM,MAAM,KAAK,GAAG;IAClB,OAAO,EAAE,MAAM,CAAC;IAGhB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B,CAAC;AAmEF,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,CAuC1D"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../src/deploy/compile.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,YAAY,EAElB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEjE,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IAIb,IAAI,EAAE,MAAM,CAAC;IAGb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAIhC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAKhB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AACF,MAAM,MAAM,KAAK,GAAG;IAClB,OAAO,EAAE,MAAM,CAAC;IAGhB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B,CAAC;AAqEF,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,CAyC1D"}
@@ -18,7 +18,8 @@ function validate(nodes, edges) {
18
18
  const errors = [];
19
19
  const ids = new Set(nodes.map((n) => n.id));
20
20
  for (const node of nodes) {
21
- for (const dep of edges.get(node.id) ?? new Set()) {
21
+ const nodeEdges = edges.get(node.id);
22
+ for (const dep of nodeEdges !== undefined ? nodeEdges : new Set()) {
22
23
  if (!ids.has(dep)) {
23
24
  errors.push({
24
25
  id: node.id,
@@ -42,7 +43,8 @@ function topoSort(nodes, edges) {
42
43
  return false;
43
44
  }
44
45
  visited.set(id, "visiting");
45
- for (const dep of edges.get(id) ?? new Set()) {
46
+ const idEdges = edges.get(id);
47
+ for (const dep of idEdges !== undefined ? idEdges : new Set()) {
46
48
  if (!edges.has(dep))
47
49
  continue; // unknown dep — reported by validate()
48
50
  if (!visit(dep)) {
@@ -63,7 +65,7 @@ function topoSort(nodes, edges) {
63
65
  return { order, cycle };
64
66
  }
65
67
  export function compile(input) {
66
- const { nodes } = input;
68
+ const { nodes, state } = input;
67
69
  const byId = new Map(nodes.map((n) => [n.id, n]));
68
70
  const edges = new Map();
69
71
  for (const node of nodes) {
@@ -80,14 +82,14 @@ export function compile(input) {
80
82
  const plan = order.map((id) => {
81
83
  const node = byId.get(id);
82
84
  const hash = hashOf(node.spec);
83
- const prior = input.state?.resources[id];
85
+ const prior = state !== undefined ? state.resources[id] : undefined;
84
86
  const change = prior === undefined ? "create" : prior.hash === hash ? "noop" : "update";
85
87
  return { id, kind: node.kind, slug: node.slug, change, hash };
86
88
  });
87
89
  // Resources in state but no longer in code — candidates to prune. Appended
88
90
  // after the apply order; the actual removal runs in dependency-safe order.
89
91
  const deletes = [];
90
- for (const [id, entry] of Object.entries(input.state?.resources ?? {})) {
92
+ for (const [id, entry] of Object.entries(state !== undefined ? state.resources : {})) {
91
93
  if (byId.has(id))
92
94
  continue;
93
95
  const kind = id.slice(0, id.indexOf(":"));
@@ -1 +1 @@
1
- {"version":3,"file":"destroy.d.ts","sourceRoot":"","sources":["../../../src/deploy/destroy.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAMzC,MAAM,MAAM,aAAa,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AA8ItE;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,MAAM,EAAE,GACZ,OAAO,CAAC,aAAa,CAAC,CA4BxB;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,GAAG,EACR,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7B,OAAO,CAAC,aAAa,CAAC,CA4BxB"}
1
+ {"version":3,"file":"destroy.d.ts","sourceRoot":"","sources":["../../../src/deploy/destroy.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAMzC,MAAM,MAAM,aAAa,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAyJtE;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,MAAM,EAAE,GACZ,OAAO,CAAC,aAAa,CAAC,CA4BxB;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,GAAG,EACR,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7B,OAAO,CAAC,aAAa,CAAC,CAgCxB"}
@@ -55,7 +55,9 @@ function removalOrder(ids, state) {
55
55
  if (visited.has(id))
56
56
  return;
57
57
  visited.add(id);
58
- const deps = (state.resources[id]?.deps ?? [])
58
+ const entry = state.resources[id];
59
+ const rawDeps = entry !== undefined && entry.deps !== undefined ? entry.deps : [];
60
+ const deps = rawDeps
59
61
  .filter((dep) => inSet.has(dep) && dep !== id)
60
62
  .sort(reverseKind);
61
63
  for (const dep of deps)
@@ -116,18 +118,21 @@ async function remove(api, kind, uuid) {
116
118
  const datasetUuid = target.fromDatasetUuid;
117
119
  const remaining = relationships
118
120
  .filter((r) => r.fromDatasetUuid === datasetUuid && r.uuid !== uuid)
119
- .map((r) => ({
120
- uuid: r.uuid,
121
- fromModelUuid: r.fromModelUuid,
122
- fromColumnSlug: r.fromColumnSlug,
123
- fromPropertySlug: r.fromPropertySlug ?? null,
124
- toModelUuid: r.toModelUuid,
125
- toColumnSlug: r.toColumnSlug,
126
- toPropertySlug: r.toPropertySlug ?? null,
127
- fromSelectedColumnSlugs: r.fromSelectedColumnSlugs ?? null,
128
- toSelectedColumnSlugs: r.toSelectedColumnSlugs ?? null,
129
- relation: r.relation,
130
- }));
121
+ .map((r) => {
122
+ const { fromPropertySlug = null, toPropertySlug = null, fromSelectedColumnSlugs = null, toSelectedColumnSlugs = null, } = r;
123
+ return {
124
+ uuid: r.uuid,
125
+ fromModelUuid: r.fromModelUuid,
126
+ fromColumnSlug: r.fromColumnSlug,
127
+ fromPropertySlug,
128
+ toModelUuid: r.toModelUuid,
129
+ toColumnSlug: r.toColumnSlug,
130
+ toPropertySlug,
131
+ fromSelectedColumnSlugs,
132
+ toSelectedColumnSlugs,
133
+ relation: r.relation,
134
+ };
135
+ });
131
136
  await api.storage.relationship.set({
132
137
  datasetUuid,
133
138
  relationships: remaining,
@@ -181,7 +186,12 @@ export async function destroy(root, api, opts = {}) {
181
186
  if (opts.target !== undefined && opts.target in state.resources) {
182
187
  const target = opts.target;
183
188
  const dependents = Object.entries(state.resources)
184
- .filter(([id, e]) => id !== target && (e.deps ?? []).includes(target))
189
+ .filter(([id, e]) => {
190
+ if (id === target)
191
+ return false;
192
+ const deps = e.deps !== undefined ? e.deps : [];
193
+ return deps.includes(target);
194
+ })
185
195
  .map(([id]) => id);
186
196
  if (dependents.length > 0) {
187
197
  throw new Error(`cannot destroy "${target}": ${String(dependents.length)} resource(s) ` +