@tailor-platform/sdk 1.13.0 → 1.14.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.
@@ -7607,6 +7607,16 @@ function formatDiffChange(change) {
7607
7607
  const after = change.after;
7608
7608
  return ` ~ ${change.fieldName}: ${formatFieldModification(before, after)}`;
7609
7609
  }
7610
+ case "index_added": return ` + [Index] ${change.indexName}`;
7611
+ case "index_removed": return ` - [Index] ${change.indexName}`;
7612
+ case "index_modified": return ` ~ [Index] ${change.indexName}: ${change.reason ?? "modified"}`;
7613
+ case "file_added": return ` + [File] ${change.fieldName}`;
7614
+ case "file_removed": return ` - [File] ${change.fieldName}`;
7615
+ case "file_modified": return ` ~ [File] ${change.fieldName}: ${change.reason ?? "modified"}`;
7616
+ case "relationship_added": return ` + [Relationship${change.relationshipType ? ` (${change.relationshipType})` : ""}] ${change.relationshipName}`;
7617
+ case "relationship_removed": return ` - [Relationship${change.relationshipType ? ` (${change.relationshipType})` : ""}] ${change.relationshipName}`;
7618
+ case "relationship_modified": return ` ~ [Relationship${change.relationshipType ? ` (${change.relationshipType})` : ""}] ${change.relationshipName}: ${change.reason ?? "modified"}`;
7619
+ case "permission_modified": return ` ~ [Permission] ${change.reason ?? "modified"}`;
7610
7620
  default: return ` ? ${change.typeName}.${change.fieldName ?? ""}`;
7611
7621
  }
7612
7622
  }
@@ -7635,10 +7645,22 @@ function formatFieldModification(before, after) {
7635
7645
  if (Boolean(before.array) !== Boolean(after.array)) changes.push(`array: ${before.array ?? false} → ${after.array ?? false}`);
7636
7646
  if (Boolean(before.index) !== Boolean(after.index)) changes.push(`index: ${before.index ?? false} → ${after.index ?? false}`);
7637
7647
  if (Boolean(before.unique) !== Boolean(after.unique)) changes.push(`unique: ${before.unique ?? false} → ${after.unique ?? false}`);
7648
+ if (Boolean(before.vector) !== Boolean(after.vector)) changes.push(`vector: ${before.vector ?? false} → ${after.vector ?? false}`);
7638
7649
  const beforeAllowed = before.allowedValues ?? [];
7639
7650
  const afterAllowed = after.allowedValues ?? [];
7640
- const afterSet = new Set(afterAllowed);
7641
- if (beforeAllowed.length !== afterAllowed.length || beforeAllowed.some((v) => !afterSet.has(v))) changes.push(`allowedValues: [${beforeAllowed.join(", ")}] → [${afterAllowed.join(", ")}]`);
7651
+ const afterSet = new Set(afterAllowed.map((v) => v.value));
7652
+ if (beforeAllowed.length !== afterAllowed.length || beforeAllowed.some((v) => !afterSet.has(v.value))) {
7653
+ const beforeValues = beforeAllowed.map((v) => v.value).join(", ");
7654
+ const afterValues = afterAllowed.map((v) => v.value).join(", ");
7655
+ changes.push(`allowedValues: [${beforeValues}] → [${afterValues}]`);
7656
+ }
7657
+ const beforeHooks = before.hooks;
7658
+ const afterHooks = after.hooks;
7659
+ if ((beforeHooks?.create?.expr ?? "") !== (afterHooks?.create?.expr ?? "") || (beforeHooks?.update?.expr ?? "") !== (afterHooks?.update?.expr ?? "")) changes.push("hooks modified");
7660
+ const beforeValidate = before.validate ?? [];
7661
+ const afterValidate = after.validate ?? [];
7662
+ if (beforeValidate.length !== afterValidate.length) changes.push(`validations: ${beforeValidate.length} → ${afterValidate.length}`);
7663
+ if (Boolean(before.serial) !== Boolean(after.serial)) changes.push(`serial: ${before.serial ? "enabled" : "disabled"} → ${after.serial ? "enabled" : "disabled"}`);
7642
7664
  return changes.join(", ");
7643
7665
  }
7644
7666
  /**
@@ -7655,44 +7677,34 @@ function formatBreakingChanges(breakingChanges) {
7655
7677
  }
7656
7678
  return lines.join("\n");
7657
7679
  }
7680
+ const DIFF_CHANGE_LABELS = {
7681
+ type_added: "type(s) added",
7682
+ type_removed: "type(s) removed",
7683
+ type_modified: "type(s) modified",
7684
+ field_added: "field(s) added",
7685
+ field_removed: "field(s) removed",
7686
+ field_modified: "field(s) modified",
7687
+ index_added: "index(es) added",
7688
+ index_removed: "index(es) removed",
7689
+ index_modified: "index(es) modified",
7690
+ file_added: "file field(s) added",
7691
+ file_removed: "file field(s) removed",
7692
+ file_modified: "file field(s) modified",
7693
+ relationship_added: "relationship(s) added",
7694
+ relationship_removed: "relationship(s) removed",
7695
+ relationship_modified: "relationship(s) modified",
7696
+ permission_modified: "permission(s) modified"
7697
+ };
7658
7698
  /**
7659
7699
  * Format a summary of the migration diff
7660
7700
  * @param {MigrationDiff} diff - Migration diff to summarize
7661
7701
  * @returns {string} Formatted summary string
7662
7702
  */
7663
7703
  function formatDiffSummary(diff) {
7664
- const stats = {
7665
- typesAdded: 0,
7666
- typesRemoved: 0,
7667
- fieldsAdded: 0,
7668
- fieldsRemoved: 0,
7669
- fieldsModified: 0
7670
- };
7671
- for (const change of diff.changes) switch (change.kind) {
7672
- case "type_added":
7673
- stats.typesAdded++;
7674
- break;
7675
- case "type_removed":
7676
- stats.typesRemoved++;
7677
- break;
7678
- case "field_added":
7679
- stats.fieldsAdded++;
7680
- break;
7681
- case "field_removed":
7682
- stats.fieldsRemoved++;
7683
- break;
7684
- case "field_modified":
7685
- stats.fieldsModified++;
7686
- break;
7687
- }
7688
- const parts = [];
7689
- if (stats.typesAdded > 0) parts.push(`${stats.typesAdded} type(s) added`);
7690
- if (stats.typesRemoved > 0) parts.push(`${stats.typesRemoved} type(s) removed`);
7691
- if (stats.fieldsAdded > 0) parts.push(`${stats.fieldsAdded} field(s) added`);
7692
- if (stats.fieldsRemoved > 0) parts.push(`${stats.fieldsRemoved} field(s) removed`);
7693
- if (stats.fieldsModified > 0) parts.push(`${stats.fieldsModified} field(s) modified`);
7694
- if (parts.length === 0) return "No changes";
7695
- return parts.join(", ");
7704
+ const stats = {};
7705
+ for (const change of diff.changes) stats[change.kind] = (stats[change.kind] ?? 0) + 1;
7706
+ const parts = Object.keys(stats).map((kind) => `${stats[kind]} ${DIFF_CHANGE_LABELS[kind]}`);
7707
+ return parts.length > 0 ? parts.join(", ") : "No changes";
7696
7708
  }
7697
7709
 
7698
7710
  //#endregion
@@ -7775,12 +7787,79 @@ function createSnapshotFieldConfig(field) {
7775
7787
  if (field.config.array) config.array = true;
7776
7788
  if (field.config.index) config.index = true;
7777
7789
  if (field.config.unique) config.unique = true;
7778
- if (field.config.allowedValues && field.config.allowedValues.length > 0) config.allowedValues = field.config.allowedValues.map((v) => v.value);
7790
+ if (field.config.allowedValues && field.config.allowedValues.length > 0) config.allowedValues = field.config.allowedValues.map((v) => ({
7791
+ value: v.value,
7792
+ ...v.description && { description: v.description }
7793
+ }));
7779
7794
  if (field.config.foreignKey) {
7780
7795
  config.foreignKey = true;
7781
7796
  if (field.config.foreignKeyType) config.foreignKeyType = field.config.foreignKeyType;
7782
7797
  if (field.config.foreignKeyField) config.foreignKeyField = field.config.foreignKeyField;
7783
7798
  }
7799
+ if (field.config.description) config.description = field.config.description;
7800
+ if (field.config.vector) config.vector = true;
7801
+ if (field.config.hooks) {
7802
+ config.hooks = {};
7803
+ if (field.config.hooks.create) config.hooks.create = { expr: field.config.hooks.create.expr };
7804
+ if (field.config.hooks.update) config.hooks.update = { expr: field.config.hooks.update.expr };
7805
+ }
7806
+ if (field.config.validate && field.config.validate.length > 0) config.validate = field.config.validate.map((v) => ({
7807
+ script: { expr: v.script.expr },
7808
+ errorMessage: v.errorMessage
7809
+ }));
7810
+ if (field.config.serial) config.serial = {
7811
+ start: field.config.serial.start,
7812
+ ...field.config.serial.maxValue !== void 0 && { maxValue: field.config.serial.maxValue },
7813
+ ...field.config.serial.format && { format: field.config.serial.format }
7814
+ };
7815
+ if (field.config.fields && Object.keys(field.config.fields).length > 0) {
7816
+ config.fields = {};
7817
+ for (const [nestedName, nestedConfig] of Object.entries(field.config.fields)) config.fields[nestedName] = createSnapshotFieldConfigFromOperatorConfig(nestedConfig);
7818
+ }
7819
+ return config;
7820
+ }
7821
+ /**
7822
+ * Create a snapshot field config from an OperatorFieldConfig (for nested fields)
7823
+ * @param {import("@/parser/service/tailordb/types").OperatorFieldConfig} fieldConfig - Field configuration
7824
+ * @returns {SnapshotFieldConfig} Snapshot field configuration
7825
+ */
7826
+ function createSnapshotFieldConfigFromOperatorConfig(fieldConfig) {
7827
+ const config = {
7828
+ type: fieldConfig.type,
7829
+ required: fieldConfig.required !== false
7830
+ };
7831
+ if (fieldConfig.array) config.array = true;
7832
+ if (fieldConfig.index) config.index = true;
7833
+ if (fieldConfig.unique) config.unique = true;
7834
+ if (fieldConfig.allowedValues && fieldConfig.allowedValues.length > 0) config.allowedValues = fieldConfig.allowedValues.map((v) => ({
7835
+ value: v.value,
7836
+ ...v.description && { description: v.description }
7837
+ }));
7838
+ if (fieldConfig.foreignKey) {
7839
+ config.foreignKey = true;
7840
+ if (fieldConfig.foreignKeyType) config.foreignKeyType = fieldConfig.foreignKeyType;
7841
+ if (fieldConfig.foreignKeyField) config.foreignKeyField = fieldConfig.foreignKeyField;
7842
+ }
7843
+ if (fieldConfig.description) config.description = fieldConfig.description;
7844
+ if (fieldConfig.vector) config.vector = true;
7845
+ if (fieldConfig.hooks) {
7846
+ config.hooks = {};
7847
+ if (fieldConfig.hooks.create) config.hooks.create = { expr: fieldConfig.hooks.create.expr };
7848
+ if (fieldConfig.hooks.update) config.hooks.update = { expr: fieldConfig.hooks.update.expr };
7849
+ }
7850
+ if (fieldConfig.validate && fieldConfig.validate.length > 0) config.validate = fieldConfig.validate.map((v) => ({
7851
+ script: { expr: v.script.expr },
7852
+ errorMessage: v.errorMessage
7853
+ }));
7854
+ if (fieldConfig.serial) config.serial = {
7855
+ start: fieldConfig.serial.start,
7856
+ ...fieldConfig.serial.maxValue !== void 0 && { maxValue: fieldConfig.serial.maxValue },
7857
+ ...fieldConfig.serial.format && { format: fieldConfig.serial.format }
7858
+ };
7859
+ if (fieldConfig.fields && Object.keys(fieldConfig.fields).length > 0) {
7860
+ config.fields = {};
7861
+ for (const [nestedName, nestedConfig] of Object.entries(fieldConfig.fields)) config.fields[nestedName] = createSnapshotFieldConfigFromOperatorConfig(nestedConfig);
7862
+ }
7784
7863
  return config;
7785
7864
  }
7786
7865
  /**
@@ -7819,9 +7898,56 @@ function createSnapshotType(type) {
7819
7898
  };
7820
7899
  }
7821
7900
  if (type.files && Object.keys(type.files).length > 0) snapshotType.files = { ...type.files };
7901
+ if (Object.keys(type.forwardRelationships).length > 0) {
7902
+ snapshotType.forwardRelationships = {};
7903
+ for (const [relName, rel] of Object.entries(type.forwardRelationships)) snapshotType.forwardRelationships[relName] = {
7904
+ targetType: rel.targetType,
7905
+ targetField: rel.targetField,
7906
+ sourceField: rel.sourceField,
7907
+ isArray: rel.isArray,
7908
+ description: rel.description
7909
+ };
7910
+ }
7911
+ if (Object.keys(type.backwardRelationships).length > 0) {
7912
+ snapshotType.backwardRelationships = {};
7913
+ for (const [relName, rel] of Object.entries(type.backwardRelationships)) snapshotType.backwardRelationships[relName] = {
7914
+ targetType: rel.targetType,
7915
+ targetField: rel.targetField,
7916
+ sourceField: rel.sourceField,
7917
+ isArray: rel.isArray,
7918
+ description: rel.description
7919
+ };
7920
+ }
7921
+ if (type.permissions.record || type.permissions.gql) {
7922
+ snapshotType.permissions = {};
7923
+ if (type.permissions.record) snapshotType.permissions.record = {
7924
+ create: type.permissions.record.create.map(convertActionPermission),
7925
+ read: type.permissions.record.read.map(convertActionPermission),
7926
+ update: type.permissions.record.update.map(convertActionPermission),
7927
+ delete: type.permissions.record.delete.map(convertActionPermission)
7928
+ };
7929
+ if (type.permissions.gql) snapshotType.permissions.gql = type.permissions.gql.map((policy) => ({
7930
+ conditions: policy.conditions,
7931
+ actions: policy.actions,
7932
+ permit: policy.permit,
7933
+ ...policy.description && { description: policy.description }
7934
+ }));
7935
+ }
7822
7936
  return snapshotType;
7823
7937
  }
7824
7938
  /**
7939
+ * Convert an action permission to snapshot format
7940
+ * @param {StandardActionPermission<"record">} permission - Action permission
7941
+ * @returns {SnapshotActionPermission} Snapshot action permission
7942
+ */
7943
+ function convertActionPermission(permission) {
7944
+ return {
7945
+ conditions: permission.conditions,
7946
+ permit: permission.permit,
7947
+ ...permission.description && { description: permission.description }
7948
+ };
7949
+ }
7950
+ /**
7825
7951
  * Create a schema snapshot from local type definitions
7826
7952
  * @param {Record<string, TailorDBType>} types - Local type definitions
7827
7953
  * @param {string} namespace - Namespace for the snapshot
@@ -7940,6 +8066,95 @@ function applyDiffToSnapshot(snapshot, diff) {
7940
8066
  };
7941
8067
  }
7942
8068
  break;
8069
+ case "index_added":
8070
+ case "index_modified":
8071
+ if (types[change.typeName] && change.indexName) types[change.typeName] = {
8072
+ ...types[change.typeName],
8073
+ indexes: {
8074
+ ...types[change.typeName].indexes,
8075
+ [change.indexName]: change.after
8076
+ }
8077
+ };
8078
+ break;
8079
+ case "index_removed":
8080
+ if (types[change.typeName] && change.indexName && types[change.typeName].indexes) {
8081
+ const { [change.indexName]: _, ...remainingIndexes } = types[change.typeName].indexes;
8082
+ types[change.typeName] = {
8083
+ ...types[change.typeName],
8084
+ indexes: Object.keys(remainingIndexes).length > 0 ? remainingIndexes : void 0
8085
+ };
8086
+ }
8087
+ break;
8088
+ case "file_added":
8089
+ case "file_modified":
8090
+ if (types[change.typeName] && change.fieldName) types[change.typeName] = {
8091
+ ...types[change.typeName],
8092
+ files: {
8093
+ ...types[change.typeName].files,
8094
+ [change.fieldName]: change.after
8095
+ }
8096
+ };
8097
+ break;
8098
+ case "file_removed":
8099
+ if (types[change.typeName] && change.fieldName && types[change.typeName].files) {
8100
+ const { [change.fieldName]: _, ...remainingFiles } = types[change.typeName].files;
8101
+ types[change.typeName] = {
8102
+ ...types[change.typeName],
8103
+ files: Object.keys(remainingFiles).length > 0 ? remainingFiles : void 0
8104
+ };
8105
+ }
8106
+ break;
8107
+ case "relationship_added":
8108
+ case "relationship_modified":
8109
+ if (types[change.typeName] && change.relationshipName) {
8110
+ const rel = change.after;
8111
+ if ((change.relationshipType ?? (types[change.typeName].forwardRelationships?.[change.relationshipName] ? "forward" : types[change.typeName].backwardRelationships?.[change.relationshipName] ? "backward" : "forward")) === "forward") types[change.typeName] = {
8112
+ ...types[change.typeName],
8113
+ forwardRelationships: {
8114
+ ...types[change.typeName].forwardRelationships,
8115
+ [change.relationshipName]: rel
8116
+ }
8117
+ };
8118
+ else types[change.typeName] = {
8119
+ ...types[change.typeName],
8120
+ backwardRelationships: {
8121
+ ...types[change.typeName].backwardRelationships,
8122
+ [change.relationshipName]: rel
8123
+ }
8124
+ };
8125
+ }
8126
+ break;
8127
+ case "relationship_removed":
8128
+ if (types[change.typeName] && change.relationshipName) {
8129
+ const type = types[change.typeName];
8130
+ const targetType = change.relationshipType ?? (type.forwardRelationships?.[change.relationshipName] ? "forward" : type.backwardRelationships?.[change.relationshipName] ? "backward" : null);
8131
+ if (targetType === "forward" && type.forwardRelationships?.[change.relationshipName]) {
8132
+ const { [change.relationshipName]: _, ...remaining } = type.forwardRelationships;
8133
+ types[change.typeName] = {
8134
+ ...type,
8135
+ forwardRelationships: Object.keys(remaining).length > 0 ? remaining : void 0
8136
+ };
8137
+ } else if (targetType === "backward" && type.backwardRelationships?.[change.relationshipName]) {
8138
+ const { [change.relationshipName]: _, ...remaining } = type.backwardRelationships;
8139
+ types[change.typeName] = {
8140
+ ...type,
8141
+ backwardRelationships: Object.keys(remaining).length > 0 ? remaining : void 0
8142
+ };
8143
+ }
8144
+ }
8145
+ break;
8146
+ case "permission_modified":
8147
+ if (types[change.typeName] && change.after) {
8148
+ const after = change.after;
8149
+ types[change.typeName] = {
8150
+ ...types[change.typeName],
8151
+ permissions: {
8152
+ record: after.recordPermission,
8153
+ gql: after.gqlPermission
8154
+ }
8155
+ };
8156
+ }
8157
+ break;
7943
8158
  }
7944
8159
  return {
7945
8160
  ...snapshot,
@@ -7991,15 +8206,51 @@ function areFieldsDifferent(oldField, newField) {
7991
8206
  "array",
7992
8207
  "index",
7993
8208
  "unique",
7994
- "foreignKey"
8209
+ "foreignKey",
8210
+ "vector"
7995
8211
  ]) if ((oldField[prop] ?? false) !== (newField[prop] ?? false)) return true;
7996
8212
  if (oldField.foreignKeyType !== newField.foreignKeyType) return true;
7997
8213
  if (oldField.foreignKeyField !== newField.foreignKeyField) return true;
8214
+ if ((oldField.description ?? "") !== (newField.description ?? "")) return true;
7998
8215
  const oldAllowed = oldField.allowedValues ?? [];
7999
8216
  const newAllowed = newField.allowedValues ?? [];
8000
8217
  if (oldAllowed.length !== newAllowed.length) return true;
8001
- const newAllowedSet = new Set(newAllowed);
8002
- if (oldAllowed.some((v) => !newAllowedSet.has(v))) return true;
8218
+ const newAllowedMap = new Map(newAllowed.map((v) => [v.value, v.description]));
8219
+ for (const v of oldAllowed) {
8220
+ if (!newAllowedMap.has(v.value)) return true;
8221
+ if ((v.description ?? "") !== (newAllowedMap.get(v.value) ?? "")) return true;
8222
+ }
8223
+ const oldHooks = oldField.hooks;
8224
+ const newHooks = newField.hooks;
8225
+ if (Boolean(oldHooks) !== Boolean(newHooks)) return true;
8226
+ if (oldHooks && newHooks) {
8227
+ if ((oldHooks.create?.expr ?? "") !== (newHooks.create?.expr ?? "")) return true;
8228
+ if ((oldHooks.update?.expr ?? "") !== (newHooks.update?.expr ?? "")) return true;
8229
+ }
8230
+ const oldValidate = oldField.validate ?? [];
8231
+ const newValidate = newField.validate ?? [];
8232
+ if (oldValidate.length !== newValidate.length) return true;
8233
+ for (let i = 0; i < oldValidate.length; i++) {
8234
+ if (oldValidate[i].script.expr !== newValidate[i].script.expr) return true;
8235
+ if (oldValidate[i].errorMessage !== newValidate[i].errorMessage) return true;
8236
+ }
8237
+ const oldSerial = oldField.serial;
8238
+ const newSerial = newField.serial;
8239
+ if (Boolean(oldSerial) !== Boolean(newSerial)) return true;
8240
+ if (oldSerial && newSerial) {
8241
+ if (oldSerial.start !== newSerial.start) return true;
8242
+ if (oldSerial.maxValue !== newSerial.maxValue) return true;
8243
+ if ((oldSerial.format ?? "") !== (newSerial.format ?? "")) return true;
8244
+ }
8245
+ const oldFields = oldField.fields ?? {};
8246
+ const newFields = newField.fields ?? {};
8247
+ const oldFieldNames = Object.keys(oldFields);
8248
+ const newFieldNames = Object.keys(newFields);
8249
+ if (oldFieldNames.length !== newFieldNames.length) return true;
8250
+ for (const fieldName of oldFieldNames) {
8251
+ if (!newFields[fieldName]) return true;
8252
+ if (areFieldsDifferent(oldFields[fieldName], newFields[fieldName])) return true;
8253
+ }
8003
8254
  return false;
8004
8255
  }
8005
8256
  /**
@@ -8055,7 +8306,9 @@ function isBreakingFieldChange(typeName, fieldName, oldField, newField) {
8055
8306
  if (oldField && newField && oldField.type === "enum" && newField.type === "enum") {
8056
8307
  const oldAllowed = oldField.allowedValues ?? [];
8057
8308
  const newAllowed = newField.allowedValues ?? [];
8058
- const removedValues = oldAllowed.filter((v) => !newAllowed.includes(v));
8309
+ const oldValues = oldAllowed.map((v) => v.value);
8310
+ const newValuesSet = new Set(newAllowed.map((v) => v.value));
8311
+ const removedValues = oldValues.filter((v) => !newValuesSet.has(v));
8059
8312
  if (removedValues.length > 0) return {
8060
8313
  typeName,
8061
8314
  fieldName,
@@ -8111,29 +8364,35 @@ function compareIndexes(ctx, typeName, oldIndexes, newIndexes) {
8111
8364
  const oldKeys = new Set(Object.keys(oldIndexes || {}));
8112
8365
  const newKeys = new Set(Object.keys(newIndexes || {}));
8113
8366
  for (const indexName of newKeys) if (!oldKeys.has(indexName)) ctx.changes.push({
8114
- kind: "type_modified",
8367
+ kind: "index_added",
8115
8368
  typeName,
8116
- reason: `Index "${indexName}" added`,
8117
- before: { indexes: oldIndexes },
8118
- after: { indexes: newIndexes }
8369
+ indexName,
8370
+ after: newIndexes[indexName]
8119
8371
  });
8120
8372
  for (const indexName of oldKeys) if (!newKeys.has(indexName)) ctx.changes.push({
8121
- kind: "type_modified",
8373
+ kind: "index_removed",
8122
8374
  typeName,
8123
- reason: `Index "${indexName}" removed`,
8124
- before: { indexes: oldIndexes },
8125
- after: { indexes: newIndexes }
8375
+ indexName,
8376
+ before: oldIndexes[indexName]
8126
8377
  });
8127
8378
  for (const indexName of newKeys) if (oldKeys.has(indexName)) {
8128
8379
  const oldIndex = oldIndexes[indexName];
8129
8380
  const newIndex = newIndexes[indexName];
8130
- if (JSON.stringify(oldIndex.fields.toSorted()) !== JSON.stringify(newIndex.fields.toSorted()) || oldIndex.unique !== newIndex.unique) ctx.changes.push({
8131
- kind: "type_modified",
8132
- typeName,
8133
- reason: `Index "${indexName}" modified`,
8134
- before: { indexes: oldIndexes },
8135
- after: { indexes: newIndexes }
8136
- });
8381
+ const oldFieldsStr = JSON.stringify(oldIndex.fields.toSorted());
8382
+ const newFieldsStr = JSON.stringify(newIndex.fields.toSorted());
8383
+ if (oldFieldsStr !== newFieldsStr || oldIndex.unique !== newIndex.unique) {
8384
+ const reasons = [];
8385
+ if (oldFieldsStr !== newFieldsStr) reasons.push("fields changed");
8386
+ if (oldIndex.unique !== newIndex.unique) reasons.push("unique constraint changed");
8387
+ ctx.changes.push({
8388
+ kind: "index_modified",
8389
+ typeName,
8390
+ indexName,
8391
+ reason: reasons.join(", "),
8392
+ before: oldIndex,
8393
+ after: newIndex
8394
+ });
8395
+ }
8137
8396
  }
8138
8397
  }
8139
8398
  /**
@@ -8148,26 +8407,102 @@ function compareFiles(ctx, typeName, oldFiles, newFiles) {
8148
8407
  const oldKeys = new Set(Object.keys(oldFiles || {}));
8149
8408
  const newKeys = new Set(Object.keys(newFiles || {}));
8150
8409
  for (const fileName of newKeys) if (!oldKeys.has(fileName)) ctx.changes.push({
8151
- kind: "type_modified",
8410
+ kind: "file_added",
8152
8411
  typeName,
8153
- reason: `File field "${fileName}" added`,
8154
- before: { files: oldFiles },
8155
- after: { files: newFiles }
8412
+ fieldName: fileName,
8413
+ after: newFiles[fileName]
8156
8414
  });
8157
8415
  for (const fileName of oldKeys) if (!newKeys.has(fileName)) ctx.changes.push({
8158
- kind: "type_modified",
8416
+ kind: "file_removed",
8159
8417
  typeName,
8160
- reason: `File field "${fileName}" removed`,
8161
- before: { files: oldFiles },
8162
- after: { files: newFiles }
8418
+ fieldName: fileName,
8419
+ before: oldFiles[fileName]
8163
8420
  });
8164
8421
  for (const fileName of newKeys) if (oldKeys.has(fileName)) {
8165
8422
  if (oldFiles[fileName] !== newFiles[fileName]) ctx.changes.push({
8166
- kind: "type_modified",
8423
+ kind: "file_modified",
8167
8424
  typeName,
8168
- reason: `File field "${fileName}" description changed`,
8169
- before: { files: oldFiles },
8170
- after: { files: newFiles }
8425
+ fieldName: fileName,
8426
+ reason: "description changed",
8427
+ before: oldFiles[fileName],
8428
+ after: newFiles[fileName]
8429
+ });
8430
+ }
8431
+ }
8432
+ /**
8433
+ * Compare type-level relationships
8434
+ * @param {DiffContext} ctx - Diff context
8435
+ * @param {string} typeName - Type name
8436
+ * @param relationshipType
8437
+ * @param {Record<string, SnapshotRelationship> | undefined} oldRelationships - Previous relationships
8438
+ * @param {Record<string, SnapshotRelationship> | undefined} newRelationships - Current relationships
8439
+ * @returns {void}
8440
+ */
8441
+ function compareRelationships(ctx, typeName, relationshipType, oldRelationships, newRelationships) {
8442
+ const oldKeys = new Set(Object.keys(oldRelationships || {}));
8443
+ const newKeys = new Set(Object.keys(newRelationships || {}));
8444
+ for (const relName of newKeys) if (!oldKeys.has(relName)) ctx.changes.push({
8445
+ kind: "relationship_added",
8446
+ typeName,
8447
+ relationshipName: relName,
8448
+ relationshipType,
8449
+ after: newRelationships[relName]
8450
+ });
8451
+ for (const relName of oldKeys) if (!newKeys.has(relName)) ctx.changes.push({
8452
+ kind: "relationship_removed",
8453
+ typeName,
8454
+ relationshipName: relName,
8455
+ relationshipType,
8456
+ before: oldRelationships[relName]
8457
+ });
8458
+ for (const relName of newKeys) if (oldKeys.has(relName)) {
8459
+ const oldRel = oldRelationships[relName];
8460
+ const newRel = newRelationships[relName];
8461
+ const reasons = [];
8462
+ if (oldRel.targetType !== newRel.targetType) reasons.push("targetType changed");
8463
+ if (oldRel.targetField !== newRel.targetField) reasons.push("targetField changed");
8464
+ if (oldRel.sourceField !== newRel.sourceField) reasons.push("sourceField changed");
8465
+ if (oldRel.isArray !== newRel.isArray) reasons.push("isArray changed");
8466
+ if (reasons.length > 0) ctx.changes.push({
8467
+ kind: "relationship_modified",
8468
+ typeName,
8469
+ relationshipName: relName,
8470
+ relationshipType,
8471
+ reason: reasons.join(", "),
8472
+ before: oldRel,
8473
+ after: newRel
8474
+ });
8475
+ }
8476
+ }
8477
+ /**
8478
+ * Compare type-level permissions
8479
+ * @param {DiffContext} ctx - Diff context
8480
+ * @param {string} typeName - Type name
8481
+ * @param {SnapshotRecordPermission | undefined} oldRecordPerm - Previous record permission
8482
+ * @param {SnapshotRecordPermission | undefined} newRecordPerm - Current record permission
8483
+ * @param {SnapshotGqlPermission | undefined} oldGqlPerm - Previous GQL permission
8484
+ * @param {SnapshotGqlPermission | undefined} newGqlPerm - Current GQL permission
8485
+ * @returns {void}
8486
+ */
8487
+ function comparePermissions(ctx, typeName, oldRecordPerm, newRecordPerm, oldGqlPerm, newGqlPerm) {
8488
+ const recordPermChanged = JSON.stringify(oldRecordPerm ?? null) !== JSON.stringify(newRecordPerm ?? null);
8489
+ const gqlPermChanged = JSON.stringify(oldGqlPerm ?? null) !== JSON.stringify(newGqlPerm ?? null);
8490
+ if (recordPermChanged || gqlPermChanged) {
8491
+ const reasons = [];
8492
+ if (recordPermChanged) reasons.push("record permission");
8493
+ if (gqlPermChanged) reasons.push("GQL permission");
8494
+ ctx.changes.push({
8495
+ kind: "permission_modified",
8496
+ typeName,
8497
+ reason: `${reasons.join(" and ")} changed`,
8498
+ before: {
8499
+ recordPermission: oldRecordPerm,
8500
+ gqlPermission: oldGqlPerm
8501
+ },
8502
+ after: {
8503
+ recordPermission: newRecordPerm,
8504
+ gqlPermission: newGqlPerm
8505
+ }
8171
8506
  });
8172
8507
  }
8173
8508
  }
@@ -8201,6 +8536,9 @@ function compareSnapshots(previous, current) {
8201
8536
  compareTypeFields(ctx, typeName, prevType, currType);
8202
8537
  compareIndexes(ctx, typeName, prevType.indexes, currType.indexes);
8203
8538
  compareFiles(ctx, typeName, prevType.files, currType.files);
8539
+ compareRelationships(ctx, typeName, "forward", prevType.forwardRelationships, currType.forwardRelationships);
8540
+ compareRelationships(ctx, typeName, "backward", prevType.backwardRelationships, currType.backwardRelationships);
8541
+ comparePermissions(ctx, typeName, prevType.permissions?.record, currType.permissions?.record, prevType.permissions?.gql, currType.permissions?.gql);
8204
8542
  }
8205
8543
  return {
8206
8544
  version: SCHEMA_SNAPSHOT_VERSION,
@@ -8306,7 +8644,26 @@ function convertRemoteFieldsToSnapshot(remoteType) {
8306
8644
  if (remoteField.foreignKeyType) config.foreignKeyType = remoteField.foreignKeyType;
8307
8645
  if (remoteField.foreignKeyField) config.foreignKeyField = remoteField.foreignKeyField;
8308
8646
  }
8309
- if (remoteField.allowedValues && remoteField.allowedValues.length > 0) config.allowedValues = remoteField.allowedValues.map((v) => v.value);
8647
+ if (remoteField.allowedValues && remoteField.allowedValues.length > 0) config.allowedValues = remoteField.allowedValues.map((v) => ({
8648
+ value: v.value,
8649
+ ...v.description && { description: v.description }
8650
+ }));
8651
+ if (remoteField.description) config.description = remoteField.description;
8652
+ if (remoteField.vector) config.vector = true;
8653
+ if (remoteField.hooks) {
8654
+ config.hooks = {};
8655
+ if (remoteField.hooks.create?.expr) config.hooks.create = { expr: remoteField.hooks.create.expr };
8656
+ if (remoteField.hooks.update?.expr) config.hooks.update = { expr: remoteField.hooks.update.expr };
8657
+ }
8658
+ if (remoteField.validate && remoteField.validate.length > 0) config.validate = remoteField.validate.map((v) => ({
8659
+ script: { expr: v.script?.expr ?? "" },
8660
+ errorMessage: v.errorMessage ?? ""
8661
+ }));
8662
+ if (remoteField.serial) config.serial = {
8663
+ start: Number(remoteField.serial.start),
8664
+ ...remoteField.serial.maxValue && { maxValue: Number(remoteField.serial.maxValue) },
8665
+ ...remoteField.serial.format && { format: remoteField.serial.format }
8666
+ };
8310
8667
  fields[fieldName] = config;
8311
8668
  }
8312
8669
  return fields;
@@ -8333,19 +8690,24 @@ function compareFields(typeName, fieldName, remoteField, snapshotField) {
8333
8690
  const snapshotFk = snapshotField.foreignKey ?? false;
8334
8691
  if (remoteFk !== snapshotFk) differences.push(`foreignKey: remote=${remoteFk}, expected=${snapshotFk}`);
8335
8692
  if (remoteField.foreignKeyType !== snapshotField.foreignKeyType) differences.push(`foreignKeyType: remote=${remoteField.foreignKeyType ?? "none"}, expected=${snapshotField.foreignKeyType ?? "none"}`);
8336
- const remoteAllowed = new Set(remoteField.allowedValues ?? []);
8337
- const snapshotAllowed = new Set(snapshotField.allowedValues ?? []);
8338
- if (remoteAllowed.size !== snapshotAllowed.size) differences.push(`allowedValues count: remote=${remoteAllowed.size}, expected=${snapshotAllowed.size}`);
8693
+ const remoteAllowed = remoteField.allowedValues ?? [];
8694
+ const snapshotAllowed = snapshotField.allowedValues ?? [];
8695
+ const remoteAllowedValues = new Set(remoteAllowed.map((v) => v.value));
8696
+ const snapshotAllowedValues = new Set(snapshotAllowed.map((v) => v.value));
8697
+ if (remoteAllowedValues.size !== snapshotAllowedValues.size) differences.push(`allowedValues count: remote=${remoteAllowedValues.size}, expected=${snapshotAllowedValues.size}`);
8339
8698
  else {
8340
- for (const v of remoteAllowed) if (!snapshotAllowed.has(v)) {
8699
+ for (const v of remoteAllowedValues) if (!snapshotAllowedValues.has(v)) {
8341
8700
  differences.push(`allowedValues: remote has '${v}' not in snapshot`);
8342
8701
  break;
8343
8702
  }
8344
- for (const v of snapshotAllowed) if (!remoteAllowed.has(v)) {
8703
+ for (const v of snapshotAllowedValues) if (!remoteAllowedValues.has(v)) {
8345
8704
  differences.push(`allowedValues: snapshot has '${v}' not in remote`);
8346
8705
  break;
8347
8706
  }
8348
8707
  }
8708
+ const remoteVector = remoteField.vector ?? false;
8709
+ const snapshotVector = snapshotField.vector ?? false;
8710
+ if (remoteVector !== snapshotVector) differences.push(`vector: remote=${remoteVector}, expected=${snapshotVector}`);
8349
8711
  if (differences.length > 0) return {
8350
8712
  typeName,
8351
8713
  kind: "field_mismatch",
@@ -9056,10 +9418,16 @@ function applyPreMigrationFieldAdjustments(fields, typeChanges) {
9056
9418
  if (!before?.required && after?.required) field.required = false;
9057
9419
  if (!(before?.unique ?? false) && (after?.unique ?? false)) field.unique = false;
9058
9420
  if (before?.allowedValues && after?.allowedValues) {
9059
- if (before.allowedValues.filter((value) => !after.allowedValues.includes(value)).length > 0) field.allowedValues = [...new Set([...before.allowedValues, ...after.allowedValues])].map((value) => ({
9060
- value,
9061
- description: ""
9062
- }));
9421
+ const afterValues = new Set(after.allowedValues.map((v) => v.value));
9422
+ if (before.allowedValues.filter((v) => !afterValues.has(v.value)).length > 0) {
9423
+ const valueMap = /* @__PURE__ */ new Map();
9424
+ for (const v of before.allowedValues) valueMap.set(v.value, v.description ?? "");
9425
+ for (const v of after.allowedValues) if (!valueMap.has(v.value)) valueMap.set(v.value, v.description ?? "");
9426
+ field.allowedValues = Array.from(valueMap.entries()).map(([value, description]) => ({
9427
+ value,
9428
+ description
9429
+ }));
9430
+ }
9063
9431
  }
9064
9432
  }
9065
9433
  }
@@ -11529,31 +11897,31 @@ const jobsCommand = defineCommand({
11529
11897
  description: "List or get executor jobs.",
11530
11898
  examples: [
11531
11899
  {
11532
- cmd: "tailor-sdk executor jobs my-executor",
11900
+ cmd: "my-executor",
11533
11901
  desc: "List jobs for an executor (default: 50 jobs)"
11534
11902
  },
11535
11903
  {
11536
- cmd: "tailor-sdk executor jobs my-executor --limit 10",
11904
+ cmd: "my-executor --limit 10",
11537
11905
  desc: "Limit the number of jobs"
11538
11906
  },
11539
11907
  {
11540
- cmd: "tailor-sdk executor jobs my-executor -s RUNNING",
11908
+ cmd: "my-executor -s RUNNING",
11541
11909
  desc: "Filter by status"
11542
11910
  },
11543
11911
  {
11544
- cmd: "tailor-sdk executor jobs my-executor <job-id>",
11912
+ cmd: "my-executor <job-id>",
11545
11913
  desc: "Get job details"
11546
11914
  },
11547
11915
  {
11548
- cmd: "tailor-sdk executor jobs my-executor <job-id> --attempts",
11916
+ cmd: "my-executor <job-id> --attempts",
11549
11917
  desc: "Get job details with attempts"
11550
11918
  },
11551
11919
  {
11552
- cmd: "tailor-sdk executor jobs my-executor <job-id> -W",
11920
+ cmd: "my-executor <job-id> -W",
11553
11921
  desc: "Wait for job to complete"
11554
11922
  },
11555
11923
  {
11556
- cmd: "tailor-sdk executor jobs my-executor <job-id> -W -l",
11924
+ cmd: "my-executor <job-id> -W -l",
11557
11925
  desc: "Wait for job with logs"
11558
11926
  }
11559
11927
  ],
@@ -11781,23 +12149,23 @@ When using \`--wait\`, the CLI tracks not only the executor job but also any dow
11781
12149
  The \`--logs\` option displays logs from the downstream execution when available.`,
11782
12150
  examples: [
11783
12151
  {
11784
- cmd: "tailor-sdk executor trigger my-executor",
12152
+ cmd: "my-executor",
11785
12153
  desc: "Trigger an executor"
11786
12154
  },
11787
12155
  {
11788
- cmd: "tailor-sdk executor trigger my-executor -d '{\"message\": \"hello\"}'",
12156
+ cmd: "my-executor -d '{\"message\": \"hello\"}'",
11789
12157
  desc: "Trigger with data"
11790
12158
  },
11791
12159
  {
11792
- cmd: "tailor-sdk executor trigger my-executor -d '{\"message\": \"hello\"}' -H \"X-Custom: value\" -H \"X-Another: value2\"",
12160
+ cmd: "my-executor -d '{\"message\": \"hello\"}' -H \"X-Custom: value\" -H \"X-Another: value2\"",
11793
12161
  desc: "Trigger with data and headers"
11794
12162
  },
11795
12163
  {
11796
- cmd: "tailor-sdk executor trigger my-executor -W",
12164
+ cmd: "my-executor -W",
11797
12165
  desc: "Trigger and wait for completion"
11798
12166
  },
11799
12167
  {
11800
- cmd: "tailor-sdk executor trigger my-executor -W -l",
12168
+ cmd: "my-executor -W -l",
11801
12169
  desc: "Trigger, wait, and show logs"
11802
12170
  }
11803
12171
  ],
@@ -13193,13 +13561,15 @@ function extractBreakingChangeFields(diff) {
13193
13561
  optionalToRequired.get(change.typeName).add(change.fieldName);
13194
13562
  }
13195
13563
  if (before && after && before.type === "enum" && after.type === "enum" && before.allowedValues && after.allowedValues) {
13196
- const beforeSet = new Set(before.allowedValues);
13197
- const afterSet = new Set(after.allowedValues);
13198
- if (before.allowedValues.some((v) => !afterSet.has(v)) || after.allowedValues.some((v) => !beforeSet.has(v))) {
13564
+ const beforeValues = before.allowedValues.map((v) => v.value);
13565
+ const afterValues = after.allowedValues.map((v) => v.value);
13566
+ const beforeSet = new Set(beforeValues);
13567
+ const afterSet = new Set(afterValues);
13568
+ if (beforeValues.some((v) => !afterSet.has(v)) || afterValues.some((v) => !beforeSet.has(v))) {
13199
13569
  if (!enumValueChanges.has(change.typeName)) enumValueChanges.set(change.typeName, /* @__PURE__ */ new Map());
13200
13570
  enumValueChanges.get(change.typeName).set(change.fieldName, {
13201
- beforeValues: before.allowedValues,
13202
- afterValues: after.allowedValues
13571
+ beforeValues,
13572
+ afterValues
13203
13573
  });
13204
13574
  }
13205
13575
  }
@@ -13371,8 +13741,10 @@ function generateFieldType(config, isOptionalToRequired, enumValueChange) {
13371
13741
  };
13372
13742
  let baseType;
13373
13743
  let usedTimestamp = false;
13374
- if (config.type === "enum") baseType = config.allowedValues && config.allowedValues.length > 0 ? formatEnumUnion(config.allowedValues) : "string";
13375
- else {
13744
+ if (config.type === "enum") {
13745
+ const enumValues = config.allowedValues?.map((v) => v.value) ?? [];
13746
+ baseType = enumValues.length > 0 ? formatEnumUnion(enumValues) : "string";
13747
+ } else {
13376
13748
  const mapped = mapToTsType(config.type);
13377
13749
  baseType = mapped.type;
13378
13750
  usedTimestamp = mapped.usedTimestamp;
@@ -14883,4 +15255,4 @@ const updateCommand = defineCommand({
14883
15255
 
14884
15256
  //#endregion
14885
15257
  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 };
14886
- //# sourceMappingURL=update-CUvANRhs.mjs.map
15258
+ //# sourceMappingURL=update-BnKKm4aR.mjs.map