@fmaplabs/meta-manifest 0.1.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.
- package/README.md +49 -4
- package/dist/{chunk-PFU5VAO7.js → chunk-AUR2YQCW.js} +2 -2
- package/dist/{chunk-3R6VQ3Z3.js → chunk-VSJUGUH7.js} +15 -3
- package/dist/chunk-VSJUGUH7.js.map +1 -0
- package/dist/{chunk-GH5DXHS5.js → chunk-ZTWFDJHN.js} +318 -54
- package/dist/chunk-ZTWFDJHN.js.map +1 -0
- package/dist/cli/index.cjs +324 -39
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +49 -17
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +332 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +168 -36
- package/dist/index.d.ts +168 -36
- 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;
|
|
@@ -442,9 +438,7 @@ function ref(target, opts = {}) {
|
|
|
442
438
|
var StringScalarField = class extends Field {
|
|
443
439
|
constructor(opts) {
|
|
444
440
|
super();
|
|
445
|
-
this.
|
|
446
|
-
this.name = opts.name;
|
|
447
|
-
this.description = opts.description;
|
|
441
|
+
this.applyCommon(opts);
|
|
448
442
|
}
|
|
449
443
|
toJson(value) {
|
|
450
444
|
return value;
|
|
@@ -494,9 +488,7 @@ var JsonField = class extends Field {
|
|
|
494
488
|
wireIsJson = true;
|
|
495
489
|
constructor(opts) {
|
|
496
490
|
super();
|
|
497
|
-
this.
|
|
498
|
-
this.name = opts.name;
|
|
499
|
-
this.description = opts.description;
|
|
491
|
+
this.applyCommon(opts);
|
|
500
492
|
}
|
|
501
493
|
validations() {
|
|
502
494
|
return [];
|
|
@@ -530,9 +522,7 @@ var TextField = class extends Field {
|
|
|
530
522
|
super();
|
|
531
523
|
this.opts = opts;
|
|
532
524
|
this.shopifyType = multiline ? "multi_line_text_field" : "single_line_text_field";
|
|
533
|
-
this.
|
|
534
|
-
this.name = opts.name;
|
|
535
|
-
this.description = opts.description;
|
|
525
|
+
this.applyCommon(opts);
|
|
536
526
|
}
|
|
537
527
|
opts;
|
|
538
528
|
shopifyType;
|
|
@@ -600,16 +590,44 @@ function mapAccess(access) {
|
|
|
600
590
|
const out = {};
|
|
601
591
|
if (access.admin) out.admin = access.admin.toUpperCase();
|
|
602
592
|
if (access.storefront) out.storefront = access.storefront.toUpperCase();
|
|
593
|
+
if (access.customerAccount) out.customerAccount = access.customerAccount.toUpperCase();
|
|
603
594
|
return out;
|
|
604
595
|
}
|
|
605
596
|
function mapCapabilities(caps) {
|
|
606
597
|
if (!caps) return void 0;
|
|
607
598
|
const out = {};
|
|
608
|
-
|
|
599
|
+
if (caps.publishable != null) out.publishable = { enabled: caps.publishable };
|
|
600
|
+
if (caps.translatable != null) out.translatable = { enabled: caps.translatable };
|
|
601
|
+
if (caps.renderable != null) {
|
|
602
|
+
if (typeof caps.renderable === "boolean") {
|
|
603
|
+
out.renderable = { enabled: caps.renderable };
|
|
604
|
+
} else {
|
|
605
|
+
const data = {};
|
|
606
|
+
if (caps.renderable.metaTitleKey != null) data.metaTitleKey = caps.renderable.metaTitleKey;
|
|
607
|
+
if (caps.renderable.metaDescriptionKey != null) data.metaDescriptionKey = caps.renderable.metaDescriptionKey;
|
|
608
|
+
out.renderable = Object.keys(data).length ? { enabled: true, data } : { enabled: true };
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (caps.onlineStore != null) {
|
|
612
|
+
const data = { urlHandle: caps.onlineStore.urlHandle };
|
|
613
|
+
if (caps.onlineStore.createRedirects != null) data.createRedirects = caps.onlineStore.createRedirects;
|
|
614
|
+
out.onlineStore = { enabled: true, data };
|
|
615
|
+
}
|
|
609
616
|
return Object.keys(out).length ? out : void 0;
|
|
610
617
|
}
|
|
618
|
+
function validateSeoKeys(caps, fieldKeys, name) {
|
|
619
|
+
const r = caps?.renderable;
|
|
620
|
+
if (!r || typeof r === "boolean") return;
|
|
621
|
+
for (const prop of ["metaTitleKey", "metaDescriptionKey"]) {
|
|
622
|
+
const key = r[prop];
|
|
623
|
+
if (key != null && !fieldKeys.has(key)) {
|
|
624
|
+
throw new Error(`renderable.${prop} "${key}" is not a declared field key on "${name}".`);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
611
628
|
function toDefinitionInput(schema) {
|
|
612
629
|
const { config } = schema;
|
|
630
|
+
validateSeoKeys(config.capabilities, new Set(Object.keys(schema.fields)), config.name);
|
|
613
631
|
const fieldDefinitions = Object.entries(schema.fields).map(([key, field]) => {
|
|
614
632
|
const def = {
|
|
615
633
|
key,
|
|
@@ -619,6 +637,7 @@ function toDefinitionInput(schema) {
|
|
|
619
637
|
validations: field.validations()
|
|
620
638
|
};
|
|
621
639
|
if (field.description != null) def.description = field.description;
|
|
640
|
+
if (field.filterable) def.capabilities = { adminFilterable: { enabled: true } };
|
|
622
641
|
return def;
|
|
623
642
|
});
|
|
624
643
|
const out = {
|
|
@@ -691,6 +710,12 @@ function defineMetaobject(handle, config) {
|
|
|
691
710
|
|
|
692
711
|
// src/codegen.ts
|
|
693
712
|
var APP_PREFIX = "$app:";
|
|
713
|
+
function isMerchant(type) {
|
|
714
|
+
return !type.startsWith(APP_PREFIX);
|
|
715
|
+
}
|
|
716
|
+
function filterableEntry(field) {
|
|
717
|
+
return field.filterable ? ["filterable: true"] : [];
|
|
718
|
+
}
|
|
694
719
|
var SIMPLE = {
|
|
695
720
|
single_line_text_field: "text",
|
|
696
721
|
multi_line_text_field: "multilineText",
|
|
@@ -772,8 +797,8 @@ function scalarEntries(field, warnings, builder) {
|
|
|
772
797
|
jsonArr("file_type_options", "accept");
|
|
773
798
|
return e;
|
|
774
799
|
}
|
|
775
|
-
function scalarCall(builder, field, warnings) {
|
|
776
|
-
const lit = optsLiteral(scalarEntries(field, warnings, builder));
|
|
800
|
+
function scalarCall(builder, field, warnings, extra = []) {
|
|
801
|
+
const lit = optsLiteral([...scalarEntries(field, warnings, builder), ...extra]);
|
|
777
802
|
return lit ? `m.${builder}(${lit})` : `m.${builder}()`;
|
|
778
803
|
}
|
|
779
804
|
function fieldCall(field, typeToIdent, warnings) {
|
|
@@ -783,6 +808,7 @@ function fieldCall(field, typeToIdent, warnings) {
|
|
|
783
808
|
const max = v(field.validations, "max");
|
|
784
809
|
const e = [`min: ${Number(min ?? 1)}`, `max: ${Number(max ?? 5)}`];
|
|
785
810
|
if (field.required) e.unshift("required: true");
|
|
811
|
+
e.push(...filterableEntry(field));
|
|
786
812
|
if (min === void 0 || max === void 0) warnings.push(`rating field "${field.key}" missing min/max`);
|
|
787
813
|
return `m.rating(${optsLiteral(e)})`;
|
|
788
814
|
}
|
|
@@ -793,7 +819,11 @@ function fieldCall(field, typeToIdent, warnings) {
|
|
|
793
819
|
warnings.push(`unresolved reference on field "${field.key}"`);
|
|
794
820
|
return `m.json() /* TODO: unmapped reference */`;
|
|
795
821
|
}
|
|
796
|
-
|
|
822
|
+
const refEntries = [];
|
|
823
|
+
if (field.required) refEntries.push("required: true");
|
|
824
|
+
refEntries.push(...filterableEntry(field));
|
|
825
|
+
const opts = optsLiteral(refEntries);
|
|
826
|
+
return opts ? `m.ref(() => ${ident}, ${opts})` : `m.ref(() => ${ident})`;
|
|
797
827
|
}
|
|
798
828
|
if (type.startsWith("list.")) {
|
|
799
829
|
const inner = type.slice("list.".length);
|
|
@@ -803,6 +833,7 @@ function fieldCall(field, typeToIdent, warnings) {
|
|
|
803
833
|
const max = v(field.validations, "list.max");
|
|
804
834
|
if (min !== void 0) listEntries.push(`min: ${Number(min)}`);
|
|
805
835
|
if (max !== void 0) listEntries.push(`max: ${Number(max)}`);
|
|
836
|
+
listEntries.push(...filterableEntry(field));
|
|
806
837
|
const listOpts = optsLiteral(listEntries);
|
|
807
838
|
let innerCall;
|
|
808
839
|
if (inner === "metaobject_reference") {
|
|
@@ -821,17 +852,53 @@ function fieldCall(field, typeToIdent, warnings) {
|
|
|
821
852
|
}
|
|
822
853
|
return listOpts ? `m.list(${innerCall}, ${listOpts})` : `m.list(${innerCall})`;
|
|
823
854
|
}
|
|
824
|
-
if (SIMPLE[type]) return scalarCall(SIMPLE[type], field, warnings);
|
|
855
|
+
if (SIMPLE[type]) return scalarCall(SIMPLE[type], field, warnings, filterableEntry(field));
|
|
825
856
|
warnings.push(`unmapped field type "${type}" on field "${field.key}"`);
|
|
826
857
|
return `m.json() /* TODO: unmapped type ${type} */`;
|
|
827
858
|
}
|
|
859
|
+
function accessSource(access) {
|
|
860
|
+
if (!access) return "";
|
|
861
|
+
const parts = [];
|
|
862
|
+
if (access.admin === "MERCHANT_READ_WRITE") parts.push(`admin: "merchant_read_write"`);
|
|
863
|
+
if (access.storefront === "PUBLIC_READ") parts.push(`storefront: "public_read"`);
|
|
864
|
+
if (access.customerAccount === "READ") parts.push(`customerAccount: "read"`);
|
|
865
|
+
return parts.length ? `{ ${parts.join(", ")} }` : "";
|
|
866
|
+
}
|
|
867
|
+
function capabilitiesSource(caps) {
|
|
868
|
+
if (!caps) return "";
|
|
869
|
+
const parts = [];
|
|
870
|
+
if (caps.publishable?.enabled) parts.push(`publishable: true`);
|
|
871
|
+
if (caps.translatable?.enabled) parts.push(`translatable: true`);
|
|
872
|
+
if (caps.renderable?.enabled) {
|
|
873
|
+
const d = caps.renderable.data;
|
|
874
|
+
const dparts = [];
|
|
875
|
+
if (d?.metaTitleKey != null) dparts.push(`metaTitleKey: ${JSON.stringify(d.metaTitleKey)}`);
|
|
876
|
+
if (d?.metaDescriptionKey != null) dparts.push(`metaDescriptionKey: ${JSON.stringify(d.metaDescriptionKey)}`);
|
|
877
|
+
parts.push(dparts.length ? `renderable: { ${dparts.join(", ")} }` : `renderable: true`);
|
|
878
|
+
}
|
|
879
|
+
if (caps.onlineStore?.enabled && caps.onlineStore.data?.urlHandle != null) {
|
|
880
|
+
parts.push(`onlineStore: { urlHandle: ${JSON.stringify(caps.onlineStore.data.urlHandle)} }`);
|
|
881
|
+
}
|
|
882
|
+
return parts.length ? `{ ${parts.join(", ")} }` : "";
|
|
883
|
+
}
|
|
884
|
+
function defConfigLines(def) {
|
|
885
|
+
const lines = [];
|
|
886
|
+
if (isMerchant(def.type)) lines.push(` scope: "merchant",`);
|
|
887
|
+
if (def.name) lines.push(` name: ${JSON.stringify(def.name)},`);
|
|
888
|
+
if (def.description != null) lines.push(` description: ${JSON.stringify(def.description)},`);
|
|
889
|
+
if (def.displayNameKey != null) lines.push(` displayName: ${JSON.stringify(def.displayNameKey)},`);
|
|
890
|
+
const access = accessSource(def.access);
|
|
891
|
+
if (access) lines.push(` access: ${access},`);
|
|
892
|
+
const caps = capabilitiesSource(def.capabilities);
|
|
893
|
+
if (caps) lines.push(` capabilities: ${caps},`);
|
|
894
|
+
return lines.length ? `
|
|
895
|
+
${lines.join("\n")}` : "";
|
|
896
|
+
}
|
|
828
897
|
function defSource(def, typeToIdent, warnings) {
|
|
829
898
|
const ident = typeToIdent.get(def.type);
|
|
830
899
|
const handle = handleOf(def.type);
|
|
831
900
|
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}
|
|
901
|
+
return `export const ${ident} = defineMetaobject(${JSON.stringify(handle)}, {${defConfigLines(def)}
|
|
835
902
|
fields: {
|
|
836
903
|
${fields}
|
|
837
904
|
},
|
|
@@ -891,6 +958,42 @@ function sameValidations(a, b) {
|
|
|
891
958
|
const norm = (v2) => JSON.stringify([...v2].sort((x, y) => x.name.localeCompare(y.name)));
|
|
892
959
|
return norm(a) === norm(b);
|
|
893
960
|
}
|
|
961
|
+
var CAP_KEYS = ["publishable", "translatable", "renderable", "onlineStore"];
|
|
962
|
+
function accessChanged(local, remote) {
|
|
963
|
+
for (const key of ["admin", "storefront", "customerAccount"]) {
|
|
964
|
+
const lv = local[key];
|
|
965
|
+
if (lv != null && remote?.[key] !== lv) return true;
|
|
966
|
+
}
|
|
967
|
+
return false;
|
|
968
|
+
}
|
|
969
|
+
function capabilitiesChanged(local, remote) {
|
|
970
|
+
for (const key of CAP_KEYS) {
|
|
971
|
+
const lc = local[key];
|
|
972
|
+
if (!lc) continue;
|
|
973
|
+
const rc = remote?.[key];
|
|
974
|
+
if ((rc?.enabled ?? false) !== lc.enabled) return true;
|
|
975
|
+
const ldata = lc.data;
|
|
976
|
+
if (ldata) {
|
|
977
|
+
const rdata = rc?.data;
|
|
978
|
+
for (const [k, v2] of Object.entries(ldata)) {
|
|
979
|
+
if (v2 != null && rdata?.[k] !== v2) return true;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
return false;
|
|
984
|
+
}
|
|
985
|
+
function disablesOnlineStore(local, remote) {
|
|
986
|
+
return local.onlineStore?.enabled === false && remote?.onlineStore?.enabled === true;
|
|
987
|
+
}
|
|
988
|
+
function definitionChanges(local, remote) {
|
|
989
|
+
const changes = [];
|
|
990
|
+
if (local.name != null && local.name !== remote.name) changes.push("name");
|
|
991
|
+
if (local.description != null && local.description !== remote.description) changes.push("description");
|
|
992
|
+
if (local.displayNameKey != null && local.displayNameKey !== remote.displayNameKey) changes.push("displayNameKey");
|
|
993
|
+
if (local.access && accessChanged(local.access, remote.access)) changes.push("access");
|
|
994
|
+
if (local.capabilities && capabilitiesChanged(local.capabilities, remote.capabilities)) changes.push("capabilities");
|
|
995
|
+
return changes;
|
|
996
|
+
}
|
|
894
997
|
function diff(local, remote) {
|
|
895
998
|
const ops = [];
|
|
896
999
|
const remoteByType = new Map(remote.map((d) => [d.type, d]));
|
|
@@ -914,6 +1017,7 @@ function diff(local, remote) {
|
|
|
914
1017
|
}
|
|
915
1018
|
const changes = {};
|
|
916
1019
|
if (rf.required !== lf.required) changes.required = lf.required;
|
|
1020
|
+
if (rf.filterable !== lf.filterable) changes.filterable = lf.filterable;
|
|
917
1021
|
if (!sameValidations(rf.validations, lf.validations)) changes.validations = lf.validations;
|
|
918
1022
|
if (Object.keys(changes).length) {
|
|
919
1023
|
ops.push({ kind: "updateField", type: localDef.type, key: lf.key, changes });
|
|
@@ -924,35 +1028,158 @@ function diff(local, remote) {
|
|
|
924
1028
|
ops.push({ kind: "removeField", type: localDef.type, key: rf.key, destructive: true });
|
|
925
1029
|
}
|
|
926
1030
|
}
|
|
1031
|
+
const metaChanges = definitionChanges(localDef, remoteDef);
|
|
1032
|
+
if (metaChanges.length) {
|
|
1033
|
+
const destructive = localDef.capabilities ? disablesOnlineStore(localDef.capabilities, remoteDef.capabilities) : false;
|
|
1034
|
+
ops.push({
|
|
1035
|
+
kind: "updateDefinition",
|
|
1036
|
+
type: localDef.type,
|
|
1037
|
+
changes: metaChanges,
|
|
1038
|
+
...destructive ? { destructive: true } : {}
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
927
1041
|
}
|
|
928
1042
|
return ops;
|
|
929
1043
|
}
|
|
930
1044
|
|
|
931
1045
|
// src/sync/normalize.ts
|
|
932
|
-
function
|
|
933
|
-
const
|
|
934
|
-
|
|
1046
|
+
function localCapabilities(caps) {
|
|
1047
|
+
const out = {};
|
|
1048
|
+
if (caps?.publishable) out.publishable = { enabled: caps.publishable.enabled };
|
|
1049
|
+
if (caps?.translatable) out.translatable = { enabled: caps.translatable.enabled };
|
|
1050
|
+
if (caps?.renderable) {
|
|
1051
|
+
out.renderable = { enabled: caps.renderable.enabled };
|
|
1052
|
+
if (caps.renderable.data) out.renderable.data = { ...caps.renderable.data };
|
|
1053
|
+
}
|
|
1054
|
+
out.onlineStore = caps?.onlineStore ? { enabled: caps.onlineStore.enabled, data: { urlHandle: caps.onlineStore.data?.urlHandle } } : { enabled: false };
|
|
1055
|
+
return out;
|
|
1056
|
+
}
|
|
1057
|
+
function normalizeDefinition(def) {
|
|
1058
|
+
const out = {
|
|
935
1059
|
type: def.type,
|
|
936
1060
|
name: def.name,
|
|
1061
|
+
capabilities: localCapabilities(def.capabilities),
|
|
937
1062
|
fields: def.fieldDefinitions.map((f) => ({
|
|
938
1063
|
key: f.key,
|
|
939
1064
|
type: f.type,
|
|
940
1065
|
required: f.required,
|
|
1066
|
+
filterable: f.capabilities?.adminFilterable?.enabled ?? false,
|
|
941
1067
|
validations: f.validations
|
|
942
1068
|
}))
|
|
943
1069
|
};
|
|
1070
|
+
if (def.description != null) out.description = def.description;
|
|
1071
|
+
if (def.displayNameKey != null) out.displayNameKey = def.displayNameKey;
|
|
1072
|
+
if (def.access) out.access = { ...def.access };
|
|
1073
|
+
return out;
|
|
1074
|
+
}
|
|
1075
|
+
function normalizeLocal(schema) {
|
|
1076
|
+
return normalizeDefinition(schema.toDefinitionInput());
|
|
1077
|
+
}
|
|
1078
|
+
function remoteAccess(access) {
|
|
1079
|
+
if (!access) return void 0;
|
|
1080
|
+
const out = {};
|
|
1081
|
+
if (access.admin != null) out.admin = access.admin;
|
|
1082
|
+
if (access.storefront != null) out.storefront = access.storefront;
|
|
1083
|
+
if (access.customerAccount != null) out.customerAccount = access.customerAccount;
|
|
1084
|
+
return out;
|
|
1085
|
+
}
|
|
1086
|
+
function remoteCapabilities(caps) {
|
|
1087
|
+
const out = {};
|
|
1088
|
+
if (!caps) return out;
|
|
1089
|
+
if (caps.publishable) out.publishable = { enabled: !!caps.publishable.enabled };
|
|
1090
|
+
if (caps.translatable) out.translatable = { enabled: !!caps.translatable.enabled };
|
|
1091
|
+
if (caps.renderable) {
|
|
1092
|
+
out.renderable = { enabled: !!caps.renderable.enabled };
|
|
1093
|
+
const d = caps.renderable.data;
|
|
1094
|
+
if (d) {
|
|
1095
|
+
const data = {};
|
|
1096
|
+
if (d.metaTitleKey != null) data.metaTitleKey = d.metaTitleKey;
|
|
1097
|
+
if (d.metaDescriptionKey != null) data.metaDescriptionKey = d.metaDescriptionKey;
|
|
1098
|
+
if (Object.keys(data).length) out.renderable.data = data;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
if (caps.onlineStore) {
|
|
1102
|
+
out.onlineStore = { enabled: !!caps.onlineStore.enabled };
|
|
1103
|
+
if (caps.onlineStore.data?.urlHandle != null) out.onlineStore.data = { urlHandle: caps.onlineStore.data.urlHandle };
|
|
1104
|
+
}
|
|
1105
|
+
return out;
|
|
944
1106
|
}
|
|
945
1107
|
function normalizeRemote(def) {
|
|
946
|
-
|
|
1108
|
+
const out = {
|
|
947
1109
|
type: def.type,
|
|
948
1110
|
name: def.name,
|
|
1111
|
+
capabilities: remoteCapabilities(def.capabilities),
|
|
949
1112
|
fields: def.fieldDefinitions.map((f) => ({
|
|
950
1113
|
key: f.key,
|
|
951
1114
|
type: typeof f.type === "string" ? f.type : f.type.name,
|
|
952
1115
|
required: f.required,
|
|
1116
|
+
filterable: f.capabilities?.adminFilterable?.enabled ?? false,
|
|
953
1117
|
validations: f.validations ?? []
|
|
954
1118
|
}))
|
|
955
1119
|
};
|
|
1120
|
+
if (def.description != null) out.description = def.description;
|
|
1121
|
+
if (def.displayNameKey != null) out.displayNameKey = def.displayNameKey;
|
|
1122
|
+
const access = remoteAccess(def.access);
|
|
1123
|
+
if (access) out.access = access;
|
|
1124
|
+
return out;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// src/sync/resolve.ts
|
|
1128
|
+
var APP_PREFIX2 = "$app:";
|
|
1129
|
+
function effectiveScope(schema, config) {
|
|
1130
|
+
return schema.config.scope ?? config.scope ?? "app";
|
|
1131
|
+
}
|
|
1132
|
+
function effectiveType(handle, scope) {
|
|
1133
|
+
return scope === "merchant" ? handle : `${APP_PREFIX2}${handle}`;
|
|
1134
|
+
}
|
|
1135
|
+
function rewriteReference(v2, effByCanonical) {
|
|
1136
|
+
if (v2.name === "metaobject_definition_type") {
|
|
1137
|
+
const mapped = effByCanonical.get(v2.value);
|
|
1138
|
+
return mapped ? { ...v2, value: mapped } : v2;
|
|
1139
|
+
}
|
|
1140
|
+
if (v2.name === "metaobject_definition_types") {
|
|
1141
|
+
try {
|
|
1142
|
+
const parsed = JSON.parse(v2.value);
|
|
1143
|
+
if (Array.isArray(parsed)) {
|
|
1144
|
+
const rewritten = parsed.map((t) => typeof t === "string" ? effByCanonical.get(t) ?? t : t);
|
|
1145
|
+
return { ...v2, value: JSON.stringify(rewritten) };
|
|
1146
|
+
}
|
|
1147
|
+
} catch {
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
return v2;
|
|
1151
|
+
}
|
|
1152
|
+
function resolveAdmin(out, handle, scope, config) {
|
|
1153
|
+
const explicitAdmin = out.access?.admin;
|
|
1154
|
+
if (scope === "merchant") {
|
|
1155
|
+
if (explicitAdmin != null) {
|
|
1156
|
+
throw new Error(
|
|
1157
|
+
`"${handle}" is merchant-scoped but sets access.admin; admin access is only valid on app-scoped metaobjects.`
|
|
1158
|
+
);
|
|
1159
|
+
}
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
if (explicitAdmin == null) {
|
|
1163
|
+
const admin = config.merchantEditable ? "MERCHANT_READ_WRITE" : "MERCHANT_READ";
|
|
1164
|
+
out.access = { ...out.access, admin };
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
function resolveDefinitions(schemas, config = {}) {
|
|
1168
|
+
const effByCanonical = /* @__PURE__ */ new Map();
|
|
1169
|
+
for (const s of schemas) {
|
|
1170
|
+
effByCanonical.set(`${APP_PREFIX2}${s.handle}`, effectiveType(s.handle, effectiveScope(s, config)));
|
|
1171
|
+
}
|
|
1172
|
+
return schemas.map((s) => {
|
|
1173
|
+
const scope = effectiveScope(s, config);
|
|
1174
|
+
const base = s.toDefinitionInput();
|
|
1175
|
+
const fieldDefinitions = base.fieldDefinitions.map((f) => ({
|
|
1176
|
+
...f,
|
|
1177
|
+
validations: f.validations.map((v2) => rewriteReference(v2, effByCanonical))
|
|
1178
|
+
}));
|
|
1179
|
+
const out = { ...base, type: effectiveType(s.handle, scope), fieldDefinitions };
|
|
1180
|
+
resolveAdmin(out, s.handle, scope, config);
|
|
1181
|
+
return out;
|
|
1182
|
+
});
|
|
956
1183
|
}
|
|
957
1184
|
|
|
958
1185
|
// src/sync/client.ts
|
|
@@ -970,12 +1197,14 @@ var PULL_DEFINITION_QUERY = `query PullMetaobjectDefinition($type: String!) {
|
|
|
970
1197
|
required
|
|
971
1198
|
type { name }
|
|
972
1199
|
validations { name value }
|
|
1200
|
+
capabilities { adminFilterable { enabled } }
|
|
973
1201
|
}
|
|
974
|
-
access { admin storefront }
|
|
1202
|
+
access { admin storefront customerAccount }
|
|
975
1203
|
capabilities {
|
|
976
1204
|
publishable { enabled }
|
|
977
1205
|
translatable { enabled }
|
|
978
|
-
renderable { enabled }
|
|
1206
|
+
renderable { enabled data { metaTitleKey metaDescriptionKey } }
|
|
1207
|
+
onlineStore { enabled data { urlHandle } }
|
|
979
1208
|
}
|
|
980
1209
|
}
|
|
981
1210
|
}`;
|
|
@@ -985,6 +1214,8 @@ var LIST_DEFINITIONS_QUERY = `query ListMetaobjectDefinitions($after: String) {
|
|
|
985
1214
|
id
|
|
986
1215
|
name
|
|
987
1216
|
type
|
|
1217
|
+
description
|
|
1218
|
+
displayNameKey
|
|
988
1219
|
fieldDefinitions {
|
|
989
1220
|
key
|
|
990
1221
|
name
|
|
@@ -992,6 +1223,14 @@ var LIST_DEFINITIONS_QUERY = `query ListMetaobjectDefinitions($after: String) {
|
|
|
992
1223
|
required
|
|
993
1224
|
type { name }
|
|
994
1225
|
validations { name value }
|
|
1226
|
+
capabilities { adminFilterable { enabled } }
|
|
1227
|
+
}
|
|
1228
|
+
access { admin storefront customerAccount }
|
|
1229
|
+
capabilities {
|
|
1230
|
+
publishable { enabled }
|
|
1231
|
+
translatable { enabled }
|
|
1232
|
+
renderable { enabled data { metaTitleKey metaDescriptionKey } }
|
|
1233
|
+
onlineStore { enabled data { urlHandle } }
|
|
995
1234
|
}
|
|
996
1235
|
}
|
|
997
1236
|
pageInfo { hasNextPage endCursor }
|
|
@@ -1026,17 +1265,24 @@ async function execute(client, query, variables) {
|
|
|
1026
1265
|
}
|
|
1027
1266
|
|
|
1028
1267
|
// src/sync/pull.ts
|
|
1268
|
+
function toDefinition(type, node) {
|
|
1269
|
+
return {
|
|
1270
|
+
type,
|
|
1271
|
+
name: node.name,
|
|
1272
|
+
description: node.description,
|
|
1273
|
+
displayNameKey: node.displayNameKey,
|
|
1274
|
+
access: node.access,
|
|
1275
|
+
capabilities: node.capabilities,
|
|
1276
|
+
fieldDefinitions: node.fieldDefinitions
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1029
1279
|
async function pull(client, types) {
|
|
1030
1280
|
const out = [];
|
|
1031
1281
|
for (const type of types) {
|
|
1032
1282
|
const data = await execute(client, PULL_DEFINITION_QUERY, { type });
|
|
1033
1283
|
const node = data.metaobjectDefinitionByType;
|
|
1034
1284
|
if (!node) continue;
|
|
1035
|
-
out.push({
|
|
1036
|
-
id: node.id,
|
|
1037
|
-
type,
|
|
1038
|
-
definition: { type, name: node.name, fieldDefinitions: node.fieldDefinitions }
|
|
1039
|
-
});
|
|
1285
|
+
out.push({ id: node.id, type, definition: toDefinition(type, node) });
|
|
1040
1286
|
}
|
|
1041
1287
|
return out;
|
|
1042
1288
|
}
|
|
@@ -1054,7 +1300,7 @@ async function pullAll(client, opts = {}) {
|
|
|
1054
1300
|
const canonical = toCanonicalType(node.type);
|
|
1055
1301
|
if (appOwnedOnly && !canonical) continue;
|
|
1056
1302
|
const type = canonical ?? node.type;
|
|
1057
|
-
out.push({ id: node.id, type, definition:
|
|
1303
|
+
out.push({ id: node.id, type, definition: toDefinition(type, node) });
|
|
1058
1304
|
}
|
|
1059
1305
|
after = data.metaobjectDefinitions.pageInfo.hasNextPage ? data.metaobjectDefinitions.pageInfo.endCursor : null;
|
|
1060
1306
|
} while (after !== null);
|
|
@@ -1062,6 +1308,25 @@ async function pullAll(client, opts = {}) {
|
|
|
1062
1308
|
}
|
|
1063
1309
|
|
|
1064
1310
|
// src/sync/push.ts
|
|
1311
|
+
function definitionUpdateFor(def, changes) {
|
|
1312
|
+
const out = {};
|
|
1313
|
+
for (const c of changes) {
|
|
1314
|
+
if (c === "name") out.name = def.name;
|
|
1315
|
+
else if (c === "description") out.description = def.description;
|
|
1316
|
+
else if (c === "displayNameKey") out.displayNameKey = def.displayNameKey;
|
|
1317
|
+
else if (c === "access") out.access = def.access;
|
|
1318
|
+
else if (c === "capabilities") {
|
|
1319
|
+
const caps = def.capabilities;
|
|
1320
|
+
const payload = {};
|
|
1321
|
+
if (caps?.publishable) payload.publishable = caps.publishable;
|
|
1322
|
+
if (caps?.translatable) payload.translatable = caps.translatable;
|
|
1323
|
+
if (caps?.renderable) payload.renderable = caps.renderable;
|
|
1324
|
+
payload.onlineStore = caps?.onlineStore ?? { enabled: false };
|
|
1325
|
+
out.capabilities = payload;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
return out;
|
|
1329
|
+
}
|
|
1065
1330
|
function fieldInputFor(defByType, type, key) {
|
|
1066
1331
|
return defByType.get(type)?.fieldDefinitions.find((f) => f.key === key);
|
|
1067
1332
|
}
|
|
@@ -1162,14 +1427,22 @@ async function push(client, plan, sources, options) {
|
|
|
1162
1427
|
if (id2) idByType.set(op.type, id2);
|
|
1163
1428
|
return { op, status: "applied", id: id2 };
|
|
1164
1429
|
}
|
|
1165
|
-
const destructive =
|
|
1430
|
+
const destructive = "destructive" in op && op.destructive === true;
|
|
1166
1431
|
if (destructive && !allowDestructive) return { op, status: "skipped", reason: "destructive" };
|
|
1167
1432
|
if (failedTypes.has(op.type)) return { op, status: "blocked", reason: `blocked: definition "${op.type}" was not created` };
|
|
1168
1433
|
const id = idByType.get(op.type);
|
|
1169
1434
|
if (id == null) return { op, status: "blocked", reason: `no definition id for "${op.type}"` };
|
|
1170
|
-
|
|
1171
|
-
if (
|
|
1172
|
-
|
|
1435
|
+
let definition;
|
|
1436
|
+
if (op.kind === "updateDefinition") {
|
|
1437
|
+
const def = defByType.get(op.type);
|
|
1438
|
+
if (!def) return { op, status: "blocked", reason: `no definition input for "${op.type}"` };
|
|
1439
|
+
definition = definitionUpdateFor(def, op.changes);
|
|
1440
|
+
} else {
|
|
1441
|
+
const fieldDefinitions = fieldOpsFor(op);
|
|
1442
|
+
if (!fieldDefinitions) return { op, status: "blocked", reason: `no field input for "${op.type}"` };
|
|
1443
|
+
definition = { fieldDefinitions };
|
|
1444
|
+
}
|
|
1445
|
+
const data = await execute(client, UPDATE_DEFINITION_MUTATION, { id, definition });
|
|
1173
1446
|
const payload = data.metaobjectDefinitionUpdate;
|
|
1174
1447
|
if (payload.userErrors.length) return { op, status: "failed", userErrors: payload.userErrors };
|
|
1175
1448
|
return { op, status: "applied", id: payload.metaobjectDefinition?.id ?? id };
|
|
@@ -1190,6 +1463,9 @@ async function push(client, plan, sources, options) {
|
|
|
1190
1463
|
validations: field.validations
|
|
1191
1464
|
};
|
|
1192
1465
|
if (field.description != null) update.description = field.description;
|
|
1466
|
+
if ("filterable" in op.changes) {
|
|
1467
|
+
update.capabilities = { adminFilterable: { enabled: op.changes.filterable ?? false } };
|
|
1468
|
+
}
|
|
1193
1469
|
return [{ update }];
|
|
1194
1470
|
}
|
|
1195
1471
|
case "removeField":
|
|
@@ -1218,11 +1494,13 @@ async function push(client, plan, sources, options) {
|
|
|
1218
1494
|
diff,
|
|
1219
1495
|
generateSchemaSource,
|
|
1220
1496
|
m,
|
|
1497
|
+
normalizeDefinition,
|
|
1221
1498
|
normalizeLocal,
|
|
1222
1499
|
normalizeRemote,
|
|
1223
1500
|
pull,
|
|
1224
1501
|
pullAll,
|
|
1225
1502
|
push,
|
|
1503
|
+
resolveDefinitions,
|
|
1226
1504
|
toDefinitionInput,
|
|
1227
1505
|
validateConfig
|
|
1228
1506
|
});
|