94 lines
2.7 KiB
TypeScript
94 lines
2.7 KiB
TypeScript
type GraphqlResponse<T> = {
|
|
data?: T;
|
|
errors?: unknown;
|
|
};
|
|
|
|
type UserError = {
|
|
field?: string[];
|
|
message: string;
|
|
};
|
|
|
|
const shop = requiredEnv("SHOPIFY_SHOP_DOMAIN");
|
|
const token = requiredEnv("SHOPIFY_ADMIN_ACCESS_TOKEN");
|
|
const metaobjectType = process.env.METAOBJECT_TYPE || "$app:dreame_activity";
|
|
const metaobjectHandle = process.env.METAOBJECT_HANDLE || "dreame-activity-config";
|
|
const endpoint = `https://${shop}/admin/api/2026-01/graphql.json`;
|
|
|
|
const metaobjectMutation = `#graphql
|
|
mutation DreameMetaobjectUpsert($handle: MetaobjectHandleInput!, $metaobject: MetaobjectUpsertInput!) {
|
|
metaobjectUpsert(handle: $handle, metaobject: $metaobject) {
|
|
metaobject {
|
|
id
|
|
handle
|
|
}
|
|
userErrors {
|
|
field
|
|
message
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
|
|
async function main() {
|
|
const result = await graphql<{
|
|
metaobjectUpsert?: {
|
|
userErrors: UserError[];
|
|
};
|
|
}>(metaobjectMutation, {
|
|
handle: {
|
|
type: metaobjectType,
|
|
handle: metaobjectHandle,
|
|
},
|
|
metaobject: {
|
|
fields: [
|
|
{ key: "activity_id", value: "12" },
|
|
{ key: "api_app_id", value: "mock-app-id" },
|
|
{ key: "api_secret", value: "mock-secret" },
|
|
{ key: "status_api_url", value: "https://third-party.example/status" },
|
|
{ key: "push_api_url", value: "https://third-party.example/push" },
|
|
{ key: "status_success_code", value: "0" },
|
|
{ key: "status_active_required", value: "true" },
|
|
{ key: "push_success_code", value: "0" },
|
|
{ key: "redirect_url", value: "https://activity.example.com" },
|
|
{ key: "button_text", value: JSON.stringify({ en: "Claim Your Reward", "zh-CN": "领取奖励" }) },
|
|
{ key: "shop", value: shop },
|
|
],
|
|
},
|
|
});
|
|
|
|
const userErrors = result.data?.metaobjectUpsert?.userErrors || [];
|
|
if (userErrors.length) {
|
|
throw new Error(JSON.stringify(userErrors));
|
|
}
|
|
}
|
|
|
|
async function graphql<T>(query: string, variables: Record<string, unknown>): Promise<GraphqlResponse<T>> {
|
|
const response = await fetch(endpoint, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"X-Shopify-Access-Token": token,
|
|
},
|
|
body: JSON.stringify({ query, variables }),
|
|
});
|
|
const payload = (await response.json()) as GraphqlResponse<T>;
|
|
if (!response.ok || payload.errors) {
|
|
throw new Error(JSON.stringify(payload.errors || payload));
|
|
}
|
|
console.log(JSON.stringify(payload, null, 2));
|
|
return payload;
|
|
}
|
|
|
|
function requiredEnv(name: string): string {
|
|
const value = process.env[name];
|
|
if (!value) {
|
|
throw new Error(`${name} is required`);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error(error);
|
|
process.exit(1);
|
|
});
|