@fmaplabs/meta-manifest 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -3
- package/dist/{chunk-PFU5VAO7.js → chunk-AUR2YQCW.js} +2 -2
- package/dist/{chunk-GH5DXHS5.js → chunk-OEJJXMYC.js} +461 -97
- package/dist/chunk-OEJJXMYC.js.map +1 -0
- package/dist/{chunk-3R6VQ3Z3.js → chunk-VSJUGUH7.js} +15 -3
- package/dist/chunk-VSJUGUH7.js.map +1 -0
- package/dist/cli/index.cjs +434 -75
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +35 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +475 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +180 -38
- package/dist/index.d.ts +180 -38
- package/dist/index.js +6 -2
- package/dist/node/client.cjs.map +1 -1
- package/dist/node/client.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-3R6VQ3Z3.js.map +0 -1
- package/dist/chunk-GH5DXHS5.js.map +0 -1
- /package/dist/{chunk-PFU5VAO7.js.map → chunk-AUR2YQCW.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -28,11 +28,13 @@ __export(src_exports, {
|
|
|
28
28
|
diff: () => diff,
|
|
29
29
|
generateSchemaSource: () => generateSchemaSource,
|
|
30
30
|
m: () => m,
|
|
31
|
+
normalizeDefinition: () => normalizeDefinition,
|
|
31
32
|
normalizeLocal: () => normalizeLocal,
|
|
32
33
|
normalizeRemote: () => normalizeRemote,
|
|
33
34
|
pull: () => pull,
|
|
34
35
|
pullAll: () => pullAll,
|
|
35
36
|
push: () => push,
|
|
37
|
+
resolveDefinitions: () => resolveDefinitions,
|
|
36
38
|
toDefinitionInput: () => toDefinitionInput,
|
|
37
39
|
validateConfig: () => validateConfig
|
|
38
40
|
});
|
|
@@ -60,6 +62,14 @@ var Field = class {
|
|
|
60
62
|
required = false;
|
|
61
63
|
name;
|
|
62
64
|
description;
|
|
65
|
+
filterable = false;
|
|
66
|
+
/** Apply the shared field options; call from each concrete constructor. */
|
|
67
|
+
applyCommon(opts) {
|
|
68
|
+
this.required = opts.required ?? false;
|
|
69
|
+
this.name = opts.name;
|
|
70
|
+
this.description = opts.description;
|
|
71
|
+
this.filterable = opts.filterable ?? false;
|
|
72
|
+
}
|
|
63
73
|
/** Constraint validation on an already-typed value. */
|
|
64
74
|
check(_value) {
|
|
65
75
|
return [];
|
|
@@ -116,9 +126,7 @@ var BooleanField = class extends Field {
|
|
|
116
126
|
shopifyType = "boolean";
|
|
117
127
|
constructor(opts) {
|
|
118
128
|
super();
|
|
119
|
-
this.
|
|
120
|
-
this.name = opts.name;
|
|
121
|
-
this.description = opts.description;
|
|
129
|
+
this.applyCommon(opts);
|
|
122
130
|
}
|
|
123
131
|
validations() {
|
|
124
132
|
return [];
|
|
@@ -144,9 +152,7 @@ var ListField = class extends Field {
|
|
|
144
152
|
this.inner = inner;
|
|
145
153
|
this.o = o;
|
|
146
154
|
this.shopifyType = `list.${inner.shopifyType}`;
|
|
147
|
-
this.
|
|
148
|
-
this.name = o.name;
|
|
149
|
-
this.description = o.description;
|
|
155
|
+
this.applyCommon(o);
|
|
150
156
|
}
|
|
151
157
|
inner;
|
|
152
158
|
o;
|
|
@@ -182,9 +188,7 @@ var MeasurementField = class extends Field {
|
|
|
182
188
|
constructor(opts, shopifyType) {
|
|
183
189
|
super();
|
|
184
190
|
this.shopifyType = shopifyType;
|
|
185
|
-
this.
|
|
186
|
-
this.name = opts.name;
|
|
187
|
-
this.description = opts.description;
|
|
191
|
+
this.applyCommon(opts);
|
|
188
192
|
}
|
|
189
193
|
shopifyType;
|
|
190
194
|
wireIsJson = true;
|
|
@@ -220,9 +224,7 @@ var MoneyField = class extends Field {
|
|
|
220
224
|
wireIsJson = true;
|
|
221
225
|
constructor(opts) {
|
|
222
226
|
super();
|
|
223
|
-
this.
|
|
224
|
-
this.name = opts.name;
|
|
225
|
-
this.description = opts.description;
|
|
227
|
+
this.applyCommon(opts);
|
|
226
228
|
}
|
|
227
229
|
validations() {
|
|
228
230
|
return [];
|
|
@@ -248,9 +250,7 @@ var NumericField = class extends Field {
|
|
|
248
250
|
constructor(opts) {
|
|
249
251
|
super();
|
|
250
252
|
this.opts = opts;
|
|
251
|
-
this.
|
|
252
|
-
this.name = opts.name;
|
|
253
|
-
this.description = opts.description;
|
|
253
|
+
this.applyCommon(opts);
|
|
254
254
|
}
|
|
255
255
|
opts;
|
|
256
256
|
toJson(value) {
|
|
@@ -315,9 +315,7 @@ var RatingField = class extends Field {
|
|
|
315
315
|
constructor(o) {
|
|
316
316
|
super();
|
|
317
317
|
this.o = o;
|
|
318
|
-
this.
|
|
319
|
-
this.name = o.name;
|
|
320
|
-
this.description = o.description;
|
|
318
|
+
this.applyCommon(o);
|
|
321
319
|
}
|
|
322
320
|
o;
|
|
323
321
|
shopifyType = "rating";
|
|
@@ -372,9 +370,7 @@ function rating(opts) {
|
|
|
372
370
|
var GidField = class extends Field {
|
|
373
371
|
constructor(opts) {
|
|
374
372
|
super();
|
|
375
|
-
this.
|
|
376
|
-
this.name = opts.name;
|
|
377
|
-
this.description = opts.description;
|
|
373
|
+
this.applyCommon(opts);
|
|
378
374
|
}
|
|
379
375
|
toJson(value) {
|
|
380
376
|
return value;
|
|
@@ -419,6 +415,17 @@ var MetaobjectRefField = class extends GidField {
|
|
|
419
415
|
return [{ name: "metaobject_definition_type", value: resolveType(this.target) }];
|
|
420
416
|
}
|
|
421
417
|
};
|
|
418
|
+
var MixedRefField = class extends GidField {
|
|
419
|
+
constructor(targets, opts) {
|
|
420
|
+
super(opts);
|
|
421
|
+
this.targets = targets;
|
|
422
|
+
}
|
|
423
|
+
targets;
|
|
424
|
+
shopifyType = "mixed_reference";
|
|
425
|
+
validations() {
|
|
426
|
+
return [{ name: "metaobject_definition_types", value: JSON.stringify(this.targets.map(resolveType)) }];
|
|
427
|
+
}
|
|
428
|
+
};
|
|
422
429
|
function product(opts = {}) {
|
|
423
430
|
return new SimpleRefField(opts, "product_reference");
|
|
424
431
|
}
|
|
@@ -437,14 +444,15 @@ function file(opts = {}) {
|
|
|
437
444
|
function ref(target, opts = {}) {
|
|
438
445
|
return new MetaobjectRefField(target, opts);
|
|
439
446
|
}
|
|
447
|
+
function mixedRef(targets, opts = {}) {
|
|
448
|
+
return new MixedRefField(targets, opts);
|
|
449
|
+
}
|
|
440
450
|
|
|
441
451
|
// src/fields/scalar.ts
|
|
442
452
|
var StringScalarField = class extends Field {
|
|
443
453
|
constructor(opts) {
|
|
444
454
|
super();
|
|
445
|
-
this.
|
|
446
|
-
this.name = opts.name;
|
|
447
|
-
this.description = opts.description;
|
|
455
|
+
this.applyCommon(opts);
|
|
448
456
|
}
|
|
449
457
|
toJson(value) {
|
|
450
458
|
return value;
|
|
@@ -494,9 +502,7 @@ var JsonField = class extends Field {
|
|
|
494
502
|
wireIsJson = true;
|
|
495
503
|
constructor(opts) {
|
|
496
504
|
super();
|
|
497
|
-
this.
|
|
498
|
-
this.name = opts.name;
|
|
499
|
-
this.description = opts.description;
|
|
505
|
+
this.applyCommon(opts);
|
|
500
506
|
}
|
|
501
507
|
validations() {
|
|
502
508
|
return [];
|
|
@@ -530,9 +536,7 @@ var TextField = class extends Field {
|
|
|
530
536
|
super();
|
|
531
537
|
this.opts = opts;
|
|
532
538
|
this.shopifyType = multiline ? "multi_line_text_field" : "single_line_text_field";
|
|
533
|
-
this.
|
|
534
|
-
this.name = opts.name;
|
|
535
|
-
this.description = opts.description;
|
|
539
|
+
this.applyCommon(opts);
|
|
536
540
|
}
|
|
537
541
|
opts;
|
|
538
542
|
shopifyType;
|
|
@@ -591,6 +595,7 @@ var m = {
|
|
|
591
595
|
page,
|
|
592
596
|
file,
|
|
593
597
|
ref,
|
|
598
|
+
mixedRef,
|
|
594
599
|
list
|
|
595
600
|
};
|
|
596
601
|
|
|
@@ -600,16 +605,44 @@ function mapAccess(access) {
|
|
|
600
605
|
const out = {};
|
|
601
606
|
if (access.admin) out.admin = access.admin.toUpperCase();
|
|
602
607
|
if (access.storefront) out.storefront = access.storefront.toUpperCase();
|
|
608
|
+
if (access.customerAccount) out.customerAccount = access.customerAccount.toUpperCase();
|
|
603
609
|
return out;
|
|
604
610
|
}
|
|
605
611
|
function mapCapabilities(caps) {
|
|
606
612
|
if (!caps) return void 0;
|
|
607
613
|
const out = {};
|
|
608
|
-
|
|
614
|
+
if (caps.publishable != null) out.publishable = { enabled: caps.publishable };
|
|
615
|
+
if (caps.translatable != null) out.translatable = { enabled: caps.translatable };
|
|
616
|
+
if (caps.renderable != null) {
|
|
617
|
+
if (typeof caps.renderable === "boolean") {
|
|
618
|
+
out.renderable = { enabled: caps.renderable };
|
|
619
|
+
} else {
|
|
620
|
+
const data = {};
|
|
621
|
+
if (caps.renderable.metaTitleKey != null) data.metaTitleKey = caps.renderable.metaTitleKey;
|
|
622
|
+
if (caps.renderable.metaDescriptionKey != null) data.metaDescriptionKey = caps.renderable.metaDescriptionKey;
|
|
623
|
+
out.renderable = Object.keys(data).length ? { enabled: true, data } : { enabled: true };
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
if (caps.onlineStore != null) {
|
|
627
|
+
const data = { urlHandle: caps.onlineStore.urlHandle };
|
|
628
|
+
if (caps.onlineStore.createRedirects != null) data.createRedirects = caps.onlineStore.createRedirects;
|
|
629
|
+
out.onlineStore = { enabled: true, data };
|
|
630
|
+
}
|
|
609
631
|
return Object.keys(out).length ? out : void 0;
|
|
610
632
|
}
|
|
633
|
+
function validateSeoKeys(caps, fieldKeys, name) {
|
|
634
|
+
const r = caps?.renderable;
|
|
635
|
+
if (!r || typeof r === "boolean") return;
|
|
636
|
+
for (const prop of ["metaTitleKey", "metaDescriptionKey"]) {
|
|
637
|
+
const key = r[prop];
|
|
638
|
+
if (key != null && !fieldKeys.has(key)) {
|
|
639
|
+
throw new Error(`renderable.${prop} "${key}" is not a declared field key on "${name}".`);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
611
643
|
function toDefinitionInput(schema) {
|
|
612
644
|
const { config } = schema;
|
|
645
|
+
validateSeoKeys(config.capabilities, new Set(Object.keys(schema.fields)), config.name);
|
|
613
646
|
const fieldDefinitions = Object.entries(schema.fields).map(([key, field]) => {
|
|
614
647
|
const def = {
|
|
615
648
|
key,
|
|
@@ -619,6 +652,7 @@ function toDefinitionInput(schema) {
|
|
|
619
652
|
validations: field.validations()
|
|
620
653
|
};
|
|
621
654
|
if (field.description != null) def.description = field.description;
|
|
655
|
+
if (field.filterable) def.capabilities = { adminFilterable: { enabled: true } };
|
|
622
656
|
return def;
|
|
623
657
|
});
|
|
624
658
|
const out = {
|
|
@@ -691,6 +725,12 @@ function defineMetaobject(handle, config) {
|
|
|
691
725
|
|
|
692
726
|
// src/codegen.ts
|
|
693
727
|
var APP_PREFIX = "$app:";
|
|
728
|
+
function isMerchant(type) {
|
|
729
|
+
return !type.startsWith(APP_PREFIX);
|
|
730
|
+
}
|
|
731
|
+
function filterableEntry(field) {
|
|
732
|
+
return field.filterable ? ["filterable: true"] : [];
|
|
733
|
+
}
|
|
694
734
|
var SIMPLE = {
|
|
695
735
|
single_line_text_field: "text",
|
|
696
736
|
multi_line_text_field: "multilineText",
|
|
@@ -734,6 +774,27 @@ function refTarget(field) {
|
|
|
734
774
|
}
|
|
735
775
|
return void 0;
|
|
736
776
|
}
|
|
777
|
+
function refTargets(field) {
|
|
778
|
+
const many = v(field.validations, "metaobject_definition_types");
|
|
779
|
+
if (many) {
|
|
780
|
+
try {
|
|
781
|
+
const arr = JSON.parse(many);
|
|
782
|
+
if (Array.isArray(arr)) return arr.map(String);
|
|
783
|
+
} catch {
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
const single = v(field.validations, "metaobject_definition_type");
|
|
787
|
+
return single ? [single] : [];
|
|
788
|
+
}
|
|
789
|
+
function mixedTargetsLiteral(field, typeToIdent, warnings) {
|
|
790
|
+
const targets = refTargets(field);
|
|
791
|
+
const idents = targets.map((t) => typeToIdent.get(t));
|
|
792
|
+
if (!targets.length || idents.some((i) => !i)) {
|
|
793
|
+
warnings.push(`unresolved mixed reference on field "${field.key}"`);
|
|
794
|
+
return void 0;
|
|
795
|
+
}
|
|
796
|
+
return `[${idents.map((i) => `() => ${i}`).join(", ")}]`;
|
|
797
|
+
}
|
|
737
798
|
function optsLiteral(entries) {
|
|
738
799
|
return entries.length ? `{ ${entries.join(", ")} }` : "";
|
|
739
800
|
}
|
|
@@ -772,8 +833,8 @@ function scalarEntries(field, warnings, builder) {
|
|
|
772
833
|
jsonArr("file_type_options", "accept");
|
|
773
834
|
return e;
|
|
774
835
|
}
|
|
775
|
-
function scalarCall(builder, field, warnings) {
|
|
776
|
-
const lit = optsLiteral(scalarEntries(field, warnings, builder));
|
|
836
|
+
function scalarCall(builder, field, warnings, extra = []) {
|
|
837
|
+
const lit = optsLiteral([...scalarEntries(field, warnings, builder), ...extra]);
|
|
777
838
|
return lit ? `m.${builder}(${lit})` : `m.${builder}()`;
|
|
778
839
|
}
|
|
779
840
|
function fieldCall(field, typeToIdent, warnings) {
|
|
@@ -783,6 +844,7 @@ function fieldCall(field, typeToIdent, warnings) {
|
|
|
783
844
|
const max = v(field.validations, "max");
|
|
784
845
|
const e = [`min: ${Number(min ?? 1)}`, `max: ${Number(max ?? 5)}`];
|
|
785
846
|
if (field.required) e.unshift("required: true");
|
|
847
|
+
e.push(...filterableEntry(field));
|
|
786
848
|
if (min === void 0 || max === void 0) warnings.push(`rating field "${field.key}" missing min/max`);
|
|
787
849
|
return `m.rating(${optsLiteral(e)})`;
|
|
788
850
|
}
|
|
@@ -793,7 +855,20 @@ function fieldCall(field, typeToIdent, warnings) {
|
|
|
793
855
|
warnings.push(`unresolved reference on field "${field.key}"`);
|
|
794
856
|
return `m.json() /* TODO: unmapped reference */`;
|
|
795
857
|
}
|
|
796
|
-
|
|
858
|
+
const refEntries = [];
|
|
859
|
+
if (field.required) refEntries.push("required: true");
|
|
860
|
+
refEntries.push(...filterableEntry(field));
|
|
861
|
+
const opts = optsLiteral(refEntries);
|
|
862
|
+
return opts ? `m.ref(() => ${ident}, ${opts})` : `m.ref(() => ${ident})`;
|
|
863
|
+
}
|
|
864
|
+
if (type === "mixed_reference") {
|
|
865
|
+
const arr = mixedTargetsLiteral(field, typeToIdent, warnings);
|
|
866
|
+
if (!arr) return `m.json() /* TODO: unmapped mixed reference */`;
|
|
867
|
+
const refEntries = [];
|
|
868
|
+
if (field.required) refEntries.push("required: true");
|
|
869
|
+
refEntries.push(...filterableEntry(field));
|
|
870
|
+
const opts = optsLiteral(refEntries);
|
|
871
|
+
return opts ? `m.mixedRef(${arr}, ${opts})` : `m.mixedRef(${arr})`;
|
|
797
872
|
}
|
|
798
873
|
if (type.startsWith("list.")) {
|
|
799
874
|
const inner = type.slice("list.".length);
|
|
@@ -803,6 +878,7 @@ function fieldCall(field, typeToIdent, warnings) {
|
|
|
803
878
|
const max = v(field.validations, "list.max");
|
|
804
879
|
if (min !== void 0) listEntries.push(`min: ${Number(min)}`);
|
|
805
880
|
if (max !== void 0) listEntries.push(`max: ${Number(max)}`);
|
|
881
|
+
listEntries.push(...filterableEntry(field));
|
|
806
882
|
const listOpts = optsLiteral(listEntries);
|
|
807
883
|
let innerCall;
|
|
808
884
|
if (inner === "metaobject_reference") {
|
|
@@ -813,6 +889,10 @@ function fieldCall(field, typeToIdent, warnings) {
|
|
|
813
889
|
return `m.json() /* TODO: unmapped list reference */`;
|
|
814
890
|
}
|
|
815
891
|
innerCall = `m.ref(() => ${ident})`;
|
|
892
|
+
} else if (inner === "mixed_reference") {
|
|
893
|
+
const arr = mixedTargetsLiteral(field, typeToIdent, warnings);
|
|
894
|
+
if (!arr) return `m.json() /* TODO: unmapped list mixed reference */`;
|
|
895
|
+
innerCall = `m.mixedRef(${arr})`;
|
|
816
896
|
} else if (SIMPLE[inner]) {
|
|
817
897
|
innerCall = scalarCall(SIMPLE[inner], { ...field, required: false }, warnings);
|
|
818
898
|
} else {
|
|
@@ -821,17 +901,53 @@ function fieldCall(field, typeToIdent, warnings) {
|
|
|
821
901
|
}
|
|
822
902
|
return listOpts ? `m.list(${innerCall}, ${listOpts})` : `m.list(${innerCall})`;
|
|
823
903
|
}
|
|
824
|
-
if (SIMPLE[type]) return scalarCall(SIMPLE[type], field, warnings);
|
|
904
|
+
if (SIMPLE[type]) return scalarCall(SIMPLE[type], field, warnings, filterableEntry(field));
|
|
825
905
|
warnings.push(`unmapped field type "${type}" on field "${field.key}"`);
|
|
826
906
|
return `m.json() /* TODO: unmapped type ${type} */`;
|
|
827
907
|
}
|
|
908
|
+
function accessSource(access) {
|
|
909
|
+
if (!access) return "";
|
|
910
|
+
const parts = [];
|
|
911
|
+
if (access.admin === "MERCHANT_READ_WRITE") parts.push(`admin: "merchant_read_write"`);
|
|
912
|
+
if (access.storefront === "PUBLIC_READ") parts.push(`storefront: "public_read"`);
|
|
913
|
+
if (access.customerAccount === "READ") parts.push(`customerAccount: "read"`);
|
|
914
|
+
return parts.length ? `{ ${parts.join(", ")} }` : "";
|
|
915
|
+
}
|
|
916
|
+
function capabilitiesSource(caps) {
|
|
917
|
+
if (!caps) return "";
|
|
918
|
+
const parts = [];
|
|
919
|
+
if (caps.publishable?.enabled) parts.push(`publishable: true`);
|
|
920
|
+
if (caps.translatable?.enabled) parts.push(`translatable: true`);
|
|
921
|
+
if (caps.renderable?.enabled) {
|
|
922
|
+
const d = caps.renderable.data;
|
|
923
|
+
const dparts = [];
|
|
924
|
+
if (d?.metaTitleKey != null) dparts.push(`metaTitleKey: ${JSON.stringify(d.metaTitleKey)}`);
|
|
925
|
+
if (d?.metaDescriptionKey != null) dparts.push(`metaDescriptionKey: ${JSON.stringify(d.metaDescriptionKey)}`);
|
|
926
|
+
parts.push(dparts.length ? `renderable: { ${dparts.join(", ")} }` : `renderable: true`);
|
|
927
|
+
}
|
|
928
|
+
if (caps.onlineStore?.enabled && caps.onlineStore.data?.urlHandle != null) {
|
|
929
|
+
parts.push(`onlineStore: { urlHandle: ${JSON.stringify(caps.onlineStore.data.urlHandle)} }`);
|
|
930
|
+
}
|
|
931
|
+
return parts.length ? `{ ${parts.join(", ")} }` : "";
|
|
932
|
+
}
|
|
933
|
+
function defConfigLines(def) {
|
|
934
|
+
const lines = [];
|
|
935
|
+
if (isMerchant(def.type)) lines.push(` scope: "merchant",`);
|
|
936
|
+
if (def.name) lines.push(` name: ${JSON.stringify(def.name)},`);
|
|
937
|
+
if (def.description != null) lines.push(` description: ${JSON.stringify(def.description)},`);
|
|
938
|
+
if (def.displayNameKey != null) lines.push(` displayName: ${JSON.stringify(def.displayNameKey)},`);
|
|
939
|
+
const access = accessSource(def.access);
|
|
940
|
+
if (access) lines.push(` access: ${access},`);
|
|
941
|
+
const caps = capabilitiesSource(def.capabilities);
|
|
942
|
+
if (caps) lines.push(` capabilities: ${caps},`);
|
|
943
|
+
return lines.length ? `
|
|
944
|
+
${lines.join("\n")}` : "";
|
|
945
|
+
}
|
|
828
946
|
function defSource(def, typeToIdent, warnings) {
|
|
829
947
|
const ident = typeToIdent.get(def.type);
|
|
830
948
|
const handle = handleOf(def.type);
|
|
831
949
|
const fields = def.fields.map((f) => ` ${f.key}: ${fieldCall(f, typeToIdent, warnings)},`).join("\n");
|
|
832
|
-
const
|
|
833
|
-
name: ${JSON.stringify(def.name)},` : "";
|
|
834
|
-
return `export const ${ident} = defineMetaobject(${JSON.stringify(handle)}, {${name}
|
|
950
|
+
return `export const ${ident} = defineMetaobject(${JSON.stringify(handle)}, {${defConfigLines(def)}
|
|
835
951
|
fields: {
|
|
836
952
|
${fields}
|
|
837
953
|
},
|
|
@@ -843,6 +959,8 @@ function referencedTypes(def) {
|
|
|
843
959
|
if (f.type === "metaobject_reference" || f.type === "list.metaobject_reference") {
|
|
844
960
|
const t = refTarget(f);
|
|
845
961
|
if (t) out.add(t);
|
|
962
|
+
} else if (f.type === "mixed_reference" || f.type === "list.mixed_reference") {
|
|
963
|
+
for (const t of refTargets(f)) out.add(t);
|
|
846
964
|
}
|
|
847
965
|
}
|
|
848
966
|
return out;
|
|
@@ -891,6 +1009,42 @@ function sameValidations(a, b) {
|
|
|
891
1009
|
const norm = (v2) => JSON.stringify([...v2].sort((x, y) => x.name.localeCompare(y.name)));
|
|
892
1010
|
return norm(a) === norm(b);
|
|
893
1011
|
}
|
|
1012
|
+
var CAP_KEYS = ["publishable", "translatable", "renderable", "onlineStore"];
|
|
1013
|
+
function accessChanged(local, remote) {
|
|
1014
|
+
for (const key of ["admin", "storefront", "customerAccount"]) {
|
|
1015
|
+
const lv = local[key];
|
|
1016
|
+
if (lv != null && remote?.[key] !== lv) return true;
|
|
1017
|
+
}
|
|
1018
|
+
return false;
|
|
1019
|
+
}
|
|
1020
|
+
function capabilitiesChanged(local, remote) {
|
|
1021
|
+
for (const key of CAP_KEYS) {
|
|
1022
|
+
const lc = local[key];
|
|
1023
|
+
if (!lc) continue;
|
|
1024
|
+
const rc = remote?.[key];
|
|
1025
|
+
if ((rc?.enabled ?? false) !== lc.enabled) return true;
|
|
1026
|
+
const ldata = lc.data;
|
|
1027
|
+
if (ldata) {
|
|
1028
|
+
const rdata = rc?.data;
|
|
1029
|
+
for (const [k, v2] of Object.entries(ldata)) {
|
|
1030
|
+
if (v2 != null && rdata?.[k] !== v2) return true;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
return false;
|
|
1035
|
+
}
|
|
1036
|
+
function disablesOnlineStore(local, remote) {
|
|
1037
|
+
return local.onlineStore?.enabled === false && remote?.onlineStore?.enabled === true;
|
|
1038
|
+
}
|
|
1039
|
+
function definitionChanges(local, remote) {
|
|
1040
|
+
const changes = [];
|
|
1041
|
+
if (local.name != null && local.name !== remote.name) changes.push("name");
|
|
1042
|
+
if (local.description != null && local.description !== remote.description) changes.push("description");
|
|
1043
|
+
if (local.displayNameKey != null && local.displayNameKey !== remote.displayNameKey) changes.push("displayNameKey");
|
|
1044
|
+
if (local.access && accessChanged(local.access, remote.access)) changes.push("access");
|
|
1045
|
+
if (local.capabilities && capabilitiesChanged(local.capabilities, remote.capabilities)) changes.push("capabilities");
|
|
1046
|
+
return changes;
|
|
1047
|
+
}
|
|
894
1048
|
function diff(local, remote) {
|
|
895
1049
|
const ops = [];
|
|
896
1050
|
const remoteByType = new Map(remote.map((d) => [d.type, d]));
|
|
@@ -914,6 +1068,7 @@ function diff(local, remote) {
|
|
|
914
1068
|
}
|
|
915
1069
|
const changes = {};
|
|
916
1070
|
if (rf.required !== lf.required) changes.required = lf.required;
|
|
1071
|
+
if (rf.filterable !== lf.filterable) changes.filterable = lf.filterable;
|
|
917
1072
|
if (!sameValidations(rf.validations, lf.validations)) changes.validations = lf.validations;
|
|
918
1073
|
if (Object.keys(changes).length) {
|
|
919
1074
|
ops.push({ kind: "updateField", type: localDef.type, key: lf.key, changes });
|
|
@@ -924,35 +1079,158 @@ function diff(local, remote) {
|
|
|
924
1079
|
ops.push({ kind: "removeField", type: localDef.type, key: rf.key, destructive: true });
|
|
925
1080
|
}
|
|
926
1081
|
}
|
|
1082
|
+
const metaChanges = definitionChanges(localDef, remoteDef);
|
|
1083
|
+
if (metaChanges.length) {
|
|
1084
|
+
const destructive = localDef.capabilities ? disablesOnlineStore(localDef.capabilities, remoteDef.capabilities) : false;
|
|
1085
|
+
ops.push({
|
|
1086
|
+
kind: "updateDefinition",
|
|
1087
|
+
type: localDef.type,
|
|
1088
|
+
changes: metaChanges,
|
|
1089
|
+
...destructive ? { destructive: true } : {}
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
927
1092
|
}
|
|
928
1093
|
return ops;
|
|
929
1094
|
}
|
|
930
1095
|
|
|
931
1096
|
// src/sync/normalize.ts
|
|
932
|
-
function
|
|
933
|
-
const
|
|
934
|
-
|
|
1097
|
+
function localCapabilities(caps) {
|
|
1098
|
+
const out = {};
|
|
1099
|
+
if (caps?.publishable) out.publishable = { enabled: caps.publishable.enabled };
|
|
1100
|
+
if (caps?.translatable) out.translatable = { enabled: caps.translatable.enabled };
|
|
1101
|
+
if (caps?.renderable) {
|
|
1102
|
+
out.renderable = { enabled: caps.renderable.enabled };
|
|
1103
|
+
if (caps.renderable.data) out.renderable.data = { ...caps.renderable.data };
|
|
1104
|
+
}
|
|
1105
|
+
out.onlineStore = caps?.onlineStore ? { enabled: caps.onlineStore.enabled, data: { urlHandle: caps.onlineStore.data?.urlHandle } } : { enabled: false };
|
|
1106
|
+
return out;
|
|
1107
|
+
}
|
|
1108
|
+
function normalizeDefinition(def) {
|
|
1109
|
+
const out = {
|
|
935
1110
|
type: def.type,
|
|
936
1111
|
name: def.name,
|
|
1112
|
+
capabilities: localCapabilities(def.capabilities),
|
|
937
1113
|
fields: def.fieldDefinitions.map((f) => ({
|
|
938
1114
|
key: f.key,
|
|
939
1115
|
type: f.type,
|
|
940
1116
|
required: f.required,
|
|
1117
|
+
filterable: f.capabilities?.adminFilterable?.enabled ?? false,
|
|
941
1118
|
validations: f.validations
|
|
942
1119
|
}))
|
|
943
1120
|
};
|
|
1121
|
+
if (def.description != null) out.description = def.description;
|
|
1122
|
+
if (def.displayNameKey != null) out.displayNameKey = def.displayNameKey;
|
|
1123
|
+
if (def.access) out.access = { ...def.access };
|
|
1124
|
+
return out;
|
|
1125
|
+
}
|
|
1126
|
+
function normalizeLocal(schema) {
|
|
1127
|
+
return normalizeDefinition(schema.toDefinitionInput());
|
|
1128
|
+
}
|
|
1129
|
+
function remoteAccess(access) {
|
|
1130
|
+
if (!access) return void 0;
|
|
1131
|
+
const out = {};
|
|
1132
|
+
if (access.admin != null) out.admin = access.admin;
|
|
1133
|
+
if (access.storefront != null) out.storefront = access.storefront;
|
|
1134
|
+
if (access.customerAccount != null) out.customerAccount = access.customerAccount;
|
|
1135
|
+
return out;
|
|
1136
|
+
}
|
|
1137
|
+
function remoteCapabilities(caps) {
|
|
1138
|
+
const out = {};
|
|
1139
|
+
if (!caps) return out;
|
|
1140
|
+
if (caps.publishable) out.publishable = { enabled: !!caps.publishable.enabled };
|
|
1141
|
+
if (caps.translatable) out.translatable = { enabled: !!caps.translatable.enabled };
|
|
1142
|
+
if (caps.renderable) {
|
|
1143
|
+
out.renderable = { enabled: !!caps.renderable.enabled };
|
|
1144
|
+
const d = caps.renderable.data;
|
|
1145
|
+
if (d) {
|
|
1146
|
+
const data = {};
|
|
1147
|
+
if (d.metaTitleKey != null) data.metaTitleKey = d.metaTitleKey;
|
|
1148
|
+
if (d.metaDescriptionKey != null) data.metaDescriptionKey = d.metaDescriptionKey;
|
|
1149
|
+
if (Object.keys(data).length) out.renderable.data = data;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
if (caps.onlineStore) {
|
|
1153
|
+
out.onlineStore = { enabled: !!caps.onlineStore.enabled };
|
|
1154
|
+
if (caps.onlineStore.data?.urlHandle != null) out.onlineStore.data = { urlHandle: caps.onlineStore.data.urlHandle };
|
|
1155
|
+
}
|
|
1156
|
+
return out;
|
|
944
1157
|
}
|
|
945
1158
|
function normalizeRemote(def) {
|
|
946
|
-
|
|
1159
|
+
const out = {
|
|
947
1160
|
type: def.type,
|
|
948
1161
|
name: def.name,
|
|
1162
|
+
capabilities: remoteCapabilities(def.capabilities),
|
|
949
1163
|
fields: def.fieldDefinitions.map((f) => ({
|
|
950
1164
|
key: f.key,
|
|
951
1165
|
type: typeof f.type === "string" ? f.type : f.type.name,
|
|
952
1166
|
required: f.required,
|
|
1167
|
+
filterable: f.capabilities?.adminFilterable?.enabled ?? false,
|
|
953
1168
|
validations: f.validations ?? []
|
|
954
1169
|
}))
|
|
955
1170
|
};
|
|
1171
|
+
if (def.description != null) out.description = def.description;
|
|
1172
|
+
if (def.displayNameKey != null) out.displayNameKey = def.displayNameKey;
|
|
1173
|
+
const access = remoteAccess(def.access);
|
|
1174
|
+
if (access) out.access = access;
|
|
1175
|
+
return out;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// src/sync/resolve.ts
|
|
1179
|
+
var APP_PREFIX2 = "$app:";
|
|
1180
|
+
function effectiveScope(schema, config) {
|
|
1181
|
+
return schema.config.scope ?? config.scope ?? "app";
|
|
1182
|
+
}
|
|
1183
|
+
function effectiveType(handle, scope) {
|
|
1184
|
+
return scope === "merchant" ? handle : `${APP_PREFIX2}${handle}`;
|
|
1185
|
+
}
|
|
1186
|
+
function rewriteReference(v2, effByCanonical) {
|
|
1187
|
+
if (v2.name === "metaobject_definition_type") {
|
|
1188
|
+
const mapped = effByCanonical.get(v2.value);
|
|
1189
|
+
return mapped ? { ...v2, value: mapped } : v2;
|
|
1190
|
+
}
|
|
1191
|
+
if (v2.name === "metaobject_definition_types") {
|
|
1192
|
+
try {
|
|
1193
|
+
const parsed = JSON.parse(v2.value);
|
|
1194
|
+
if (Array.isArray(parsed)) {
|
|
1195
|
+
const rewritten = parsed.map((t) => typeof t === "string" ? effByCanonical.get(t) ?? t : t);
|
|
1196
|
+
return { ...v2, value: JSON.stringify(rewritten) };
|
|
1197
|
+
}
|
|
1198
|
+
} catch {
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
return v2;
|
|
1202
|
+
}
|
|
1203
|
+
function resolveAdmin(out, handle, scope, config) {
|
|
1204
|
+
const explicitAdmin = out.access?.admin;
|
|
1205
|
+
if (scope === "merchant") {
|
|
1206
|
+
if (explicitAdmin != null) {
|
|
1207
|
+
throw new Error(
|
|
1208
|
+
`"${handle}" is merchant-scoped but sets access.admin; admin access is only valid on app-scoped metaobjects.`
|
|
1209
|
+
);
|
|
1210
|
+
}
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
if (explicitAdmin == null) {
|
|
1214
|
+
const admin = config.merchantEditable ? "MERCHANT_READ_WRITE" : "MERCHANT_READ";
|
|
1215
|
+
out.access = { ...out.access, admin };
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
function resolveDefinitions(schemas, config = {}) {
|
|
1219
|
+
const effByCanonical = /* @__PURE__ */ new Map();
|
|
1220
|
+
for (const s of schemas) {
|
|
1221
|
+
effByCanonical.set(`${APP_PREFIX2}${s.handle}`, effectiveType(s.handle, effectiveScope(s, config)));
|
|
1222
|
+
}
|
|
1223
|
+
return schemas.map((s) => {
|
|
1224
|
+
const scope = effectiveScope(s, config);
|
|
1225
|
+
const base = s.toDefinitionInput();
|
|
1226
|
+
const fieldDefinitions = base.fieldDefinitions.map((f) => ({
|
|
1227
|
+
...f,
|
|
1228
|
+
validations: f.validations.map((v2) => rewriteReference(v2, effByCanonical))
|
|
1229
|
+
}));
|
|
1230
|
+
const out = { ...base, type: effectiveType(s.handle, scope), fieldDefinitions };
|
|
1231
|
+
resolveAdmin(out, s.handle, scope, config);
|
|
1232
|
+
return out;
|
|
1233
|
+
});
|
|
956
1234
|
}
|
|
957
1235
|
|
|
958
1236
|
// src/sync/client.ts
|
|
@@ -970,12 +1248,14 @@ var PULL_DEFINITION_QUERY = `query PullMetaobjectDefinition($type: String!) {
|
|
|
970
1248
|
required
|
|
971
1249
|
type { name }
|
|
972
1250
|
validations { name value }
|
|
1251
|
+
capabilities { adminFilterable { enabled } }
|
|
973
1252
|
}
|
|
974
|
-
access { admin storefront }
|
|
1253
|
+
access { admin storefront customerAccount }
|
|
975
1254
|
capabilities {
|
|
976
1255
|
publishable { enabled }
|
|
977
1256
|
translatable { enabled }
|
|
978
|
-
renderable { enabled }
|
|
1257
|
+
renderable { enabled data { metaTitleKey metaDescriptionKey } }
|
|
1258
|
+
onlineStore { enabled data { urlHandle } }
|
|
979
1259
|
}
|
|
980
1260
|
}
|
|
981
1261
|
}`;
|
|
@@ -985,6 +1265,8 @@ var LIST_DEFINITIONS_QUERY = `query ListMetaobjectDefinitions($after: String) {
|
|
|
985
1265
|
id
|
|
986
1266
|
name
|
|
987
1267
|
type
|
|
1268
|
+
description
|
|
1269
|
+
displayNameKey
|
|
988
1270
|
fieldDefinitions {
|
|
989
1271
|
key
|
|
990
1272
|
name
|
|
@@ -992,6 +1274,14 @@ var LIST_DEFINITIONS_QUERY = `query ListMetaobjectDefinitions($after: String) {
|
|
|
992
1274
|
required
|
|
993
1275
|
type { name }
|
|
994
1276
|
validations { name value }
|
|
1277
|
+
capabilities { adminFilterable { enabled } }
|
|
1278
|
+
}
|
|
1279
|
+
access { admin storefront customerAccount }
|
|
1280
|
+
capabilities {
|
|
1281
|
+
publishable { enabled }
|
|
1282
|
+
translatable { enabled }
|
|
1283
|
+
renderable { enabled data { metaTitleKey metaDescriptionKey } }
|
|
1284
|
+
onlineStore { enabled data { urlHandle } }
|
|
995
1285
|
}
|
|
996
1286
|
}
|
|
997
1287
|
pageInfo { hasNextPage endCursor }
|
|
@@ -1026,17 +1316,24 @@ async function execute(client, query, variables) {
|
|
|
1026
1316
|
}
|
|
1027
1317
|
|
|
1028
1318
|
// src/sync/pull.ts
|
|
1319
|
+
function toDefinition(type, node) {
|
|
1320
|
+
return {
|
|
1321
|
+
type,
|
|
1322
|
+
name: node.name,
|
|
1323
|
+
description: node.description,
|
|
1324
|
+
displayNameKey: node.displayNameKey,
|
|
1325
|
+
access: node.access,
|
|
1326
|
+
capabilities: node.capabilities,
|
|
1327
|
+
fieldDefinitions: node.fieldDefinitions
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1029
1330
|
async function pull(client, types) {
|
|
1030
1331
|
const out = [];
|
|
1031
1332
|
for (const type of types) {
|
|
1032
1333
|
const data = await execute(client, PULL_DEFINITION_QUERY, { type });
|
|
1033
1334
|
const node = data.metaobjectDefinitionByType;
|
|
1034
1335
|
if (!node) continue;
|
|
1035
|
-
out.push({
|
|
1036
|
-
id: node.id,
|
|
1037
|
-
type,
|
|
1038
|
-
definition: { type, name: node.name, fieldDefinitions: node.fieldDefinitions }
|
|
1039
|
-
});
|
|
1336
|
+
out.push({ id: node.id, type, definition: toDefinition(type, node) });
|
|
1040
1337
|
}
|
|
1041
1338
|
return out;
|
|
1042
1339
|
}
|
|
@@ -1054,7 +1351,7 @@ async function pullAll(client, opts = {}) {
|
|
|
1054
1351
|
const canonical = toCanonicalType(node.type);
|
|
1055
1352
|
if (appOwnedOnly && !canonical) continue;
|
|
1056
1353
|
const type = canonical ?? node.type;
|
|
1057
|
-
out.push({ id: node.id, type, definition:
|
|
1354
|
+
out.push({ id: node.id, type, definition: toDefinition(type, node) });
|
|
1058
1355
|
}
|
|
1059
1356
|
after = data.metaobjectDefinitions.pageInfo.hasNextPage ? data.metaobjectDefinitions.pageInfo.endCursor : null;
|
|
1060
1357
|
} while (after !== null);
|
|
@@ -1062,28 +1359,57 @@ async function pullAll(client, opts = {}) {
|
|
|
1062
1359
|
}
|
|
1063
1360
|
|
|
1064
1361
|
// src/sync/push.ts
|
|
1362
|
+
function definitionUpdateFor(def, changes) {
|
|
1363
|
+
const out = {};
|
|
1364
|
+
for (const c of changes) {
|
|
1365
|
+
if (c === "name") out.name = def.name;
|
|
1366
|
+
else if (c === "description") out.description = def.description;
|
|
1367
|
+
else if (c === "displayNameKey") out.displayNameKey = def.displayNameKey;
|
|
1368
|
+
else if (c === "access") out.access = def.access;
|
|
1369
|
+
else if (c === "capabilities") {
|
|
1370
|
+
const caps = def.capabilities;
|
|
1371
|
+
const payload = {};
|
|
1372
|
+
if (caps?.publishable) payload.publishable = caps.publishable;
|
|
1373
|
+
if (caps?.translatable) payload.translatable = caps.translatable;
|
|
1374
|
+
if (caps?.renderable) payload.renderable = caps.renderable;
|
|
1375
|
+
payload.onlineStore = caps?.onlineStore ?? { enabled: false };
|
|
1376
|
+
out.capabilities = payload;
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
return out;
|
|
1380
|
+
}
|
|
1065
1381
|
function fieldInputFor(defByType, type, key) {
|
|
1066
1382
|
return defByType.get(type)?.fieldDefinitions.find((f) => f.key === key);
|
|
1067
1383
|
}
|
|
1068
|
-
function
|
|
1384
|
+
function fieldRefTargets(field) {
|
|
1069
1385
|
const out = [];
|
|
1070
|
-
for (const
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
if (
|
|
1078
|
-
for (const t of parsed) if (typeof t === "string") out.push(t);
|
|
1079
|
-
}
|
|
1080
|
-
} catch {
|
|
1386
|
+
for (const v2 of field.validations) {
|
|
1387
|
+
if (v2.name === "metaobject_definition_type") {
|
|
1388
|
+
out.push(v2.value);
|
|
1389
|
+
} else if (v2.name === "metaobject_definition_types") {
|
|
1390
|
+
try {
|
|
1391
|
+
const parsed = JSON.parse(v2.value);
|
|
1392
|
+
if (Array.isArray(parsed)) {
|
|
1393
|
+
for (const t of parsed) if (typeof t === "string") out.push(t);
|
|
1081
1394
|
}
|
|
1395
|
+
} catch {
|
|
1082
1396
|
}
|
|
1083
1397
|
}
|
|
1084
1398
|
}
|
|
1085
1399
|
return out;
|
|
1086
1400
|
}
|
|
1401
|
+
function referenceEdges(def) {
|
|
1402
|
+
return def.fieldDefinitions.flatMap(fieldRefTargets);
|
|
1403
|
+
}
|
|
1404
|
+
function splitCyclicFields(def, cyclicTypes) {
|
|
1405
|
+
const pass1 = [];
|
|
1406
|
+
const deferred = [];
|
|
1407
|
+
for (const f of def.fieldDefinitions) {
|
|
1408
|
+
const breaksCycle = fieldRefTargets(f).some((t) => cyclicTypes.has(t) && t !== def.type);
|
|
1409
|
+
(breaksCycle ? deferred : pass1).push(f);
|
|
1410
|
+
}
|
|
1411
|
+
return { pass1, deferred };
|
|
1412
|
+
}
|
|
1087
1413
|
function topoSortCreates(types, deps) {
|
|
1088
1414
|
const remaining = /* @__PURE__ */ new Map();
|
|
1089
1415
|
const dependents = /* @__PURE__ */ new Map();
|
|
@@ -1126,50 +1452,51 @@ async function push(client, plan, sources, options) {
|
|
|
1126
1452
|
deps.set(op.type, new Set(targets.filter((t) => createTypes.has(t) && t !== op.type)));
|
|
1127
1453
|
}
|
|
1128
1454
|
const { ordered, unordered } = topoSortCreates(createTypes, deps);
|
|
1129
|
-
const orderedSet = new Set(ordered);
|
|
1130
1455
|
const cyclicTypes = new Set(unordered);
|
|
1131
1456
|
const createByType = new Map(createOps.map((x) => [x.op.type, x]));
|
|
1132
|
-
const execOrder = [
|
|
1133
|
-
...ordered.map((t) => createByType.get(t)),
|
|
1134
|
-
...createOps.filter((x) => !orderedSet.has(x.op.type)),
|
|
1135
|
-
...otherOps
|
|
1136
|
-
];
|
|
1137
1457
|
const failedTypes = /* @__PURE__ */ new Set();
|
|
1138
|
-
async function
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
if (
|
|
1152
|
-
failedTypes.add(op.type);
|
|
1153
|
-
return { op, status: "blocked", reason: `no definition input for "${op.type}"` };
|
|
1154
|
-
}
|
|
1155
|
-
const data2 = await execute(client, CREATE_DEFINITION_MUTATION, { definition: def });
|
|
1156
|
-
const payload2 = data2.metaobjectDefinitionCreate;
|
|
1157
|
-
if (payload2.userErrors.length) {
|
|
1458
|
+
async function createDefinition(op, definition) {
|
|
1459
|
+
const data = await execute(client, CREATE_DEFINITION_MUTATION, { definition });
|
|
1460
|
+
const payload = data.metaobjectDefinitionCreate;
|
|
1461
|
+
if (payload.userErrors.length) {
|
|
1462
|
+
failedTypes.add(op.type);
|
|
1463
|
+
return { op, status: "failed", userErrors: payload.userErrors };
|
|
1464
|
+
}
|
|
1465
|
+
const id = payload.metaobjectDefinition?.id;
|
|
1466
|
+
if (id) idByType.set(op.type, id);
|
|
1467
|
+
return { op, status: "applied", id };
|
|
1468
|
+
}
|
|
1469
|
+
async function applyAcyclicCreate(op) {
|
|
1470
|
+
for (const dep of deps.get(op.type) ?? []) {
|
|
1471
|
+
if (failedTypes.has(dep)) {
|
|
1158
1472
|
failedTypes.add(op.type);
|
|
1159
|
-
return { op, status: "
|
|
1473
|
+
return { op, status: "blocked", reason: `blocked: dependency "${dep}" was not created` };
|
|
1160
1474
|
}
|
|
1161
|
-
const id2 = payload2.metaobjectDefinition?.id;
|
|
1162
|
-
if (id2) idByType.set(op.type, id2);
|
|
1163
|
-
return { op, status: "applied", id: id2 };
|
|
1164
1475
|
}
|
|
1165
|
-
const
|
|
1476
|
+
const def = defByType.get(op.type);
|
|
1477
|
+
if (!def) {
|
|
1478
|
+
failedTypes.add(op.type);
|
|
1479
|
+
return { op, status: "blocked", reason: `no definition input for "${op.type}"` };
|
|
1480
|
+
}
|
|
1481
|
+
return createDefinition(op, def);
|
|
1482
|
+
}
|
|
1483
|
+
async function applyFieldOp(op) {
|
|
1484
|
+
const destructive = "destructive" in op && op.destructive === true;
|
|
1166
1485
|
if (destructive && !allowDestructive) return { op, status: "skipped", reason: "destructive" };
|
|
1167
1486
|
if (failedTypes.has(op.type)) return { op, status: "blocked", reason: `blocked: definition "${op.type}" was not created` };
|
|
1168
1487
|
const id = idByType.get(op.type);
|
|
1169
1488
|
if (id == null) return { op, status: "blocked", reason: `no definition id for "${op.type}"` };
|
|
1170
|
-
|
|
1171
|
-
if (
|
|
1172
|
-
|
|
1489
|
+
let definition;
|
|
1490
|
+
if (op.kind === "updateDefinition") {
|
|
1491
|
+
const def = defByType.get(op.type);
|
|
1492
|
+
if (!def) return { op, status: "blocked", reason: `no definition input for "${op.type}"` };
|
|
1493
|
+
definition = definitionUpdateFor(def, op.changes);
|
|
1494
|
+
} else {
|
|
1495
|
+
const fieldDefinitions = fieldOpsFor(op);
|
|
1496
|
+
if (!fieldDefinitions) return { op, status: "blocked", reason: `no field input for "${op.type}"` };
|
|
1497
|
+
definition = { fieldDefinitions };
|
|
1498
|
+
}
|
|
1499
|
+
const data = await execute(client, UPDATE_DEFINITION_MUTATION, { id, definition });
|
|
1173
1500
|
const payload = data.metaobjectDefinitionUpdate;
|
|
1174
1501
|
if (payload.userErrors.length) return { op, status: "failed", userErrors: payload.userErrors };
|
|
1175
1502
|
return { op, status: "applied", id: payload.metaobjectDefinition?.id ?? id };
|
|
@@ -1190,6 +1517,9 @@ async function push(client, plan, sources, options) {
|
|
|
1190
1517
|
validations: field.validations
|
|
1191
1518
|
};
|
|
1192
1519
|
if (field.description != null) update.description = field.description;
|
|
1520
|
+
if ("filterable" in op.changes) {
|
|
1521
|
+
update.capabilities = { adminFilterable: { enabled: op.changes.filterable ?? false } };
|
|
1522
|
+
}
|
|
1193
1523
|
return [{ update }];
|
|
1194
1524
|
}
|
|
1195
1525
|
case "removeField":
|
|
@@ -1203,7 +1533,53 @@ async function push(client, plan, sources, options) {
|
|
|
1203
1533
|
}
|
|
1204
1534
|
}
|
|
1205
1535
|
const results = new Array(plan.length);
|
|
1206
|
-
for (const
|
|
1536
|
+
for (const type of ordered) {
|
|
1537
|
+
const entry = createByType.get(type);
|
|
1538
|
+
results[entry.index] = await applyAcyclicCreate(entry.op);
|
|
1539
|
+
}
|
|
1540
|
+
const cyclicCreates = createOps.filter((x) => cyclicTypes.has(x.op.type));
|
|
1541
|
+
const deferredByType = /* @__PURE__ */ new Map();
|
|
1542
|
+
for (const { op, index } of cyclicCreates) {
|
|
1543
|
+
const def = defByType.get(op.type);
|
|
1544
|
+
if (!def) {
|
|
1545
|
+
failedTypes.add(op.type);
|
|
1546
|
+
results[index] = { op, status: "blocked", reason: `no definition input for "${op.type}"` };
|
|
1547
|
+
continue;
|
|
1548
|
+
}
|
|
1549
|
+
const failedDep = [...deps.get(op.type) ?? []].find((d) => !cyclicTypes.has(d) && failedTypes.has(d));
|
|
1550
|
+
if (failedDep) {
|
|
1551
|
+
failedTypes.add(op.type);
|
|
1552
|
+
results[index] = { op, status: "blocked", reason: `blocked: dependency "${failedDep}" was not created` };
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
1555
|
+
const { pass1, deferred } = splitCyclicFields(def, cyclicTypes);
|
|
1556
|
+
deferredByType.set(op.type, deferred);
|
|
1557
|
+
results[index] = await createDefinition(op, { ...def, fieldDefinitions: pass1 });
|
|
1558
|
+
}
|
|
1559
|
+
for (const { op, index } of cyclicCreates) {
|
|
1560
|
+
if (results[index]?.status !== "applied") continue;
|
|
1561
|
+
const deferred = deferredByType.get(op.type) ?? [];
|
|
1562
|
+
if (!deferred.length) continue;
|
|
1563
|
+
const failedTarget = deferred.flatMap(fieldRefTargets).find((t) => failedTypes.has(t));
|
|
1564
|
+
if (failedTarget) {
|
|
1565
|
+
failedTypes.add(op.type);
|
|
1566
|
+
results[index] = { op, status: "blocked", reason: `blocked: dependency "${failedTarget}" was not created` };
|
|
1567
|
+
continue;
|
|
1568
|
+
}
|
|
1569
|
+
const id = idByType.get(op.type);
|
|
1570
|
+
if (id == null) {
|
|
1571
|
+
results[index] = { op, status: "blocked", reason: `no definition id for "${op.type}"` };
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1574
|
+
const definition = { fieldDefinitions: deferred.map((f) => ({ create: f })) };
|
|
1575
|
+
const data = await execute(client, UPDATE_DEFINITION_MUTATION, { id, definition });
|
|
1576
|
+
const payload = data.metaobjectDefinitionUpdate;
|
|
1577
|
+
if (payload.userErrors.length) {
|
|
1578
|
+
failedTypes.add(op.type);
|
|
1579
|
+
results[index] = { op, status: "failed", userErrors: payload.userErrors };
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
for (const { op, index } of otherOps) results[index] = await applyFieldOp(op);
|
|
1207
1583
|
const counts = { applied: 0, skipped: 0, blocked: 0, failed: 0 };
|
|
1208
1584
|
for (const r of results) counts[r.status]++;
|
|
1209
1585
|
return { results, counts, ok: counts.failed === 0 && counts.blocked === 0 };
|
|
@@ -1218,11 +1594,13 @@ async function push(client, plan, sources, options) {
|
|
|
1218
1594
|
diff,
|
|
1219
1595
|
generateSchemaSource,
|
|
1220
1596
|
m,
|
|
1597
|
+
normalizeDefinition,
|
|
1221
1598
|
normalizeLocal,
|
|
1222
1599
|
normalizeRemote,
|
|
1223
1600
|
pull,
|
|
1224
1601
|
pullAll,
|
|
1225
1602
|
push,
|
|
1603
|
+
resolveDefinitions,
|
|
1226
1604
|
toDefinitionInput,
|
|
1227
1605
|
validateConfig
|
|
1228
1606
|
});
|