shopify-webhook-schemas 0.3.2 → 0.3.3
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/dist/src/anonymize-exemplars.d.ts +1 -0
- package/dist/src/anonymize-exemplars.js +51 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.js +54 -0
- package/dist/src/infer-schema.d.ts +19 -0
- package/dist/src/infer-schema.js +824 -0
- package/dist/src/scrape.d.ts +1 -0
- package/dist/src/scrape.js +179 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const path_1 = __importDefault(require("path"));
|
|
7
|
+
const json_infer_types_1 = require("@jsonhero/json-infer-types");
|
|
8
|
+
const globby_1 = require("globby");
|
|
9
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
+
const traverse_1 = __importDefault(require("traverse"));
|
|
11
|
+
const main = async () => {
|
|
12
|
+
const files = await (0, globby_1.globby)(path_1.default.join(__dirname, "../exemplars/**/*.json"));
|
|
13
|
+
console.log(`anonymizing ${files.length} files`);
|
|
14
|
+
for (const file of files) {
|
|
15
|
+
let json = await fs_extra_1.default.readJSON(file);
|
|
16
|
+
json = (0, traverse_1.default)(json).map(function (value) {
|
|
17
|
+
if (typeof value == "number") {
|
|
18
|
+
return Math.round(value) == value ? 123 : 123.456;
|
|
19
|
+
}
|
|
20
|
+
else if (typeof value == "string") {
|
|
21
|
+
const type = (0, json_infer_types_1.inferType)(value);
|
|
22
|
+
if ("format" in type && type.format) {
|
|
23
|
+
switch (type.format.name) {
|
|
24
|
+
case "email": {
|
|
25
|
+
return "eallam@example.com";
|
|
26
|
+
}
|
|
27
|
+
case "date": {
|
|
28
|
+
return "2016-05-25";
|
|
29
|
+
}
|
|
30
|
+
case "datetime": {
|
|
31
|
+
return "2019-01-01 00:00:00.000Z";
|
|
32
|
+
}
|
|
33
|
+
case "uri": {
|
|
34
|
+
return "https://www.example.com/";
|
|
35
|
+
}
|
|
36
|
+
case "ip": {
|
|
37
|
+
return "192.168.0.1";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return "example string";
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
await fs_extra_1.default.writeJSON(file, json, { spaces: 2 });
|
|
48
|
+
}
|
|
49
|
+
console.log("done");
|
|
50
|
+
};
|
|
51
|
+
void main();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { inferSchemaFromExamplePayload } from "./infer-schema";
|
|
2
|
+
export { inferSchemaFromExamplePayload };
|
|
3
|
+
export declare function getPackageRootDir(): string;
|
|
4
|
+
/** Return a metadata blob from Shopify's docs describing a webhook topic */
|
|
5
|
+
export declare function metadataForWebhook(apiVersion: string, topic: string): any;
|
|
6
|
+
/** Return the inferred JSON schema describing a webhook payload */
|
|
7
|
+
export declare function schemaForWebhook(apiVersion: string, topic: string): any;
|
|
8
|
+
/** Return all the known webhook topics */
|
|
9
|
+
export declare function allTopicsForVersion(apiVersion: string): string[];
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.inferSchemaFromExamplePayload = void 0;
|
|
7
|
+
exports.getPackageRootDir = getPackageRootDir;
|
|
8
|
+
exports.metadataForWebhook = metadataForWebhook;
|
|
9
|
+
exports.schemaForWebhook = schemaForWebhook;
|
|
10
|
+
exports.allTopicsForVersion = allTopicsForVersion;
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
14
|
+
const infer_schema_1 = require("./infer-schema");
|
|
15
|
+
Object.defineProperty(exports, "inferSchemaFromExamplePayload", { enumerable: true, get: function () { return infer_schema_1.inferSchemaFromExamplePayload; } });
|
|
16
|
+
const loaded = { metadatas: {}, schemas: {} };
|
|
17
|
+
function getPackageRootDir() {
|
|
18
|
+
let currentDir = __dirname;
|
|
19
|
+
while (!fs_1.default.existsSync(path_1.default.join(currentDir, "package.json"))) {
|
|
20
|
+
currentDir = path_1.default.join(currentDir, "..");
|
|
21
|
+
}
|
|
22
|
+
return currentDir;
|
|
23
|
+
}
|
|
24
|
+
const rootDir = getPackageRootDir();
|
|
25
|
+
for (const kind of ["metadatas", "schemas"]) {
|
|
26
|
+
const dir = `${rootDir}/${kind}`;
|
|
27
|
+
for (const version of fs_1.default.readdirSync(dir)) {
|
|
28
|
+
const root = {};
|
|
29
|
+
loaded[kind][version] = root;
|
|
30
|
+
const searchPath = `${dir}/${version}/`;
|
|
31
|
+
for (const file of fast_glob_1.default.sync(`${searchPath}**/*.json`)) {
|
|
32
|
+
const topic = file.replace(searchPath, "").replace(/\.json$/, "");
|
|
33
|
+
root[topic] = JSON.parse(fs_1.default.readFileSync(file, "utf-8"));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const getVersion = (obj, version) => {
|
|
38
|
+
const value = obj[version];
|
|
39
|
+
if (value)
|
|
40
|
+
return value;
|
|
41
|
+
throw new Error(`Unknown shopify api version ${version} in shopify-webhook-schemas package -- please pass a real version or regenerate the metadata`);
|
|
42
|
+
};
|
|
43
|
+
/** Return a metadata blob from Shopify's docs describing a webhook topic */
|
|
44
|
+
function metadataForWebhook(apiVersion, topic) {
|
|
45
|
+
return getVersion(loaded.metadatas, apiVersion)[topic];
|
|
46
|
+
}
|
|
47
|
+
/** Return the inferred JSON schema describing a webhook payload */
|
|
48
|
+
function schemaForWebhook(apiVersion, topic) {
|
|
49
|
+
return getVersion(loaded.schemas, apiVersion)[topic];
|
|
50
|
+
}
|
|
51
|
+
/** Return all the known webhook topics */
|
|
52
|
+
function allTopicsForVersion(apiVersion) {
|
|
53
|
+
return Object.keys(getVersion(loaded.schemas, apiVersion));
|
|
54
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const getStartVersion: (date?: Date) => string;
|
|
2
|
+
export type Error = {
|
|
3
|
+
message: string;
|
|
4
|
+
path: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const inferSchemaFromExamplePayload: (version: string, examplePayload: Record<string, any>, metadata: {
|
|
7
|
+
name: string;
|
|
8
|
+
}) => {
|
|
9
|
+
schema: any;
|
|
10
|
+
warnings: number;
|
|
11
|
+
errors: Error[];
|
|
12
|
+
};
|
|
13
|
+
export declare const manualExamples: [RegExp, Record<string, any>][];
|
|
14
|
+
export declare const overrides: {
|
|
15
|
+
topics: string[];
|
|
16
|
+
schema: any;
|
|
17
|
+
required?: string[];
|
|
18
|
+
versions?: string[];
|
|
19
|
+
}[];
|
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.overrides = exports.manualExamples = exports.inferSchemaFromExamplePayload = exports.getStartVersion = void 0;
|
|
4
|
+
const json_schema_walker_1 = require("@cloudflare/json-schema-walker");
|
|
5
|
+
const schema_infer_1 = require("@jsonhero/schema-infer");
|
|
6
|
+
const lodash_1 = require("lodash");
|
|
7
|
+
const safe_stable_stringify_1 = require("safe-stable-stringify");
|
|
8
|
+
const stringify = (0, safe_stable_stringify_1.configure)({ deterministic: true });
|
|
9
|
+
const getStartVersion = (date = new Date()) => {
|
|
10
|
+
const year = date.getUTCFullYear();
|
|
11
|
+
const month = date.getUTCMonth() + 1; // 1-12
|
|
12
|
+
// Map month to quarter
|
|
13
|
+
let quarter;
|
|
14
|
+
if (month <= 3)
|
|
15
|
+
quarter = 1; // Jan-Mar -> Q1 (01)
|
|
16
|
+
else if (month <= 6)
|
|
17
|
+
quarter = 2; // Apr-Jun -> Q2 (04)
|
|
18
|
+
else if (month <= 9)
|
|
19
|
+
quarter = 3; // Jul-Sep -> Q3 (07)
|
|
20
|
+
else
|
|
21
|
+
quarter = 4; // Oct-Dec -> Q4 (10)
|
|
22
|
+
// Go back 3 quarters (4 quarters including current)
|
|
23
|
+
let targetYear = year;
|
|
24
|
+
let targetQuarter = quarter - 3;
|
|
25
|
+
// Handle year wraparound
|
|
26
|
+
while (targetQuarter <= 0) {
|
|
27
|
+
targetQuarter += 4;
|
|
28
|
+
targetYear -= 1;
|
|
29
|
+
}
|
|
30
|
+
// Map quarter to month string
|
|
31
|
+
const quarterToMonth = { 1: "01", 2: "04", 3: "07", 4: "10" };
|
|
32
|
+
return `${targetYear}-${quarterToMonth[targetQuarter]}`;
|
|
33
|
+
};
|
|
34
|
+
exports.getStartVersion = getStartVersion;
|
|
35
|
+
const inferSchemaFromExamplePayload = (version, examplePayload, metadata) => {
|
|
36
|
+
const inference = (0, schema_infer_1.inferSchema)(examplePayload);
|
|
37
|
+
// build a copy of the payload and apply overrides based on the webhook name
|
|
38
|
+
for (const [matcher, override] of exports.manualExamples) {
|
|
39
|
+
if (matcher.test(metadata.name)) {
|
|
40
|
+
const overridesPayload = (0, lodash_1.cloneDeep)(examplePayload);
|
|
41
|
+
const maskedOverride = (0, lodash_1.pick)(override, Object.keys(examplePayload));
|
|
42
|
+
(0, lodash_1.merge)(overridesPayload, maskedOverride);
|
|
43
|
+
inference.infer(overridesPayload);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const schema = {
|
|
47
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
48
|
+
...inference.toJSONSchema(),
|
|
49
|
+
};
|
|
50
|
+
for (const override of exports.overrides) {
|
|
51
|
+
if (override.topics.includes(metadata.name) && (!override.versions || override.versions.includes(version))) {
|
|
52
|
+
for (const [key, schemaOverride] of Object.entries(override.schema)) {
|
|
53
|
+
schema.properties ?? (schema.properties = {});
|
|
54
|
+
schema.properties[key] = schemaOverride;
|
|
55
|
+
}
|
|
56
|
+
if (override.required) {
|
|
57
|
+
schema.required = override.required;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const sortedSchema = getDeterministicObject(schema);
|
|
62
|
+
let warnings = 0;
|
|
63
|
+
const errors = [];
|
|
64
|
+
(0, json_schema_walker_1.schemaWalk)(sortedSchema, (subschema, path, _parent, parentPath) => {
|
|
65
|
+
if ((0, lodash_1.isEqual)(subschema, { type: "null" })) {
|
|
66
|
+
warnings += 1;
|
|
67
|
+
const fullPath = [...parentPath, ...path].join(".");
|
|
68
|
+
if (unknownPaths.some(([pattern, paths]) => pattern.test(metadata.name) && paths.includes(fullPath))) {
|
|
69
|
+
// we know this path is always null, so don't error
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
errors.push({
|
|
73
|
+
message: "null type found in final schema",
|
|
74
|
+
path: fullPath,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}, () => { }, (0, json_schema_walker_1.getVocabulary)(sortedSchema));
|
|
79
|
+
return { schema: sortedSchema, warnings, errors };
|
|
80
|
+
};
|
|
81
|
+
exports.inferSchemaFromExamplePayload = inferSchemaFromExamplePayload;
|
|
82
|
+
const getDeterministicObject = (obj) => {
|
|
83
|
+
const stableString = stringify(sortStringArrays(obj));
|
|
84
|
+
return JSON.parse(stableString);
|
|
85
|
+
};
|
|
86
|
+
const sortStringArrays = (obj) => {
|
|
87
|
+
return (0, lodash_1.cloneDeepWith)(obj, (value) => {
|
|
88
|
+
if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
|
|
89
|
+
return value.sort();
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
// paths that we can't find any source data for at all, so we don't know what type they should be
|
|
94
|
+
const unknownPaths = [
|
|
95
|
+
[
|
|
96
|
+
/checkouts\/.+/,
|
|
97
|
+
[
|
|
98
|
+
"properties.line_items.items.properties.unit_price_measurement.properties.measured_type",
|
|
99
|
+
"properties.line_items.items.properties.unit_price_measurement.properties.quantity_value",
|
|
100
|
+
"properties.line_items.items.properties.unit_price_measurement.properties.quantity_unit",
|
|
101
|
+
"properties.line_items.items.properties.unit_price_measurement.properties.reference_value",
|
|
102
|
+
"properties.line_items.items.properties.unit_price_measurement.properties.reference_unit",
|
|
103
|
+
"properties.line_items.items.properties.tax_lines.items.properties.reporting_jurisdiction_name",
|
|
104
|
+
"properties.line_items.items.properties.tax_lines.items.properties.reporting_jurisdiction_type",
|
|
105
|
+
"properties.line_items.items.properties.tax_lines.items.properties.reporting_jurisdiction_code",
|
|
106
|
+
"properties.line_items.items.properties.user_id",
|
|
107
|
+
"properties.line_items.items.properties.compare_at_price",
|
|
108
|
+
"properties.gateway",
|
|
109
|
+
"properties.shipping_lines.items.properties.delivery_category",
|
|
110
|
+
"properties.shipping_lines.items.properties.validation_context",
|
|
111
|
+
"properties.shipping_lines.items.properties.requested_fulfillment_service_id",
|
|
112
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.identifier",
|
|
113
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_jurisdiction_name",
|
|
114
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.tax_api_client_id",
|
|
115
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_exempt_amount",
|
|
116
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.jurisdiction_source",
|
|
117
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_jurisdiction_code",
|
|
118
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_jurisdiction_type",
|
|
119
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_taxable_amount",
|
|
120
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.jurisdiction_type",
|
|
121
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.tax_type",
|
|
122
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.jurisdiction_id",
|
|
123
|
+
"properties.shipping_lines.items.properties.tax_lines.items.properties.reporting_non_taxable_amount",
|
|
124
|
+
"properties.shipping_lines.items.properties.custom_tax_lines",
|
|
125
|
+
"properties.shipping_lines.items.properties.estimated_delivery_time_range",
|
|
126
|
+
"properties.line_items.items.properties.tax_lines.items.properties.tax_type",
|
|
127
|
+
"properties.line_items.items.properties.tax_lines.items.properties.identifier",
|
|
128
|
+
"properties.line_items.items.properties.discount_allocations.items.properties.id",
|
|
129
|
+
"properties.line_items.items.properties.discount_allocations.items.properties.created_at",
|
|
130
|
+
],
|
|
131
|
+
],
|
|
132
|
+
[
|
|
133
|
+
/collection_listings\/.+/,
|
|
134
|
+
["properties.collection_listing.properties.default_product_image", "properties.collection_listing.properties.image"],
|
|
135
|
+
],
|
|
136
|
+
[/domains\/.+/, ["properties.localization.properties.country"]],
|
|
137
|
+
[/orders\/.+/, ["properties.client_details.properties.session_hash"]],
|
|
138
|
+
];
|
|
139
|
+
// example data we feed the schema infer-er for each topic to allow it to discover real types
|
|
140
|
+
exports.manualExamples = [
|
|
141
|
+
[
|
|
142
|
+
/.+/,
|
|
143
|
+
{
|
|
144
|
+
admin_graphql_api_id: "gid://shopify/Something/1234567890",
|
|
145
|
+
admin_graphql_api_job_id: "gid://shopify/Job/1234567890",
|
|
146
|
+
created_at: "2021-12-30T19:00:00-05:00",
|
|
147
|
+
updated_at: "2021-12-30T19:00:00-05:00",
|
|
148
|
+
address2: "Apt 123",
|
|
149
|
+
latitude: 10.1,
|
|
150
|
+
longitude: 10.1,
|
|
151
|
+
location_id: 111111,
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
[
|
|
155
|
+
/(app|shop)\/.+/,
|
|
156
|
+
{
|
|
157
|
+
domain: "example.com",
|
|
158
|
+
source: "example source",
|
|
159
|
+
myshopify_domain: "example.myshopify.com",
|
|
160
|
+
google_apps_domain: "example.com",
|
|
161
|
+
google_apps_login_enabled: true,
|
|
162
|
+
password_enabled: true,
|
|
163
|
+
taxes_included: true,
|
|
164
|
+
tax_shipping: true,
|
|
165
|
+
iana_timezone: "America/New_York",
|
|
166
|
+
auto_configure_tax_inclusivity: true,
|
|
167
|
+
county_taxes: true,
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
[
|
|
171
|
+
/bulk_operations\/.+/,
|
|
172
|
+
{
|
|
173
|
+
error_code: "SOME_ERROR_ENUM",
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
[
|
|
177
|
+
/carts\/.+/,
|
|
178
|
+
{
|
|
179
|
+
note: "some cart note string",
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
[
|
|
183
|
+
/(checkouts|orders)\/.+/,
|
|
184
|
+
{
|
|
185
|
+
gateway: "shopify_payments",
|
|
186
|
+
landing_site: "https://example.com",
|
|
187
|
+
note: "some order note",
|
|
188
|
+
referring_site: "https://example.com",
|
|
189
|
+
completed_at: "2021-12-30T19:00:00-05:00",
|
|
190
|
+
closed_at: "2021-12-30T19:00:00-05:00",
|
|
191
|
+
user_id: 11111111,
|
|
192
|
+
location_id: 22222222,
|
|
193
|
+
source_identifier: "some_source_identifier",
|
|
194
|
+
source_url: "https://example.com",
|
|
195
|
+
device_id: "some_device_id",
|
|
196
|
+
phone: "+1 (123) 456 7890",
|
|
197
|
+
sms_marketing_phone: "+1 (123) 456 7890",
|
|
198
|
+
customer_locale: "en",
|
|
199
|
+
source: "some_source",
|
|
200
|
+
total_duties: 10.11,
|
|
201
|
+
app_id: 12345,
|
|
202
|
+
browser_ip: "10.0.0.1",
|
|
203
|
+
cart_token: "some_cart_token",
|
|
204
|
+
checkout_id: 12345,
|
|
205
|
+
client_details: {
|
|
206
|
+
accept_language: "en-US,en;q=0.9",
|
|
207
|
+
browser_height: 800,
|
|
208
|
+
},
|
|
209
|
+
confirmation_number: "some_confirmation_number",
|
|
210
|
+
current_total_additional_fees_set: {
|
|
211
|
+
shop_money: {
|
|
212
|
+
amount: "0.00",
|
|
213
|
+
currency_code: "USD",
|
|
214
|
+
},
|
|
215
|
+
presentment_money: {
|
|
216
|
+
amount: "0.00",
|
|
217
|
+
currency_code: "USD",
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
current_total_duties_set: {
|
|
221
|
+
shop_money: {
|
|
222
|
+
amount: "0.00",
|
|
223
|
+
currency_code: "USD",
|
|
224
|
+
},
|
|
225
|
+
presentment_money: {
|
|
226
|
+
amount: "0.00",
|
|
227
|
+
currency_code: "USD",
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
original_total_additional_fees_set: {
|
|
231
|
+
shop_money: {
|
|
232
|
+
amount: "0.00",
|
|
233
|
+
currency_code: "USD",
|
|
234
|
+
},
|
|
235
|
+
presentment_money: {
|
|
236
|
+
amount: "0.00",
|
|
237
|
+
currency_code: "USD",
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
original_total_duties_set: {
|
|
241
|
+
shop_money: {
|
|
242
|
+
amount: "0.00",
|
|
243
|
+
currency_code: "USD",
|
|
244
|
+
},
|
|
245
|
+
presentment_money: {
|
|
246
|
+
amount: "0.00",
|
|
247
|
+
currency_code: "USD",
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
checkout_token: "some_checkout_token",
|
|
251
|
+
landing_site_ref: "https://example.com",
|
|
252
|
+
merchant_of_record_app_id: 12345,
|
|
253
|
+
po_number: "some_po_number",
|
|
254
|
+
processed_at: "2021-12-30T19:00:00-05:00",
|
|
255
|
+
reference: "some_reference",
|
|
256
|
+
payment_terms: "some_payment_terms",
|
|
257
|
+
reservation_token: "some_reservation_token",
|
|
258
|
+
billing_address: {
|
|
259
|
+
address2: "suite 101",
|
|
260
|
+
latitude: 34.1,
|
|
261
|
+
longitude: 34.1,
|
|
262
|
+
},
|
|
263
|
+
shipping_address: {
|
|
264
|
+
address2: "suite 101",
|
|
265
|
+
latitude: 34.1,
|
|
266
|
+
longitude: 34.1,
|
|
267
|
+
},
|
|
268
|
+
customer: {
|
|
269
|
+
created_at: "2024-05-05T02:42:32+08:00",
|
|
270
|
+
marketing_opt_in_level: "single_opt_in",
|
|
271
|
+
note: "some string",
|
|
272
|
+
multipass_identifier: "hello",
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
[
|
|
277
|
+
/checkouts\/.+/,
|
|
278
|
+
{
|
|
279
|
+
line_items: [
|
|
280
|
+
{
|
|
281
|
+
presentment_variant_title: "51 x 76 / Blanc / 1",
|
|
282
|
+
taxable: true,
|
|
283
|
+
variant_price: "69.00",
|
|
284
|
+
presentment_title: "Taie d'oreiller Pure Soie de Mûrier",
|
|
285
|
+
requires_shipping: true,
|
|
286
|
+
unit_price_measurement: {
|
|
287
|
+
measured_type: null,
|
|
288
|
+
quantity_unit: null,
|
|
289
|
+
quantity_value: null,
|
|
290
|
+
reference_unit: null,
|
|
291
|
+
reference_value: null,
|
|
292
|
+
},
|
|
293
|
+
variant_title: "51 x 76 / Blanc / 1",
|
|
294
|
+
title: "Taie d'oreiller Pure Soie de Mûrier",
|
|
295
|
+
gift_card: false,
|
|
296
|
+
destination_location_id: 4042942054746,
|
|
297
|
+
compare_at_price: null,
|
|
298
|
+
key: "e0105d4efb1970501cf831566fa79752",
|
|
299
|
+
line_price: "69.00",
|
|
300
|
+
vendor: "Emily's pillow",
|
|
301
|
+
quantity: 1,
|
|
302
|
+
applied_discounts: [],
|
|
303
|
+
grams: 110,
|
|
304
|
+
properties: [
|
|
305
|
+
{
|
|
306
|
+
name: "_isJust",
|
|
307
|
+
value: "true",
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
tax_lines: [
|
|
311
|
+
{
|
|
312
|
+
reporting_jurisdiction_type: null,
|
|
313
|
+
reporting_non_taxable_amount: "0.00",
|
|
314
|
+
zone: null,
|
|
315
|
+
compare_at: 0.2,
|
|
316
|
+
reporting_taxable_amount: "57.50",
|
|
317
|
+
tax_api_client_id: null,
|
|
318
|
+
jurisdiction_source: "ActiveTax",
|
|
319
|
+
title: "FR TVA",
|
|
320
|
+
identifier: null,
|
|
321
|
+
jurisdiction_type: "COUNTRY",
|
|
322
|
+
reporting_jurisdiction_code: null,
|
|
323
|
+
source: "MerchantActiveTax",
|
|
324
|
+
reporting_exempt_amount: "0.00",
|
|
325
|
+
reporting_jurisdiction_name: null,
|
|
326
|
+
jurisdiction_id: "FR",
|
|
327
|
+
tax_type: null,
|
|
328
|
+
channel_liable: false,
|
|
329
|
+
price: "11.50",
|
|
330
|
+
rate: 0.2,
|
|
331
|
+
position: 1,
|
|
332
|
+
tax_calculation_price: "11.50",
|
|
333
|
+
},
|
|
334
|
+
],
|
|
335
|
+
sku: "EMIL-TO5176-22WH",
|
|
336
|
+
rank: 0,
|
|
337
|
+
user_id: null,
|
|
338
|
+
product_id: 4610455470216,
|
|
339
|
+
discount_allocations: [],
|
|
340
|
+
origin_location_id: 1743669821576,
|
|
341
|
+
fulfillment_service: "manual",
|
|
342
|
+
variant_id: 32516187029640,
|
|
343
|
+
price: "69.00",
|
|
344
|
+
},
|
|
345
|
+
],
|
|
346
|
+
},
|
|
347
|
+
],
|
|
348
|
+
[
|
|
349
|
+
/collections\/.+/,
|
|
350
|
+
{
|
|
351
|
+
sort_order: "manual",
|
|
352
|
+
template_suffix: "some_template_suffix",
|
|
353
|
+
},
|
|
354
|
+
],
|
|
355
|
+
[
|
|
356
|
+
/collection_listings\/.+/,
|
|
357
|
+
{
|
|
358
|
+
collection_listing: {
|
|
359
|
+
updated_at: "2021-12-30T19:00:00-05:00",
|
|
360
|
+
sort_order: 1,
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
],
|
|
364
|
+
[
|
|
365
|
+
/company_locations\/.+/,
|
|
366
|
+
{
|
|
367
|
+
buyer_experience_configuration: { pay_now_only: true },
|
|
368
|
+
billing_address: {
|
|
369
|
+
address2: "suite 101",
|
|
370
|
+
},
|
|
371
|
+
shipping_address: {
|
|
372
|
+
address2: "suite 101",
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
],
|
|
376
|
+
[
|
|
377
|
+
/customers\/.+/,
|
|
378
|
+
{
|
|
379
|
+
last_order_id: 12345,
|
|
380
|
+
multipass_identifier: "some_multipass_identifier",
|
|
381
|
+
last_order_name: "Foobar",
|
|
382
|
+
phone: "+1 (123) 456 7890",
|
|
383
|
+
sms_marketing_consent: false,
|
|
384
|
+
email_marketing_consent: false,
|
|
385
|
+
accepts_marketing_updated_at: "2021-12-30T19:00:00-05:00",
|
|
386
|
+
marketing_opt_in_level: "single_opt_in",
|
|
387
|
+
},
|
|
388
|
+
],
|
|
389
|
+
[
|
|
390
|
+
/customer_account_settings\/.+/,
|
|
391
|
+
{
|
|
392
|
+
url: "https://example.com",
|
|
393
|
+
},
|
|
394
|
+
],
|
|
395
|
+
[
|
|
396
|
+
/customer.+consent\/.+/,
|
|
397
|
+
{
|
|
398
|
+
phone: "+1 (123) 456 7890",
|
|
399
|
+
email_address: "test@test.com",
|
|
400
|
+
},
|
|
401
|
+
],
|
|
402
|
+
[
|
|
403
|
+
/disputes\/.+/,
|
|
404
|
+
{
|
|
405
|
+
evidence_sent_on: "2021-12-30T19:00:00-05:00",
|
|
406
|
+
finalized_on: "2021-12-30T19:00:00-05:00",
|
|
407
|
+
},
|
|
408
|
+
],
|
|
409
|
+
[
|
|
410
|
+
/draft_orders\/.+/,
|
|
411
|
+
{
|
|
412
|
+
invoice_sent_at: "2021-12-30T19:00:00-05:00",
|
|
413
|
+
order_id: 12345,
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
[
|
|
417
|
+
/fulfillment_events\/.+/,
|
|
418
|
+
{
|
|
419
|
+
city: "Ottawa",
|
|
420
|
+
province: "ON",
|
|
421
|
+
zip: "K1P1J1",
|
|
422
|
+
address1: "150 Elgin St",
|
|
423
|
+
estimated_delivery_at: "2021-12-30T19:00:00-05:00",
|
|
424
|
+
},
|
|
425
|
+
],
|
|
426
|
+
[
|
|
427
|
+
/fulfillment_orders\/.+/,
|
|
428
|
+
{
|
|
429
|
+
remaining_fulfillment_order: {
|
|
430
|
+
id: 5859333242902,
|
|
431
|
+
shop_id: 20978040854,
|
|
432
|
+
order_id: 4804938989590,
|
|
433
|
+
assigned_location_id: 67794436118,
|
|
434
|
+
request_status: "unsubmitted",
|
|
435
|
+
status: "open",
|
|
436
|
+
supported_actions: ["request_fulfillment", "hold", "move"],
|
|
437
|
+
destination: {
|
|
438
|
+
id: 5479404371990,
|
|
439
|
+
address1: "23 Hassall Street",
|
|
440
|
+
address2: "",
|
|
441
|
+
city: "Parramatta",
|
|
442
|
+
company: null,
|
|
443
|
+
country: "Australia",
|
|
444
|
+
email: "",
|
|
445
|
+
first_name: "Tyler",
|
|
446
|
+
last_name: "Kelleher",
|
|
447
|
+
phone: null,
|
|
448
|
+
province: "New South Wales",
|
|
449
|
+
zip: "2150",
|
|
450
|
+
},
|
|
451
|
+
line_items: [
|
|
452
|
+
{
|
|
453
|
+
id: 12675478814742,
|
|
454
|
+
shop_id: 20978040854,
|
|
455
|
+
fulfillment_order_id: 5859333242902,
|
|
456
|
+
quantity: 1,
|
|
457
|
+
line_item_id: 12553770336278,
|
|
458
|
+
inventory_item_id: 44276125368342,
|
|
459
|
+
fulfillable_quantity: 1,
|
|
460
|
+
variant_id: 42182036422678,
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
fulfill_at: "2022-10-13T13:00:00-04:00",
|
|
464
|
+
fulfill_by: null,
|
|
465
|
+
international_duties: {
|
|
466
|
+
incoterm: "DAP",
|
|
467
|
+
},
|
|
468
|
+
fulfillment_holds: [],
|
|
469
|
+
delivery_method: {
|
|
470
|
+
id: 140816351254,
|
|
471
|
+
method_type: "shipping",
|
|
472
|
+
min_delivery_date_time: null,
|
|
473
|
+
max_delivery_date_time: null,
|
|
474
|
+
},
|
|
475
|
+
assigned_location: {
|
|
476
|
+
address1: null,
|
|
477
|
+
address2: null,
|
|
478
|
+
city: null,
|
|
479
|
+
country_code: "CA",
|
|
480
|
+
location_id: 67794436118,
|
|
481
|
+
name: "test-created-via-api-2",
|
|
482
|
+
phone: null,
|
|
483
|
+
province: null,
|
|
484
|
+
zip: null,
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
],
|
|
489
|
+
[
|
|
490
|
+
/fulfillments\/.+/,
|
|
491
|
+
{
|
|
492
|
+
service: "manual",
|
|
493
|
+
shipment_status: "confirmed",
|
|
494
|
+
origin_address: {
|
|
495
|
+
first_name: "Steve",
|
|
496
|
+
address1: "123 Shipping Street",
|
|
497
|
+
phone: "555-555-SHIP",
|
|
498
|
+
city: "Shippington",
|
|
499
|
+
zip: "40003",
|
|
500
|
+
province: "Kentucky",
|
|
501
|
+
country: "United States",
|
|
502
|
+
last_name: "Shipper",
|
|
503
|
+
address2: null,
|
|
504
|
+
company: "Shipping Company",
|
|
505
|
+
latitude: null,
|
|
506
|
+
longitude: null,
|
|
507
|
+
name: "Steve Shipper",
|
|
508
|
+
country_code: "US",
|
|
509
|
+
province_code: "KY",
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
],
|
|
513
|
+
[
|
|
514
|
+
/inventory_items\/.+/,
|
|
515
|
+
{
|
|
516
|
+
cost: 10.11,
|
|
517
|
+
country_code_of_origin: "CA",
|
|
518
|
+
province_code_of_origin: "CA",
|
|
519
|
+
harmonized_system_code: "1234567890",
|
|
520
|
+
},
|
|
521
|
+
],
|
|
522
|
+
[
|
|
523
|
+
/inventory_levels\/.+/,
|
|
524
|
+
{
|
|
525
|
+
available: 10,
|
|
526
|
+
},
|
|
527
|
+
],
|
|
528
|
+
[
|
|
529
|
+
/order_transactions\/.+/,
|
|
530
|
+
{
|
|
531
|
+
message: "some message from the gateway",
|
|
532
|
+
user_id: 12345,
|
|
533
|
+
parent_id: 12345,
|
|
534
|
+
processed_at: "2021-12-30T19:00:00-05:00",
|
|
535
|
+
device_id: "some_device_id",
|
|
536
|
+
error_code: "SOME_ERROR_ENUM",
|
|
537
|
+
},
|
|
538
|
+
],
|
|
539
|
+
[
|
|
540
|
+
/orders\/risk_assessment.+/,
|
|
541
|
+
{
|
|
542
|
+
provider_id: 12345,
|
|
543
|
+
provider_title: "whatever",
|
|
544
|
+
},
|
|
545
|
+
],
|
|
546
|
+
[
|
|
547
|
+
/products\/.+/,
|
|
548
|
+
{
|
|
549
|
+
template_suffix: "something",
|
|
550
|
+
image: "gid://shopify/ProductImage/1234567890",
|
|
551
|
+
},
|
|
552
|
+
],
|
|
553
|
+
[
|
|
554
|
+
/refunds\/.+/,
|
|
555
|
+
{
|
|
556
|
+
return: "unknown",
|
|
557
|
+
},
|
|
558
|
+
],
|
|
559
|
+
[
|
|
560
|
+
/selling_plan_groups\/.+/,
|
|
561
|
+
{
|
|
562
|
+
app_id: 12345,
|
|
563
|
+
description: "some description",
|
|
564
|
+
position: 1,
|
|
565
|
+
},
|
|
566
|
+
],
|
|
567
|
+
[
|
|
568
|
+
/subscription_billing_attempts\/.+/,
|
|
569
|
+
{
|
|
570
|
+
id: 12345,
|
|
571
|
+
error_message: "some error message",
|
|
572
|
+
error_code: "some error copde",
|
|
573
|
+
},
|
|
574
|
+
],
|
|
575
|
+
[
|
|
576
|
+
/subscription_billing_cycle.+/,
|
|
577
|
+
{
|
|
578
|
+
contract_edit: "some contract edit",
|
|
579
|
+
},
|
|
580
|
+
],
|
|
581
|
+
[
|
|
582
|
+
/tender_transactions\/.+/,
|
|
583
|
+
{
|
|
584
|
+
user_id: 12345,
|
|
585
|
+
processed_at: "2021-12-30T19:00:00-05:00",
|
|
586
|
+
payment_details: { something: "true" },
|
|
587
|
+
},
|
|
588
|
+
],
|
|
589
|
+
];
|
|
590
|
+
const shippingAddress = {
|
|
591
|
+
type: "object",
|
|
592
|
+
properties: {
|
|
593
|
+
first_name: {
|
|
594
|
+
type: "string",
|
|
595
|
+
},
|
|
596
|
+
address1: {
|
|
597
|
+
type: "string",
|
|
598
|
+
},
|
|
599
|
+
phone: {
|
|
600
|
+
type: "string",
|
|
601
|
+
},
|
|
602
|
+
city: {
|
|
603
|
+
type: "string",
|
|
604
|
+
},
|
|
605
|
+
zip: {
|
|
606
|
+
type: "string",
|
|
607
|
+
},
|
|
608
|
+
province: {
|
|
609
|
+
type: "string",
|
|
610
|
+
},
|
|
611
|
+
country: {
|
|
612
|
+
type: "string",
|
|
613
|
+
},
|
|
614
|
+
last_name: {
|
|
615
|
+
type: "string",
|
|
616
|
+
},
|
|
617
|
+
address2: {
|
|
618
|
+
type: ["string", "null"],
|
|
619
|
+
},
|
|
620
|
+
company: {
|
|
621
|
+
type: ["string", "null"],
|
|
622
|
+
},
|
|
623
|
+
latitude: {
|
|
624
|
+
type: ["number", "null"],
|
|
625
|
+
},
|
|
626
|
+
longitude: {
|
|
627
|
+
type: ["number", "null"],
|
|
628
|
+
},
|
|
629
|
+
name: {
|
|
630
|
+
type: "string",
|
|
631
|
+
},
|
|
632
|
+
country_code: {
|
|
633
|
+
type: "string",
|
|
634
|
+
},
|
|
635
|
+
province_code: {
|
|
636
|
+
type: "string",
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
};
|
|
640
|
+
exports.overrides = [
|
|
641
|
+
{
|
|
642
|
+
topics: ["checkouts/create", "checkouts/update"],
|
|
643
|
+
schema: {
|
|
644
|
+
shipping_address: shippingAddress,
|
|
645
|
+
},
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
topics: ["orders/create", "orders/updated", "orders/cancelled", "orders/fulfilled", "orders/paid", "orders/partially_fulfilled"],
|
|
649
|
+
schema: {
|
|
650
|
+
company: {
|
|
651
|
+
type: ["object", "null"],
|
|
652
|
+
properties: {
|
|
653
|
+
id: { type: "integer" },
|
|
654
|
+
location_id: { type: "integer" },
|
|
655
|
+
},
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
topics: ["order_transactions/create", "order_transactions/update"],
|
|
661
|
+
schema: {
|
|
662
|
+
receipt: {
|
|
663
|
+
type: "object",
|
|
664
|
+
additionalProperties: true,
|
|
665
|
+
},
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
topics: ["collections/create", "collections/update"],
|
|
670
|
+
schema: {
|
|
671
|
+
image: {
|
|
672
|
+
type: "object",
|
|
673
|
+
properties: {
|
|
674
|
+
alt: { type: "string" },
|
|
675
|
+
created_at: { type: "string" },
|
|
676
|
+
height: { type: "number" },
|
|
677
|
+
src: { type: "string" },
|
|
678
|
+
width: { type: "number" },
|
|
679
|
+
},
|
|
680
|
+
},
|
|
681
|
+
rules: {
|
|
682
|
+
type: "array",
|
|
683
|
+
items: {
|
|
684
|
+
type: "object",
|
|
685
|
+
properties: {
|
|
686
|
+
column: { type: "string" },
|
|
687
|
+
relation: { type: "string" },
|
|
688
|
+
condition: { type: "string" },
|
|
689
|
+
},
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
disjunctive: { type: "boolean" },
|
|
693
|
+
},
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
topics: ["fulfillments/create", "fulfillments/update"],
|
|
697
|
+
schema: {
|
|
698
|
+
origin_address: {
|
|
699
|
+
address1: { type: "string" },
|
|
700
|
+
city: { type: "string" },
|
|
701
|
+
country_code: { type: "string" },
|
|
702
|
+
province_code: { type: "string" },
|
|
703
|
+
zip: { type: "string" },
|
|
704
|
+
},
|
|
705
|
+
},
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
topics: ["products/create", "products/update"],
|
|
709
|
+
schema: {
|
|
710
|
+
image: {
|
|
711
|
+
properties: {
|
|
712
|
+
admin_graphql_api_id: {
|
|
713
|
+
format: "uri",
|
|
714
|
+
type: "string",
|
|
715
|
+
},
|
|
716
|
+
alt: {
|
|
717
|
+
type: ["string", "null"],
|
|
718
|
+
},
|
|
719
|
+
created_at: {
|
|
720
|
+
format: "date-time",
|
|
721
|
+
type: "string",
|
|
722
|
+
},
|
|
723
|
+
height: {
|
|
724
|
+
type: "integer",
|
|
725
|
+
},
|
|
726
|
+
id: {
|
|
727
|
+
type: "integer",
|
|
728
|
+
},
|
|
729
|
+
position: {
|
|
730
|
+
type: "integer",
|
|
731
|
+
},
|
|
732
|
+
product_id: {
|
|
733
|
+
type: "integer",
|
|
734
|
+
},
|
|
735
|
+
src: {
|
|
736
|
+
format: "uri",
|
|
737
|
+
type: "string",
|
|
738
|
+
},
|
|
739
|
+
updated_at: {
|
|
740
|
+
format: "date-time",
|
|
741
|
+
type: "string",
|
|
742
|
+
},
|
|
743
|
+
variant_ids: {
|
|
744
|
+
items: {
|
|
745
|
+
type: "integer",
|
|
746
|
+
},
|
|
747
|
+
type: "array",
|
|
748
|
+
},
|
|
749
|
+
width: {
|
|
750
|
+
type: "integer",
|
|
751
|
+
},
|
|
752
|
+
},
|
|
753
|
+
required: [
|
|
754
|
+
"admin_graphql_api_id",
|
|
755
|
+
"alt",
|
|
756
|
+
"created_at",
|
|
757
|
+
"height",
|
|
758
|
+
"id",
|
|
759
|
+
"position",
|
|
760
|
+
"product_id",
|
|
761
|
+
"src",
|
|
762
|
+
"updated_at",
|
|
763
|
+
"variant_ids",
|
|
764
|
+
"width",
|
|
765
|
+
],
|
|
766
|
+
type: "object",
|
|
767
|
+
},
|
|
768
|
+
},
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
topics: ["inventory_levels/connect", "inventory_levels/update"],
|
|
772
|
+
schema: {
|
|
773
|
+
admin_graphql_api_id: {
|
|
774
|
+
format: "uri",
|
|
775
|
+
type: "string",
|
|
776
|
+
},
|
|
777
|
+
available: {
|
|
778
|
+
type: ["integer", "null"],
|
|
779
|
+
},
|
|
780
|
+
inventory_item_id: {
|
|
781
|
+
type: "integer",
|
|
782
|
+
},
|
|
783
|
+
location_id: {
|
|
784
|
+
type: "integer",
|
|
785
|
+
},
|
|
786
|
+
updated_at: {
|
|
787
|
+
format: "date-time",
|
|
788
|
+
type: "string",
|
|
789
|
+
},
|
|
790
|
+
},
|
|
791
|
+
required: ["admin_graphql_api_id", "available", "inventory_item_id", "location_id", "updated_at"],
|
|
792
|
+
},
|
|
793
|
+
{
|
|
794
|
+
topics: ["shipping_addresses/create", "shipping_addresses/update"],
|
|
795
|
+
schema: {
|
|
796
|
+
...shippingAddress.properties,
|
|
797
|
+
},
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
topics: ["refunds/create"],
|
|
801
|
+
schema: {
|
|
802
|
+
return: {
|
|
803
|
+
anyOf: [
|
|
804
|
+
{
|
|
805
|
+
type: "null",
|
|
806
|
+
},
|
|
807
|
+
{
|
|
808
|
+
properties: {
|
|
809
|
+
admin_graphql_api_id: {
|
|
810
|
+
format: "uri",
|
|
811
|
+
type: "string",
|
|
812
|
+
},
|
|
813
|
+
id: {
|
|
814
|
+
type: "integer",
|
|
815
|
+
},
|
|
816
|
+
},
|
|
817
|
+
required: ["admin_graphql_api_id", "id"],
|
|
818
|
+
type: "object",
|
|
819
|
+
},
|
|
820
|
+
],
|
|
821
|
+
},
|
|
822
|
+
},
|
|
823
|
+
},
|
|
824
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
7
|
+
const globby_1 = require("globby");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const src_1 = require("src");
|
|
11
|
+
const infer_schema_1 = require("./infer-schema");
|
|
12
|
+
function assert(value, message) {
|
|
13
|
+
if (!value) {
|
|
14
|
+
throw new Error(message ?? "value is not truthy");
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
const dataUrl = "https://shopify.dev/docs/api/webhooks.data";
|
|
19
|
+
const dataUrlForVersion = (version) => `https://shopify.dev/docs/api/webhooks/${version}.data`;
|
|
20
|
+
let warnings = 0;
|
|
21
|
+
let errors = 0;
|
|
22
|
+
const loadExemplars = async () => {
|
|
23
|
+
const files = await (0, globby_1.globby)(path_1.default.join(__dirname, "../exemplars/**/*.json"));
|
|
24
|
+
for (const file of files) {
|
|
25
|
+
const segments = file.split(path_1.default.sep);
|
|
26
|
+
const _filename = segments.pop();
|
|
27
|
+
const topicPattern = new RegExp(`${segments.pop()}.+`);
|
|
28
|
+
const _version = segments.pop();
|
|
29
|
+
const exemplar = await fs_extra_1.default.readJSON(file);
|
|
30
|
+
infer_schema_1.manualExamples.push([topicPattern, exemplar]);
|
|
31
|
+
}
|
|
32
|
+
console.log(`loaded ${files.length} exemplars`);
|
|
33
|
+
};
|
|
34
|
+
const loadDataFromUrl = async (url) => {
|
|
35
|
+
const res = await fetch(url, { headers: { accept: "application/json" } });
|
|
36
|
+
if (!res.ok) {
|
|
37
|
+
console.error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
const flat = await res.json();
|
|
41
|
+
// Handle redirect responses (e.g., 2026-01 redirects to /latest)
|
|
42
|
+
if (Array.isArray(flat) && flat[0]?.[0] === "SingleFetchRedirect") {
|
|
43
|
+
console.log(`URL redirected, trying /latest endpoint...`);
|
|
44
|
+
const latestUrl = url.replace(/\/[^/]+\.data$/, "/latest.data");
|
|
45
|
+
return await loadDataFromUrl(latestUrl);
|
|
46
|
+
}
|
|
47
|
+
return inflateShopifyData(flat);
|
|
48
|
+
};
|
|
49
|
+
const inflateShopifyData = (flat) => {
|
|
50
|
+
const cache = new Map();
|
|
51
|
+
const fromIndex = (i) => {
|
|
52
|
+
if (!Number.isInteger(i)) {
|
|
53
|
+
return i;
|
|
54
|
+
}
|
|
55
|
+
if (cache.has(i))
|
|
56
|
+
return cache.get(i);
|
|
57
|
+
const val = flat[i];
|
|
58
|
+
const out = deref(val);
|
|
59
|
+
cache.set(i, out);
|
|
60
|
+
return out;
|
|
61
|
+
};
|
|
62
|
+
const deref = (x) => {
|
|
63
|
+
if (typeof x === "number") {
|
|
64
|
+
return fromIndex(x);
|
|
65
|
+
}
|
|
66
|
+
if (Array.isArray(x)) {
|
|
67
|
+
return x.map(deref);
|
|
68
|
+
}
|
|
69
|
+
if (x && typeof x === "object") {
|
|
70
|
+
const out = {};
|
|
71
|
+
for (const [k, v] of Object.entries(x)) {
|
|
72
|
+
if (k.startsWith("_")) {
|
|
73
|
+
const keyIdx = Number(k.slice(1));
|
|
74
|
+
const key = fromIndex(keyIdx);
|
|
75
|
+
out[key] = deref(v);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
out[k] = deref(v);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
return x;
|
|
84
|
+
};
|
|
85
|
+
return fromIndex(0);
|
|
86
|
+
};
|
|
87
|
+
const findFirstByPredicate = (node, predicate) => {
|
|
88
|
+
if (node && typeof node === "object") {
|
|
89
|
+
if (Array.isArray(node)) {
|
|
90
|
+
for (const child of node) {
|
|
91
|
+
const result = findFirstByPredicate(child, predicate);
|
|
92
|
+
if (result !== null)
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
if (predicate(node)) {
|
|
98
|
+
return node;
|
|
99
|
+
}
|
|
100
|
+
for (const value of Object.values(node)) {
|
|
101
|
+
const result = findFirstByPredicate(value, predicate);
|
|
102
|
+
if (result !== null)
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
};
|
|
109
|
+
const findFirstByKey = (node, keyName) => {
|
|
110
|
+
return findFirstByPredicate(node, (node) => Object.prototype.hasOwnProperty.call(node, keyName))?.[keyName];
|
|
111
|
+
};
|
|
112
|
+
const getAllVersions = async () => {
|
|
113
|
+
const data = await loadDataFromUrl(dataUrl);
|
|
114
|
+
const selectableVersions = findFirstByKey(data, "selectableVersions");
|
|
115
|
+
if (!selectableVersions || !Array.isArray(selectableVersions.default.values)) {
|
|
116
|
+
throw new Error("selectableVersions not found or is not an array");
|
|
117
|
+
}
|
|
118
|
+
return selectableVersions.default.values.filter((v) => v != "unstable");
|
|
119
|
+
};
|
|
120
|
+
const main = async () => {
|
|
121
|
+
await loadExemplars();
|
|
122
|
+
const rootDir = (0, src_1.getPackageRootDir)();
|
|
123
|
+
const versions = process.env.VERSION ? [process.env.VERSION] : await getAllVersions();
|
|
124
|
+
for (const version of versions) {
|
|
125
|
+
console.log(`Loading webhooks for version ${version}`);
|
|
126
|
+
const data = await loadDataFromUrl(dataUrlForVersion(version));
|
|
127
|
+
const webhooksAccordian = findFirstByPredicate(data, (node) => node.type === "WebhooksAccordion" && node.anchorLink === "list-of-topics");
|
|
128
|
+
const webhookContent = assert(webhooksAccordian.accordionContent);
|
|
129
|
+
for (const webhookNode of webhookContent) {
|
|
130
|
+
const examplePayload = webhookNode.codeblock?.tabs?.[0]?.code;
|
|
131
|
+
let response = {};
|
|
132
|
+
if (!examplePayload) {
|
|
133
|
+
console.warn(`${webhookNode.title} has no payload`);
|
|
134
|
+
warnings += 1;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
const parsedPayload = JSON.parse(examplePayload);
|
|
138
|
+
if (!parsedPayload) {
|
|
139
|
+
console.warn(`${webhookNode.title} has a null payload`);
|
|
140
|
+
warnings += 1;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
response = parsedPayload;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const webhook = {
|
|
147
|
+
access_scopes: webhookNode.accessScopes,
|
|
148
|
+
available_on: webhookNode.availableOn,
|
|
149
|
+
deprecated: !!webhookNode.webhookNotices?.find((notice) => notice.type === "deprecated"),
|
|
150
|
+
description: webhookNode.description,
|
|
151
|
+
name: webhookNode.title,
|
|
152
|
+
pii: webhookNode.pii,
|
|
153
|
+
related_resource: webhookNode.relatedResource,
|
|
154
|
+
response,
|
|
155
|
+
shop_feature: !!webhookNode.webhookNotices?.find((notice) => notice.type === "shop_feature"),
|
|
156
|
+
};
|
|
157
|
+
const metadataFile = path_1.default.join(rootDir, "metadatas", version, webhook.name + ".json");
|
|
158
|
+
await fs_extra_1.default.mkdir(path_1.default.dirname(metadataFile), { recursive: true });
|
|
159
|
+
await fs_extra_1.default.writeFile(metadataFile, JSON.stringify(webhook, null, 2), "utf-8");
|
|
160
|
+
const { schema, warnings: warningCount, errors: errorMessages } = (0, infer_schema_1.inferSchemaFromExamplePayload)(version, webhook.response, webhook);
|
|
161
|
+
warnings += warningCount;
|
|
162
|
+
for (const error of errorMessages) {
|
|
163
|
+
console.error(`${chalk_1.default.red("schema error")}: ${error.message} for version ${chalk_1.default.blue(version)} for ${chalk_1.default.blue(webhook.name)} at path ${chalk_1.default.green(error.path)}`);
|
|
164
|
+
errors += 1;
|
|
165
|
+
}
|
|
166
|
+
const schemaFile = path_1.default.join(rootDir, "schemas", version, webhook.name + ".json");
|
|
167
|
+
await fs_extra_1.default.mkdir(path_1.default.dirname(schemaFile), { recursive: true });
|
|
168
|
+
await fs_extra_1.default.writeFile(schemaFile, JSON.stringify(schema, null, 2), "utf-8");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (warnings > 0 || errors > 0) {
|
|
172
|
+
console.log(`Done with ${warnings} warnings and ${errors} errors`);
|
|
173
|
+
process.exitCode = 1;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
console.log(`Done`);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
void main();
|