@notambourine/metafields 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +96 -0
  3. package/dist/admin.d.ts +34 -0
  4. package/dist/admin.d.ts.map +1 -0
  5. package/dist/admin.js +303 -0
  6. package/dist/admin.js.map +1 -0
  7. package/dist/builders.d.ts +28 -0
  8. package/dist/builders.d.ts.map +1 -0
  9. package/dist/builders.js +103 -0
  10. package/dist/builders.js.map +1 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +244 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/generator.d.ts +14 -0
  16. package/dist/generator.d.ts.map +1 -0
  17. package/dist/generator.js +168 -0
  18. package/dist/generator.js.map +1 -0
  19. package/dist/index.d.ts +11 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +7 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/loader.d.ts +4 -0
  24. package/dist/loader.d.ts.map +1 -0
  25. package/dist/loader.js +20 -0
  26. package/dist/loader.js.map +1 -0
  27. package/dist/migration.d.ts +62 -0
  28. package/dist/migration.d.ts.map +1 -0
  29. package/dist/migration.js +265 -0
  30. package/dist/migration.js.map +1 -0
  31. package/dist/planner.d.ts +60 -0
  32. package/dist/planner.d.ts.map +1 -0
  33. package/dist/planner.js +161 -0
  34. package/dist/planner.js.map +1 -0
  35. package/dist/pull.d.ts +11 -0
  36. package/dist/pull.d.ts.map +1 -0
  37. package/dist/pull.js +133 -0
  38. package/dist/pull.js.map +1 -0
  39. package/dist/schema.d.ts +58 -0
  40. package/dist/schema.d.ts.map +1 -0
  41. package/dist/schema.js +232 -0
  42. package/dist/schema.js.map +1 -0
  43. package/dist/types.d.ts +145 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +4 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +46 -0
@@ -0,0 +1,265 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { OWNER_TYPES, stringifyCanonical } from './schema.js';
3
+ import { FIELD_MARKER } from './types.js';
4
+ export const MIGRATION_MARKER = '@notambourine/metafields/migration';
5
+ export const transforms = {
6
+ url(options) {
7
+ return { kind: 'url', ...options };
8
+ },
9
+ };
10
+ export function defineMigration(definition) {
11
+ return { __kind: MIGRATION_MARKER, ...definition };
12
+ }
13
+ export function compileMigration(value) {
14
+ if (!isRecord(value) || value.__kind !== MIGRATION_MARKER) {
15
+ throw new Error('default export must be created with defineMigration()');
16
+ }
17
+ if (typeof value.id !== 'string' || !/^[a-z0-9][a-z0-9_-]*$/.test(value.id)) {
18
+ throw new Error('migration id must contain lowercase alphanumeric, hyphen, or underscore characters');
19
+ }
20
+ const source = compileEndpoint(value.from, 'source');
21
+ const target = compileEndpoint(value.to, 'target');
22
+ if (source.owner !== target.owner)
23
+ throw new Error('migration source and target must have the same owner type');
24
+ if (source.namespace === target.namespace && source.key === target.key) {
25
+ throw new Error('migration source and target must be different keys');
26
+ }
27
+ if (value.mode !== 'copy' || value.onInvalid !== 'fail' || value.onTargetConflict !== 'fail') {
28
+ throw new Error('migrations must be copy-only and fail on invalid values or target conflicts');
29
+ }
30
+ if (!isUrlTransform(value.transform))
31
+ throw new Error('migration must use a package-supplied transform');
32
+ if (source.type !== 'single_line_text_field' || target.type !== 'url') {
33
+ throw new Error(`url transform requires single_line_text_field -> url, found ${source.type} -> ${target.type}`);
34
+ }
35
+ const unsigned = {
36
+ format: '@notambourine/metafields/migration-v1',
37
+ id: value.id,
38
+ source,
39
+ target,
40
+ mode: 'copy',
41
+ transform: value.transform,
42
+ onInvalid: 'fail',
43
+ onTargetConflict: 'fail',
44
+ };
45
+ const checksum = createHash('sha256').update(stringifyCanonical(unsigned)).digest('hex');
46
+ return { ...unsigned, checksum };
47
+ }
48
+ export function assertCompiledMigration(value) {
49
+ if (!isRecord(value) || value.format !== '@notambourine/metafields/migration-v1' ||
50
+ typeof value.checksum !== 'string') {
51
+ throw new Error('compiled input is not a @notambourine/metafields migration-v1 artifact');
52
+ }
53
+ const { checksum, ...unsigned } = value;
54
+ const actual = createHash('sha256').update(stringifyCanonical(unsigned)).digest('hex');
55
+ if (actual !== checksum)
56
+ throw new Error('compiled migration checksum does not match its contents');
57
+ }
58
+ function compileEndpoint(value, label) {
59
+ if (!isRecord(value) || value.__kind !== FIELD_MARKER || typeof value.type !== 'string' || !isRecord(value.identity)) {
60
+ throw new Error(`${label} must reference a field from a defined schema`);
61
+ }
62
+ const { owner, namespace, key } = value.identity;
63
+ if (typeof owner !== 'string' || !(owner in OWNER_TYPES) || typeof namespace !== 'string' || typeof key !== 'string') {
64
+ throw new Error(`${label} has no valid schema identity`);
65
+ }
66
+ return { owner: owner, namespace, key, type: value.type };
67
+ }
68
+ function isUrlTransform(value) {
69
+ if (!isRecord(value) || value.kind !== 'url' || value.bareHost !== 'reject' ||
70
+ typeof value.trim !== 'boolean' || !Array.isArray(value.allowedSchemes) || value.allowedSchemes.length === 0) {
71
+ return false;
72
+ }
73
+ const allowed = new Set(['http', 'https', 'mailto', 'sms', 'tel']);
74
+ return value.allowedSchemes.every((scheme) => typeof scheme === 'string' && allowed.has(scheme));
75
+ }
76
+ function isRecord(value) {
77
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
78
+ }
79
+ const ownerConnections = {
80
+ article: { connection: 'articles', graphType: 'Article' },
81
+ blog: { connection: 'blogs', graphType: 'Blog' },
82
+ collection: { connection: 'collections', graphType: 'Collection' },
83
+ customer: { connection: 'customers', graphType: 'Customer' },
84
+ draft_order: { connection: 'draftOrders', graphType: 'DraftOrder' },
85
+ location: { connection: 'locations', graphType: 'Location' },
86
+ order: { connection: 'orders', graphType: 'Order' },
87
+ page: { connection: 'pages', graphType: 'Page' },
88
+ product: { connection: 'products', graphType: 'Product' },
89
+ product_variant: { connection: 'productVariants', graphType: 'ProductVariant' },
90
+ };
91
+ export async function runMigration(client, migration, mode) {
92
+ assertCompiledMigration(migration);
93
+ await verifyDefinitions(client, migration);
94
+ const rows = await readRows(client, migration);
95
+ const writes = [];
96
+ let equal = 0;
97
+ let invalid = 0;
98
+ let conflicts = 0;
99
+ for (const row of rows) {
100
+ if (!row.source || row.source.value.length === 0)
101
+ continue;
102
+ const transformed = transformValue(row.source.value, migration.transform);
103
+ if (transformed === null) {
104
+ invalid += 1;
105
+ continue;
106
+ }
107
+ if (row.target?.value === transformed) {
108
+ equal += 1;
109
+ continue;
110
+ }
111
+ if (row.target !== null) {
112
+ conflicts += 1;
113
+ continue;
114
+ }
115
+ writes.push({
116
+ ownerId: row.id,
117
+ namespace: migration.target.namespace,
118
+ key: migration.target.key,
119
+ type: migration.target.type,
120
+ value: transformed,
121
+ compareDigest: null,
122
+ });
123
+ }
124
+ const result = {
125
+ id: migration.id,
126
+ checksum: migration.checksum,
127
+ source: rows.filter((row) => row.source?.value).length,
128
+ pending: writes.length,
129
+ equal,
130
+ invalid,
131
+ conflicts,
132
+ applied: 0,
133
+ };
134
+ if (invalid > 0 || conflicts > 0 || mode !== 'apply')
135
+ return result;
136
+ for (let index = 0; index < writes.length; index += 25) {
137
+ const batch = writes.slice(index, index + 25);
138
+ const data = await client.request(METAFIELDS_SET_MUTATION, { metafields: batch }, true);
139
+ if (data.metafieldsSet.userErrors.length > 0 || !data.metafieldsSet.metafields) {
140
+ throw new Error(`migration write failed: ${data.metafieldsSet.userErrors.map((error) => error.message).join('; ')}`);
141
+ }
142
+ const verified = await readNodes(client, migration, batch.map((write) => write.ownerId));
143
+ for (const row of verified) {
144
+ const original = rows.find((item) => item.id === row.id);
145
+ const expected = batch.find((item) => item.ownerId === row.id);
146
+ if (!original?.source || row.source?.compareDigest !== original.source.compareDigest) {
147
+ throw new Error(`source changed during migration for owner ${row.id}`);
148
+ }
149
+ if (!expected || row.target?.value !== expected.value) {
150
+ throw new Error(`target verification failed for owner ${row.id}`);
151
+ }
152
+ }
153
+ result.applied += batch.length;
154
+ }
155
+ result.pending = 0;
156
+ return result;
157
+ }
158
+ export function migrationExitCode(result, mode) {
159
+ if (result.invalid > 0 || result.conflicts > 0)
160
+ return 1;
161
+ if (mode === 'check' && result.pending > 0)
162
+ return 1;
163
+ return 0;
164
+ }
165
+ async function verifyDefinitions(client, migration) {
166
+ const source = await client.readMetafield({
167
+ ownerType: OWNER_TYPES[migration.source.owner],
168
+ namespace: migration.source.namespace,
169
+ key: migration.source.key,
170
+ });
171
+ const target = await client.readMetafield({
172
+ ownerType: OWNER_TYPES[migration.target.owner],
173
+ namespace: migration.target.namespace,
174
+ key: migration.target.key,
175
+ });
176
+ const sourceType = source && (typeof source.type === 'string' ? source.type : source.type.name);
177
+ const targetType = target && (typeof target.type === 'string' ? target.type : target.type.name);
178
+ if (sourceType !== migration.source.type)
179
+ throw new Error('migration source definition is missing or has the wrong type');
180
+ if (targetType !== migration.target.type)
181
+ throw new Error('migration target definition is missing or has the wrong type');
182
+ }
183
+ async function readRows(client, migration) {
184
+ if (migration.source.owner === 'shop') {
185
+ const data = await client.request(ownerQuery('shop', 'Shop'), variables(migration));
186
+ return [data.shop];
187
+ }
188
+ const config = ownerConnections[migration.source.owner];
189
+ if (!config)
190
+ throw new Error(`migrations do not yet support ${migration.source.owner} owners`);
191
+ const rows = [];
192
+ let after = null;
193
+ do {
194
+ const data = await client.request(ownerQuery(config.connection, config.graphType), { ...variables(migration), after });
195
+ const connection = data[config.connection];
196
+ if (!connection)
197
+ throw new Error(`Shopify returned no ${config.connection} connection`);
198
+ rows.push(...connection.nodes);
199
+ after = connection.pageInfo.hasNextPage ? connection.pageInfo.endCursor : null;
200
+ } while (after);
201
+ return rows;
202
+ }
203
+ async function readNodes(client, migration, ids) {
204
+ const graphType = migration.source.owner === 'shop'
205
+ ? 'Shop'
206
+ : ownerConnections[migration.source.owner]?.graphType;
207
+ if (!graphType)
208
+ throw new Error(`migrations do not support ${migration.source.owner} owners`);
209
+ const data = await client.request(`
210
+ query VerifyMigration($ids: [ID!]!, $sourceNamespace: String!, $sourceKey: String!, $targetNamespace: String!, $targetKey: String!) {
211
+ nodes(ids: $ids) {
212
+ ... on ${graphType} {
213
+ id
214
+ source: metafield(namespace: $sourceNamespace, key: $sourceKey) { value compareDigest }
215
+ target: metafield(namespace: $targetNamespace, key: $targetKey) { value compareDigest }
216
+ }
217
+ }
218
+ }
219
+ `, { ...variables(migration), ids });
220
+ return data.nodes.filter((row) => row !== null);
221
+ }
222
+ function ownerQuery(connection, graphType) {
223
+ const selection = `
224
+ id
225
+ source: metafield(namespace: $sourceNamespace, key: $sourceKey) { value compareDigest }
226
+ target: metafield(namespace: $targetNamespace, key: $targetKey) { value compareDigest }
227
+ `;
228
+ if (connection === 'shop') {
229
+ return `query MigrationRows($sourceNamespace: String!, $sourceKey: String!, $targetNamespace: String!, $targetKey: String!) { shop { ${selection} } }`;
230
+ }
231
+ return `query MigrationRows($after: String, $sourceNamespace: String!, $sourceKey: String!, $targetNamespace: String!, $targetKey: String!) {
232
+ ${connection}(first: 100, after: $after) {
233
+ nodes { ... on ${graphType} { ${selection} } }
234
+ pageInfo { hasNextPage endCursor }
235
+ }
236
+ }`;
237
+ }
238
+ function variables(migration) {
239
+ return {
240
+ sourceNamespace: migration.source.namespace,
241
+ sourceKey: migration.source.key,
242
+ targetNamespace: migration.target.namespace,
243
+ targetKey: migration.target.key,
244
+ };
245
+ }
246
+ function transformValue(value, transform) {
247
+ const candidate = transform.trim ? value.trim() : value;
248
+ let url;
249
+ try {
250
+ url = new URL(candidate);
251
+ }
252
+ catch {
253
+ return null;
254
+ }
255
+ const scheme = url.protocol.slice(0, -1);
256
+ return transform.allowedSchemes.includes(scheme) ? candidate : null;
257
+ }
258
+ const METAFIELDS_SET_MUTATION = `
259
+ mutation ApplyMigration($metafields: [MetafieldsSetInput!]!) {
260
+ metafieldsSet(metafields: $metafields) {
261
+ metafields { ownerType }
262
+ userErrors { field message code }
263
+ }
264
+ }`;
265
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.js","sourceRoot":"","sources":["../src/migration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import type { CanonicalMetafield, CanonicalMetaobject, CompiledSchema } from './schema.js';
2
+ export interface ExistingField {
3
+ key: string;
4
+ name: string;
5
+ description?: string | null | undefined;
6
+ type: string | {
7
+ name: string;
8
+ };
9
+ required?: boolean | undefined;
10
+ validations?: readonly {
11
+ name: string;
12
+ value: string;
13
+ }[] | undefined;
14
+ access?: Record<string, string | null>;
15
+ capabilities?: Record<string, boolean>;
16
+ constraints?: {
17
+ key: string | null;
18
+ values: readonly string[];
19
+ } | null;
20
+ }
21
+ export interface ExistingMetafield extends ExistingField {
22
+ id?: string;
23
+ ownerType: string;
24
+ namespace: string;
25
+ validationStatus?: 'ALL_VALID' | 'IN_PROGRESS' | 'SOME_INVALID' | undefined;
26
+ invalidCount?: number | undefined;
27
+ }
28
+ export interface ExistingMetaobject {
29
+ id?: string;
30
+ type: string;
31
+ name: string;
32
+ description?: string | null | undefined;
33
+ displayNameKey?: string | null | undefined;
34
+ access?: Record<string, string | null>;
35
+ capabilities?: Record<string, boolean>;
36
+ fields: ExistingField[];
37
+ }
38
+ export interface ExistingSchema {
39
+ metaobjects: ExistingMetaobject[];
40
+ metafields: ExistingMetafield[];
41
+ }
42
+ export type PlanStatus = 'CREATE' | 'PRESENT' | 'CONFLICT' | 'INDETERMINATE';
43
+ export interface PlanItem {
44
+ kind: 'metaobject' | 'metafield';
45
+ identity: string;
46
+ status: PlanStatus;
47
+ reasons: string[];
48
+ notices: string[];
49
+ desired: CanonicalMetaobject | CanonicalMetafield;
50
+ }
51
+ export interface Plan {
52
+ items: PlanItem[];
53
+ creates: number;
54
+ conflicts: number;
55
+ indeterminate: number;
56
+ notices: number;
57
+ }
58
+ export declare function planSchema(desired: CompiledSchema, existing: ExistingSchema): Plan;
59
+ export declare function exitCodeForPlan(plan: Plan, mode: 'dry-run' | 'check' | 'apply'): number;
60
+ //# sourceMappingURL=planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../src/planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACf,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,WAAW,CAAC,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,SAAS,CAAC;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;CACxE;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,cAAc,GAAG,SAAS,CAAC;IAC5E,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAClC,UAAU,EAAE,iBAAiB,EAAE,CAAC;CACjC;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,eAAe,CAAC;AAE7E,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,GAAG,WAAW,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CAAC;CACnD;AAED,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AA4FD,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,CAsElF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAIvF"}
@@ -0,0 +1,161 @@
1
+ function typeName(value) {
2
+ return typeof value === 'string' ? value : value.name;
3
+ }
4
+ function normalizedValue(validation) {
5
+ if (validation.name === 'choices' || validation.name.endsWith('_types') ||
6
+ validation.name.endsWith('_ids')) {
7
+ try {
8
+ const parsed = JSON.parse(validation.value);
9
+ if (Array.isArray(parsed))
10
+ return JSON.stringify([...parsed].sort());
11
+ }
12
+ catch {
13
+ return validation.value;
14
+ }
15
+ }
16
+ if (validation.name === 'json_schema') {
17
+ try {
18
+ return JSON.stringify(sortJson(JSON.parse(validation.value)));
19
+ }
20
+ catch {
21
+ return validation.value;
22
+ }
23
+ }
24
+ return validation.value;
25
+ }
26
+ function sortJson(value) {
27
+ if (Array.isArray(value))
28
+ return value.map(sortJson);
29
+ if (typeof value === 'object' && value !== null) {
30
+ return Object.fromEntries(Object.entries(value)
31
+ .sort(([a], [b]) => a.localeCompare(b))
32
+ .map(([key, item]) => [key, sortJson(item)]));
33
+ }
34
+ return value;
35
+ }
36
+ function normalizedValidations(values = []) {
37
+ return JSON.stringify(values
38
+ .map((value) => ({ name: value.name, value: normalizedValue(value) }))
39
+ .sort((a, b) => a.name.localeCompare(b.name) || a.value.localeCompare(b.value)));
40
+ }
41
+ function compareDeclared(label, desired, existing, reasons) {
42
+ if (!desired)
43
+ return;
44
+ for (const [key, expected] of Object.entries(desired)) {
45
+ const actual = existing?.[key];
46
+ if (actual !== expected)
47
+ reasons.push(`${label}.${key}: expected ${String(expected)}, found ${String(actual)}`);
48
+ }
49
+ }
50
+ function compareField(desired, existing, path) {
51
+ const reasons = [];
52
+ if (typeName(existing.type) !== desired.type) {
53
+ reasons.push(`${path}.type: expected ${desired.type}, found ${typeName(existing.type)}`);
54
+ }
55
+ if (normalizedValidations(existing.validations) !== normalizedValidations(desired.validations)) {
56
+ reasons.push(`${path}.validations differ`);
57
+ }
58
+ if (desired.required !== undefined && Boolean(existing.required) !== desired.required) {
59
+ reasons.push(`${path}.required: expected ${String(desired.required)}, found ${String(Boolean(existing.required))}`);
60
+ }
61
+ compareDeclared(`${path}.access`, desired.access, existing.access, reasons);
62
+ compareDeclared(`${path}.capabilities`, desired.capabilities, existing.capabilities, reasons);
63
+ if (desired.constraints !== undefined) {
64
+ const actual = existing.constraints
65
+ ? { key: existing.constraints.key, values: [...existing.constraints.values].sort() }
66
+ : null;
67
+ if (JSON.stringify(desired.constraints) !== JSON.stringify(actual)) {
68
+ reasons.push(`${path}.constraints differ`);
69
+ }
70
+ }
71
+ return reasons;
72
+ }
73
+ function cosmeticNotices(identity, desired, existing) {
74
+ const notices = [];
75
+ if (desired.name !== existing.name)
76
+ notices.push(`${identity}.name differs`);
77
+ if (desired.description !== undefined && desired.description !== (existing.description ?? undefined)) {
78
+ notices.push(`${identity}.description differs`);
79
+ }
80
+ return notices;
81
+ }
82
+ export function planSchema(desired, existing) {
83
+ const items = [];
84
+ const existingMetaobjects = new Map(existing.metaobjects.map((item) => [item.type, item]));
85
+ for (const definition of desired.metaobjects) {
86
+ const identity = `metaobject:${definition.type}`;
87
+ const found = existingMetaobjects.get(definition.type);
88
+ if (!found) {
89
+ items.push({ kind: 'metaobject', identity, status: 'CREATE', reasons: [], notices: [], desired: definition });
90
+ continue;
91
+ }
92
+ const reasons = [];
93
+ if (definition.displayNameKey !== undefined && definition.displayNameKey !== found.displayNameKey) {
94
+ reasons.push(`displayNameKey: expected ${definition.displayNameKey}, found ${String(found.displayNameKey)}`);
95
+ }
96
+ compareDeclared('access', definition.access, found.access, reasons);
97
+ compareDeclared('capabilities', definition.capabilities, found.capabilities, reasons);
98
+ const fields = new Map(found.fields.map((field) => [field.key, field]));
99
+ for (const field of definition.fields) {
100
+ const existingField = fields.get(field.key);
101
+ if (!existingField)
102
+ reasons.push(`fields.${field.key}: missing`);
103
+ else
104
+ reasons.push(...compareField(field, existingField, `fields.${field.key}`));
105
+ }
106
+ items.push({
107
+ kind: 'metaobject',
108
+ identity,
109
+ status: reasons.length > 0 ? 'CONFLICT' : 'PRESENT',
110
+ reasons,
111
+ notices: cosmeticNotices(identity, definition, found),
112
+ desired: definition,
113
+ });
114
+ }
115
+ const existingMetafields = new Map(existing.metafields.map((item) => [
116
+ `${item.ownerType}:${item.namespace}.${item.key}`,
117
+ item,
118
+ ]));
119
+ for (const definition of desired.metafields) {
120
+ const key = `${definition.ownerType}:${definition.namespace}.${definition.key}`;
121
+ const identity = `metafield:${key}`;
122
+ const found = existingMetafields.get(key);
123
+ if (!found) {
124
+ items.push({ kind: 'metafield', identity, status: 'CREATE', reasons: [], notices: [], desired: definition });
125
+ continue;
126
+ }
127
+ const reasons = compareField(definition, found, identity);
128
+ let status = reasons.length > 0 ? 'CONFLICT' : 'PRESENT';
129
+ if (found.validationStatus === 'SOME_INVALID') {
130
+ status = 'CONFLICT';
131
+ reasons.push(`stored values include ${String(found.invalidCount ?? 'unknown')} invalid value(s)`);
132
+ }
133
+ else if (found.validationStatus === 'IN_PROGRESS') {
134
+ status = 'INDETERMINATE';
135
+ reasons.push('stored-value validation is in progress');
136
+ }
137
+ items.push({
138
+ kind: 'metafield',
139
+ identity,
140
+ status,
141
+ reasons,
142
+ notices: cosmeticNotices(identity, definition, found),
143
+ desired: definition,
144
+ });
145
+ }
146
+ return {
147
+ items,
148
+ creates: items.filter((item) => item.status === 'CREATE').length,
149
+ conflicts: items.filter((item) => item.status === 'CONFLICT').length,
150
+ indeterminate: items.filter((item) => item.status === 'INDETERMINATE').length,
151
+ notices: items.reduce((count, item) => count + item.notices.length, 0),
152
+ };
153
+ }
154
+ export function exitCodeForPlan(plan, mode) {
155
+ if (plan.indeterminate > 0)
156
+ return 2;
157
+ if (plan.conflicts > 0 || (mode === 'check' && plan.creates > 0))
158
+ return 1;
159
+ return 0;
160
+ }
161
+ //# sourceMappingURL=planner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../src/planner.ts"],"names":[],"mappings":"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"}
package/dist/pull.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { AdminClient } from './admin.js';
2
+ import type { PulledSchema } from './generator.js';
3
+ import { type Owner } from './schema.js';
4
+ export interface PullOptions {
5
+ owners: Owner[];
6
+ namespaces: string[];
7
+ allNamespaces: boolean;
8
+ metaobjects: boolean;
9
+ }
10
+ export declare function pullSchema(client: AdminClient, options: PullOptions): Promise<PulledSchema>;
11
+ //# sourceMappingURL=pull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../src/pull.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAoC,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAqC3E,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA2DjG"}