@fmaplabs/meta-manifest 0.2.0 → 0.3.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.
@@ -4,7 +4,7 @@ import {
4
4
  PULL_DEFINITION_QUERY,
5
5
  UPDATE_DEFINITION_MUTATION,
6
6
  execute
7
- } from "./chunk-3R6VQ3Z3.js";
7
+ } from "./chunk-VSJUGUH7.js";
8
8
 
9
9
  // src/fields/base.ts
10
10
  var Field = class {
@@ -13,6 +13,14 @@ var Field = class {
13
13
  required = false;
14
14
  name;
15
15
  description;
16
+ filterable = false;
17
+ /** Apply the shared field options; call from each concrete constructor. */
18
+ applyCommon(opts) {
19
+ this.required = opts.required ?? false;
20
+ this.name = opts.name;
21
+ this.description = opts.description;
22
+ this.filterable = opts.filterable ?? false;
23
+ }
16
24
  /** Constraint validation on an already-typed value. */
17
25
  check(_value) {
18
26
  return [];
@@ -69,9 +77,7 @@ var BooleanField = class extends Field {
69
77
  shopifyType = "boolean";
70
78
  constructor(opts) {
71
79
  super();
72
- this.required = opts.required ?? false;
73
- this.name = opts.name;
74
- this.description = opts.description;
80
+ this.applyCommon(opts);
75
81
  }
76
82
  validations() {
77
83
  return [];
@@ -97,9 +103,7 @@ var ListField = class extends Field {
97
103
  this.inner = inner;
98
104
  this.o = o;
99
105
  this.shopifyType = `list.${inner.shopifyType}`;
100
- this.required = o.required ?? false;
101
- this.name = o.name;
102
- this.description = o.description;
106
+ this.applyCommon(o);
103
107
  }
104
108
  inner;
105
109
  o;
@@ -135,9 +139,7 @@ var MeasurementField = class extends Field {
135
139
  constructor(opts, shopifyType) {
136
140
  super();
137
141
  this.shopifyType = shopifyType;
138
- this.required = opts.required ?? false;
139
- this.name = opts.name;
140
- this.description = opts.description;
142
+ this.applyCommon(opts);
141
143
  }
142
144
  shopifyType;
143
145
  wireIsJson = true;
@@ -173,9 +175,7 @@ var MoneyField = class extends Field {
173
175
  wireIsJson = true;
174
176
  constructor(opts) {
175
177
  super();
176
- this.required = opts.required ?? false;
177
- this.name = opts.name;
178
- this.description = opts.description;
178
+ this.applyCommon(opts);
179
179
  }
180
180
  validations() {
181
181
  return [];
@@ -201,9 +201,7 @@ var NumericField = class extends Field {
201
201
  constructor(opts) {
202
202
  super();
203
203
  this.opts = opts;
204
- this.required = opts.required ?? false;
205
- this.name = opts.name;
206
- this.description = opts.description;
204
+ this.applyCommon(opts);
207
205
  }
208
206
  opts;
209
207
  toJson(value) {
@@ -268,9 +266,7 @@ var RatingField = class extends Field {
268
266
  constructor(o) {
269
267
  super();
270
268
  this.o = o;
271
- this.required = o.required ?? false;
272
- this.name = o.name;
273
- this.description = o.description;
269
+ this.applyCommon(o);
274
270
  }
275
271
  o;
276
272
  shopifyType = "rating";
@@ -325,9 +321,7 @@ function rating(opts) {
325
321
  var GidField = class extends Field {
326
322
  constructor(opts) {
327
323
  super();
328
- this.required = opts.required ?? false;
329
- this.name = opts.name;
330
- this.description = opts.description;
324
+ this.applyCommon(opts);
331
325
  }
332
326
  toJson(value) {
333
327
  return value;
@@ -395,9 +389,7 @@ function ref(target, opts = {}) {
395
389
  var StringScalarField = class extends Field {
396
390
  constructor(opts) {
397
391
  super();
398
- this.required = opts.required ?? false;
399
- this.name = opts.name;
400
- this.description = opts.description;
392
+ this.applyCommon(opts);
401
393
  }
402
394
  toJson(value) {
403
395
  return value;
@@ -447,9 +439,7 @@ var JsonField = class extends Field {
447
439
  wireIsJson = true;
448
440
  constructor(opts) {
449
441
  super();
450
- this.required = opts.required ?? false;
451
- this.name = opts.name;
452
- this.description = opts.description;
442
+ this.applyCommon(opts);
453
443
  }
454
444
  validations() {
455
445
  return [];
@@ -483,9 +473,7 @@ var TextField = class extends Field {
483
473
  super();
484
474
  this.opts = opts;
485
475
  this.shopifyType = multiline ? "multi_line_text_field" : "single_line_text_field";
486
- this.required = opts.required ?? false;
487
- this.name = opts.name;
488
- this.description = opts.description;
476
+ this.applyCommon(opts);
489
477
  }
490
478
  opts;
491
479
  shopifyType;
@@ -553,16 +541,44 @@ function mapAccess(access) {
553
541
  const out = {};
554
542
  if (access.admin) out.admin = access.admin.toUpperCase();
555
543
  if (access.storefront) out.storefront = access.storefront.toUpperCase();
544
+ if (access.customerAccount) out.customerAccount = access.customerAccount.toUpperCase();
556
545
  return out;
557
546
  }
558
547
  function mapCapabilities(caps) {
559
548
  if (!caps) return void 0;
560
549
  const out = {};
561
- for (const [k, v2] of Object.entries(caps)) if (v2 != null) out[k] = { enabled: v2 };
550
+ if (caps.publishable != null) out.publishable = { enabled: caps.publishable };
551
+ if (caps.translatable != null) out.translatable = { enabled: caps.translatable };
552
+ if (caps.renderable != null) {
553
+ if (typeof caps.renderable === "boolean") {
554
+ out.renderable = { enabled: caps.renderable };
555
+ } else {
556
+ const data = {};
557
+ if (caps.renderable.metaTitleKey != null) data.metaTitleKey = caps.renderable.metaTitleKey;
558
+ if (caps.renderable.metaDescriptionKey != null) data.metaDescriptionKey = caps.renderable.metaDescriptionKey;
559
+ out.renderable = Object.keys(data).length ? { enabled: true, data } : { enabled: true };
560
+ }
561
+ }
562
+ if (caps.onlineStore != null) {
563
+ const data = { urlHandle: caps.onlineStore.urlHandle };
564
+ if (caps.onlineStore.createRedirects != null) data.createRedirects = caps.onlineStore.createRedirects;
565
+ out.onlineStore = { enabled: true, data };
566
+ }
562
567
  return Object.keys(out).length ? out : void 0;
563
568
  }
569
+ function validateSeoKeys(caps, fieldKeys, name) {
570
+ const r = caps?.renderable;
571
+ if (!r || typeof r === "boolean") return;
572
+ for (const prop of ["metaTitleKey", "metaDescriptionKey"]) {
573
+ const key = r[prop];
574
+ if (key != null && !fieldKeys.has(key)) {
575
+ throw new Error(`renderable.${prop} "${key}" is not a declared field key on "${name}".`);
576
+ }
577
+ }
578
+ }
564
579
  function toDefinitionInput(schema) {
565
580
  const { config } = schema;
581
+ validateSeoKeys(config.capabilities, new Set(Object.keys(schema.fields)), config.name);
566
582
  const fieldDefinitions = Object.entries(schema.fields).map(([key, field]) => {
567
583
  const def = {
568
584
  key,
@@ -572,6 +588,7 @@ function toDefinitionInput(schema) {
572
588
  validations: field.validations()
573
589
  };
574
590
  if (field.description != null) def.description = field.description;
591
+ if (field.filterable) def.capabilities = { adminFilterable: { enabled: true } };
575
592
  return def;
576
593
  });
577
594
  const out = {
@@ -644,6 +661,12 @@ function defineMetaobject(handle, config) {
644
661
 
645
662
  // src/codegen.ts
646
663
  var APP_PREFIX = "$app:";
664
+ function isMerchant(type) {
665
+ return !type.startsWith(APP_PREFIX);
666
+ }
667
+ function filterableEntry(field) {
668
+ return field.filterable ? ["filterable: true"] : [];
669
+ }
647
670
  var SIMPLE = {
648
671
  single_line_text_field: "text",
649
672
  multi_line_text_field: "multilineText",
@@ -725,8 +748,8 @@ function scalarEntries(field, warnings, builder) {
725
748
  jsonArr("file_type_options", "accept");
726
749
  return e;
727
750
  }
728
- function scalarCall(builder, field, warnings) {
729
- const lit = optsLiteral(scalarEntries(field, warnings, builder));
751
+ function scalarCall(builder, field, warnings, extra = []) {
752
+ const lit = optsLiteral([...scalarEntries(field, warnings, builder), ...extra]);
730
753
  return lit ? `m.${builder}(${lit})` : `m.${builder}()`;
731
754
  }
732
755
  function fieldCall(field, typeToIdent, warnings) {
@@ -736,6 +759,7 @@ function fieldCall(field, typeToIdent, warnings) {
736
759
  const max = v(field.validations, "max");
737
760
  const e = [`min: ${Number(min ?? 1)}`, `max: ${Number(max ?? 5)}`];
738
761
  if (field.required) e.unshift("required: true");
762
+ e.push(...filterableEntry(field));
739
763
  if (min === void 0 || max === void 0) warnings.push(`rating field "${field.key}" missing min/max`);
740
764
  return `m.rating(${optsLiteral(e)})`;
741
765
  }
@@ -746,7 +770,11 @@ function fieldCall(field, typeToIdent, warnings) {
746
770
  warnings.push(`unresolved reference on field "${field.key}"`);
747
771
  return `m.json() /* TODO: unmapped reference */`;
748
772
  }
749
- return field.required ? `m.ref(() => ${ident}, { required: true })` : `m.ref(() => ${ident})`;
773
+ const refEntries = [];
774
+ if (field.required) refEntries.push("required: true");
775
+ refEntries.push(...filterableEntry(field));
776
+ const opts = optsLiteral(refEntries);
777
+ return opts ? `m.ref(() => ${ident}, ${opts})` : `m.ref(() => ${ident})`;
750
778
  }
751
779
  if (type.startsWith("list.")) {
752
780
  const inner = type.slice("list.".length);
@@ -756,6 +784,7 @@ function fieldCall(field, typeToIdent, warnings) {
756
784
  const max = v(field.validations, "list.max");
757
785
  if (min !== void 0) listEntries.push(`min: ${Number(min)}`);
758
786
  if (max !== void 0) listEntries.push(`max: ${Number(max)}`);
787
+ listEntries.push(...filterableEntry(field));
759
788
  const listOpts = optsLiteral(listEntries);
760
789
  let innerCall;
761
790
  if (inner === "metaobject_reference") {
@@ -774,17 +803,53 @@ function fieldCall(field, typeToIdent, warnings) {
774
803
  }
775
804
  return listOpts ? `m.list(${innerCall}, ${listOpts})` : `m.list(${innerCall})`;
776
805
  }
777
- if (SIMPLE[type]) return scalarCall(SIMPLE[type], field, warnings);
806
+ if (SIMPLE[type]) return scalarCall(SIMPLE[type], field, warnings, filterableEntry(field));
778
807
  warnings.push(`unmapped field type "${type}" on field "${field.key}"`);
779
808
  return `m.json() /* TODO: unmapped type ${type} */`;
780
809
  }
810
+ function accessSource(access) {
811
+ if (!access) return "";
812
+ const parts = [];
813
+ if (access.admin === "MERCHANT_READ_WRITE") parts.push(`admin: "merchant_read_write"`);
814
+ if (access.storefront === "PUBLIC_READ") parts.push(`storefront: "public_read"`);
815
+ if (access.customerAccount === "READ") parts.push(`customerAccount: "read"`);
816
+ return parts.length ? `{ ${parts.join(", ")} }` : "";
817
+ }
818
+ function capabilitiesSource(caps) {
819
+ if (!caps) return "";
820
+ const parts = [];
821
+ if (caps.publishable?.enabled) parts.push(`publishable: true`);
822
+ if (caps.translatable?.enabled) parts.push(`translatable: true`);
823
+ if (caps.renderable?.enabled) {
824
+ const d = caps.renderable.data;
825
+ const dparts = [];
826
+ if (d?.metaTitleKey != null) dparts.push(`metaTitleKey: ${JSON.stringify(d.metaTitleKey)}`);
827
+ if (d?.metaDescriptionKey != null) dparts.push(`metaDescriptionKey: ${JSON.stringify(d.metaDescriptionKey)}`);
828
+ parts.push(dparts.length ? `renderable: { ${dparts.join(", ")} }` : `renderable: true`);
829
+ }
830
+ if (caps.onlineStore?.enabled && caps.onlineStore.data?.urlHandle != null) {
831
+ parts.push(`onlineStore: { urlHandle: ${JSON.stringify(caps.onlineStore.data.urlHandle)} }`);
832
+ }
833
+ return parts.length ? `{ ${parts.join(", ")} }` : "";
834
+ }
835
+ function defConfigLines(def) {
836
+ const lines = [];
837
+ if (isMerchant(def.type)) lines.push(` scope: "merchant",`);
838
+ if (def.name) lines.push(` name: ${JSON.stringify(def.name)},`);
839
+ if (def.description != null) lines.push(` description: ${JSON.stringify(def.description)},`);
840
+ if (def.displayNameKey != null) lines.push(` displayName: ${JSON.stringify(def.displayNameKey)},`);
841
+ const access = accessSource(def.access);
842
+ if (access) lines.push(` access: ${access},`);
843
+ const caps = capabilitiesSource(def.capabilities);
844
+ if (caps) lines.push(` capabilities: ${caps},`);
845
+ return lines.length ? `
846
+ ${lines.join("\n")}` : "";
847
+ }
781
848
  function defSource(def, typeToIdent, warnings) {
782
849
  const ident = typeToIdent.get(def.type);
783
850
  const handle = handleOf(def.type);
784
851
  const fields = def.fields.map((f) => ` ${f.key}: ${fieldCall(f, typeToIdent, warnings)},`).join("\n");
785
- const name = def.name ? `
786
- name: ${JSON.stringify(def.name)},` : "";
787
- return `export const ${ident} = defineMetaobject(${JSON.stringify(handle)}, {${name}
852
+ return `export const ${ident} = defineMetaobject(${JSON.stringify(handle)}, {${defConfigLines(def)}
788
853
  fields: {
789
854
  ${fields}
790
855
  },
@@ -844,6 +909,42 @@ function sameValidations(a, b) {
844
909
  const norm = (v2) => JSON.stringify([...v2].sort((x, y) => x.name.localeCompare(y.name)));
845
910
  return norm(a) === norm(b);
846
911
  }
912
+ var CAP_KEYS = ["publishable", "translatable", "renderable", "onlineStore"];
913
+ function accessChanged(local, remote) {
914
+ for (const key of ["admin", "storefront", "customerAccount"]) {
915
+ const lv = local[key];
916
+ if (lv != null && remote?.[key] !== lv) return true;
917
+ }
918
+ return false;
919
+ }
920
+ function capabilitiesChanged(local, remote) {
921
+ for (const key of CAP_KEYS) {
922
+ const lc = local[key];
923
+ if (!lc) continue;
924
+ const rc = remote?.[key];
925
+ if ((rc?.enabled ?? false) !== lc.enabled) return true;
926
+ const ldata = lc.data;
927
+ if (ldata) {
928
+ const rdata = rc?.data;
929
+ for (const [k, v2] of Object.entries(ldata)) {
930
+ if (v2 != null && rdata?.[k] !== v2) return true;
931
+ }
932
+ }
933
+ }
934
+ return false;
935
+ }
936
+ function disablesOnlineStore(local, remote) {
937
+ return local.onlineStore?.enabled === false && remote?.onlineStore?.enabled === true;
938
+ }
939
+ function definitionChanges(local, remote) {
940
+ const changes = [];
941
+ if (local.name != null && local.name !== remote.name) changes.push("name");
942
+ if (local.description != null && local.description !== remote.description) changes.push("description");
943
+ if (local.displayNameKey != null && local.displayNameKey !== remote.displayNameKey) changes.push("displayNameKey");
944
+ if (local.access && accessChanged(local.access, remote.access)) changes.push("access");
945
+ if (local.capabilities && capabilitiesChanged(local.capabilities, remote.capabilities)) changes.push("capabilities");
946
+ return changes;
947
+ }
847
948
  function diff(local, remote) {
848
949
  const ops = [];
849
950
  const remoteByType = new Map(remote.map((d) => [d.type, d]));
@@ -867,6 +968,7 @@ function diff(local, remote) {
867
968
  }
868
969
  const changes = {};
869
970
  if (rf.required !== lf.required) changes.required = lf.required;
971
+ if (rf.filterable !== lf.filterable) changes.filterable = lf.filterable;
870
972
  if (!sameValidations(rf.validations, lf.validations)) changes.validations = lf.validations;
871
973
  if (Object.keys(changes).length) {
872
974
  ops.push({ kind: "updateField", type: localDef.type, key: lf.key, changes });
@@ -877,49 +979,179 @@ function diff(local, remote) {
877
979
  ops.push({ kind: "removeField", type: localDef.type, key: rf.key, destructive: true });
878
980
  }
879
981
  }
982
+ const metaChanges = definitionChanges(localDef, remoteDef);
983
+ if (metaChanges.length) {
984
+ const destructive = localDef.capabilities ? disablesOnlineStore(localDef.capabilities, remoteDef.capabilities) : false;
985
+ ops.push({
986
+ kind: "updateDefinition",
987
+ type: localDef.type,
988
+ changes: metaChanges,
989
+ ...destructive ? { destructive: true } : {}
990
+ });
991
+ }
880
992
  }
881
993
  return ops;
882
994
  }
883
995
 
884
996
  // src/sync/normalize.ts
885
- function normalizeLocal(schema) {
886
- const def = schema.toDefinitionInput();
887
- return {
997
+ function localCapabilities(caps) {
998
+ const out = {};
999
+ if (caps?.publishable) out.publishable = { enabled: caps.publishable.enabled };
1000
+ if (caps?.translatable) out.translatable = { enabled: caps.translatable.enabled };
1001
+ if (caps?.renderable) {
1002
+ out.renderable = { enabled: caps.renderable.enabled };
1003
+ if (caps.renderable.data) out.renderable.data = { ...caps.renderable.data };
1004
+ }
1005
+ out.onlineStore = caps?.onlineStore ? { enabled: caps.onlineStore.enabled, data: { urlHandle: caps.onlineStore.data?.urlHandle } } : { enabled: false };
1006
+ return out;
1007
+ }
1008
+ function normalizeDefinition(def) {
1009
+ const out = {
888
1010
  type: def.type,
889
1011
  name: def.name,
1012
+ capabilities: localCapabilities(def.capabilities),
890
1013
  fields: def.fieldDefinitions.map((f) => ({
891
1014
  key: f.key,
892
1015
  type: f.type,
893
1016
  required: f.required,
1017
+ filterable: f.capabilities?.adminFilterable?.enabled ?? false,
894
1018
  validations: f.validations
895
1019
  }))
896
1020
  };
1021
+ if (def.description != null) out.description = def.description;
1022
+ if (def.displayNameKey != null) out.displayNameKey = def.displayNameKey;
1023
+ if (def.access) out.access = { ...def.access };
1024
+ return out;
1025
+ }
1026
+ function normalizeLocal(schema) {
1027
+ return normalizeDefinition(schema.toDefinitionInput());
1028
+ }
1029
+ function remoteAccess(access) {
1030
+ if (!access) return void 0;
1031
+ const out = {};
1032
+ if (access.admin != null) out.admin = access.admin;
1033
+ if (access.storefront != null) out.storefront = access.storefront;
1034
+ if (access.customerAccount != null) out.customerAccount = access.customerAccount;
1035
+ return out;
1036
+ }
1037
+ function remoteCapabilities(caps) {
1038
+ const out = {};
1039
+ if (!caps) return out;
1040
+ if (caps.publishable) out.publishable = { enabled: !!caps.publishable.enabled };
1041
+ if (caps.translatable) out.translatable = { enabled: !!caps.translatable.enabled };
1042
+ if (caps.renderable) {
1043
+ out.renderable = { enabled: !!caps.renderable.enabled };
1044
+ const d = caps.renderable.data;
1045
+ if (d) {
1046
+ const data = {};
1047
+ if (d.metaTitleKey != null) data.metaTitleKey = d.metaTitleKey;
1048
+ if (d.metaDescriptionKey != null) data.metaDescriptionKey = d.metaDescriptionKey;
1049
+ if (Object.keys(data).length) out.renderable.data = data;
1050
+ }
1051
+ }
1052
+ if (caps.onlineStore) {
1053
+ out.onlineStore = { enabled: !!caps.onlineStore.enabled };
1054
+ if (caps.onlineStore.data?.urlHandle != null) out.onlineStore.data = { urlHandle: caps.onlineStore.data.urlHandle };
1055
+ }
1056
+ return out;
897
1057
  }
898
1058
  function normalizeRemote(def) {
899
- return {
1059
+ const out = {
900
1060
  type: def.type,
901
1061
  name: def.name,
1062
+ capabilities: remoteCapabilities(def.capabilities),
902
1063
  fields: def.fieldDefinitions.map((f) => ({
903
1064
  key: f.key,
904
1065
  type: typeof f.type === "string" ? f.type : f.type.name,
905
1066
  required: f.required,
1067
+ filterable: f.capabilities?.adminFilterable?.enabled ?? false,
906
1068
  validations: f.validations ?? []
907
1069
  }))
908
1070
  };
1071
+ if (def.description != null) out.description = def.description;
1072
+ if (def.displayNameKey != null) out.displayNameKey = def.displayNameKey;
1073
+ const access = remoteAccess(def.access);
1074
+ if (access) out.access = access;
1075
+ return out;
1076
+ }
1077
+
1078
+ // src/sync/resolve.ts
1079
+ var APP_PREFIX2 = "$app:";
1080
+ function effectiveScope(schema, config) {
1081
+ return schema.config.scope ?? config.scope ?? "app";
1082
+ }
1083
+ function effectiveType(handle, scope) {
1084
+ return scope === "merchant" ? handle : `${APP_PREFIX2}${handle}`;
1085
+ }
1086
+ function rewriteReference(v2, effByCanonical) {
1087
+ if (v2.name === "metaobject_definition_type") {
1088
+ const mapped = effByCanonical.get(v2.value);
1089
+ return mapped ? { ...v2, value: mapped } : v2;
1090
+ }
1091
+ if (v2.name === "metaobject_definition_types") {
1092
+ try {
1093
+ const parsed = JSON.parse(v2.value);
1094
+ if (Array.isArray(parsed)) {
1095
+ const rewritten = parsed.map((t) => typeof t === "string" ? effByCanonical.get(t) ?? t : t);
1096
+ return { ...v2, value: JSON.stringify(rewritten) };
1097
+ }
1098
+ } catch {
1099
+ }
1100
+ }
1101
+ return v2;
1102
+ }
1103
+ function resolveAdmin(out, handle, scope, config) {
1104
+ const explicitAdmin = out.access?.admin;
1105
+ if (scope === "merchant") {
1106
+ if (explicitAdmin != null) {
1107
+ throw new Error(
1108
+ `"${handle}" is merchant-scoped but sets access.admin; admin access is only valid on app-scoped metaobjects.`
1109
+ );
1110
+ }
1111
+ return;
1112
+ }
1113
+ if (explicitAdmin == null) {
1114
+ const admin = config.merchantEditable ? "MERCHANT_READ_WRITE" : "MERCHANT_READ";
1115
+ out.access = { ...out.access, admin };
1116
+ }
1117
+ }
1118
+ function resolveDefinitions(schemas, config = {}) {
1119
+ const effByCanonical = /* @__PURE__ */ new Map();
1120
+ for (const s of schemas) {
1121
+ effByCanonical.set(`${APP_PREFIX2}${s.handle}`, effectiveType(s.handle, effectiveScope(s, config)));
1122
+ }
1123
+ return schemas.map((s) => {
1124
+ const scope = effectiveScope(s, config);
1125
+ const base = s.toDefinitionInput();
1126
+ const fieldDefinitions = base.fieldDefinitions.map((f) => ({
1127
+ ...f,
1128
+ validations: f.validations.map((v2) => rewriteReference(v2, effByCanonical))
1129
+ }));
1130
+ const out = { ...base, type: effectiveType(s.handle, scope), fieldDefinitions };
1131
+ resolveAdmin(out, s.handle, scope, config);
1132
+ return out;
1133
+ });
909
1134
  }
910
1135
 
911
1136
  // src/sync/pull.ts
1137
+ function toDefinition(type, node) {
1138
+ return {
1139
+ type,
1140
+ name: node.name,
1141
+ description: node.description,
1142
+ displayNameKey: node.displayNameKey,
1143
+ access: node.access,
1144
+ capabilities: node.capabilities,
1145
+ fieldDefinitions: node.fieldDefinitions
1146
+ };
1147
+ }
912
1148
  async function pull(client, types) {
913
1149
  const out = [];
914
1150
  for (const type of types) {
915
1151
  const data = await execute(client, PULL_DEFINITION_QUERY, { type });
916
1152
  const node = data.metaobjectDefinitionByType;
917
1153
  if (!node) continue;
918
- out.push({
919
- id: node.id,
920
- type,
921
- definition: { type, name: node.name, fieldDefinitions: node.fieldDefinitions }
922
- });
1154
+ out.push({ id: node.id, type, definition: toDefinition(type, node) });
923
1155
  }
924
1156
  return out;
925
1157
  }
@@ -937,7 +1169,7 @@ async function pullAll(client, opts = {}) {
937
1169
  const canonical = toCanonicalType(node.type);
938
1170
  if (appOwnedOnly && !canonical) continue;
939
1171
  const type = canonical ?? node.type;
940
- out.push({ id: node.id, type, definition: { type, name: node.name, fieldDefinitions: node.fieldDefinitions } });
1172
+ out.push({ id: node.id, type, definition: toDefinition(type, node) });
941
1173
  }
942
1174
  after = data.metaobjectDefinitions.pageInfo.hasNextPage ? data.metaobjectDefinitions.pageInfo.endCursor : null;
943
1175
  } while (after !== null);
@@ -945,6 +1177,25 @@ async function pullAll(client, opts = {}) {
945
1177
  }
946
1178
 
947
1179
  // src/sync/push.ts
1180
+ function definitionUpdateFor(def, changes) {
1181
+ const out = {};
1182
+ for (const c of changes) {
1183
+ if (c === "name") out.name = def.name;
1184
+ else if (c === "description") out.description = def.description;
1185
+ else if (c === "displayNameKey") out.displayNameKey = def.displayNameKey;
1186
+ else if (c === "access") out.access = def.access;
1187
+ else if (c === "capabilities") {
1188
+ const caps = def.capabilities;
1189
+ const payload = {};
1190
+ if (caps?.publishable) payload.publishable = caps.publishable;
1191
+ if (caps?.translatable) payload.translatable = caps.translatable;
1192
+ if (caps?.renderable) payload.renderable = caps.renderable;
1193
+ payload.onlineStore = caps?.onlineStore ?? { enabled: false };
1194
+ out.capabilities = payload;
1195
+ }
1196
+ }
1197
+ return out;
1198
+ }
948
1199
  function fieldInputFor(defByType, type, key) {
949
1200
  return defByType.get(type)?.fieldDefinitions.find((f) => f.key === key);
950
1201
  }
@@ -1045,14 +1296,22 @@ async function push(client, plan, sources, options) {
1045
1296
  if (id2) idByType.set(op.type, id2);
1046
1297
  return { op, status: "applied", id: id2 };
1047
1298
  }
1048
- const destructive = op.kind === "removeField" || op.kind === "changeFieldType";
1299
+ const destructive = "destructive" in op && op.destructive === true;
1049
1300
  if (destructive && !allowDestructive) return { op, status: "skipped", reason: "destructive" };
1050
1301
  if (failedTypes.has(op.type)) return { op, status: "blocked", reason: `blocked: definition "${op.type}" was not created` };
1051
1302
  const id = idByType.get(op.type);
1052
1303
  if (id == null) return { op, status: "blocked", reason: `no definition id for "${op.type}"` };
1053
- const fieldDefinitions = fieldOpsFor(op);
1054
- if (!fieldDefinitions) return { op, status: "blocked", reason: `no field input for "${op.type}"` };
1055
- const data = await execute(client, UPDATE_DEFINITION_MUTATION, { id, definition: { fieldDefinitions } });
1304
+ let definition;
1305
+ if (op.kind === "updateDefinition") {
1306
+ const def = defByType.get(op.type);
1307
+ if (!def) return { op, status: "blocked", reason: `no definition input for "${op.type}"` };
1308
+ definition = definitionUpdateFor(def, op.changes);
1309
+ } else {
1310
+ const fieldDefinitions = fieldOpsFor(op);
1311
+ if (!fieldDefinitions) return { op, status: "blocked", reason: `no field input for "${op.type}"` };
1312
+ definition = { fieldDefinitions };
1313
+ }
1314
+ const data = await execute(client, UPDATE_DEFINITION_MUTATION, { id, definition });
1056
1315
  const payload = data.metaobjectDefinitionUpdate;
1057
1316
  if (payload.userErrors.length) return { op, status: "failed", userErrors: payload.userErrors };
1058
1317
  return { op, status: "applied", id: payload.metaobjectDefinition?.id ?? id };
@@ -1073,6 +1332,9 @@ async function push(client, plan, sources, options) {
1073
1332
  validations: field.validations
1074
1333
  };
1075
1334
  if (field.description != null) update.description = field.description;
1335
+ if ("filterable" in op.changes) {
1336
+ update.capabilities = { adminFilterable: { enabled: op.changes.filterable ?? false } };
1337
+ }
1076
1338
  return [{ update }];
1077
1339
  }
1078
1340
  case "removeField":
@@ -1099,10 +1361,12 @@ export {
1099
1361
  defineMetaobject,
1100
1362
  generateSchemaSource,
1101
1363
  diff,
1364
+ normalizeDefinition,
1102
1365
  normalizeLocal,
1103
1366
  normalizeRemote,
1367
+ resolveDefinitions,
1104
1368
  pull,
1105
1369
  pullAll,
1106
1370
  push
1107
1371
  };
1108
- //# sourceMappingURL=chunk-GH5DXHS5.js.map
1372
+ //# sourceMappingURL=chunk-ZTWFDJHN.js.map