@sane-shopify/sync-utils
Version:
Syncing utility for Node & the browser
1,153 lines (1,139 loc) • 158 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var unwindEdges = require('@good-idea/unwind-edges');
var createSanityClient = _interopDefault(require('@sanity/client'));
var PQueue = _interopDefault(require('p-queue'));
var xstate = require('xstate');
var types = require('@sane-shopify/types');
var Debug = _interopDefault(require('debug'));
var fetch = _interopDefault(require('cross-fetch'));
var LeakyBucket = _interopDefault(require('@good-idea/leaky-bucket'));
var gql = _interopDefault(require('graphql-tag'));
var deepMerge = _interopDefault(require('deepmerge'));
var lodash = require('lodash');
function _regeneratorRuntime() {
_regeneratorRuntime = function () {
return exports;
};
var exports = {},
Op = Object.prototype,
hasOwn = Op.hasOwnProperty,
defineProperty = Object.defineProperty || function (obj, key, desc) {
obj[key] = desc.value;
},
$Symbol = "function" == typeof Symbol ? Symbol : {},
iteratorSymbol = $Symbol.iterator || "@@iterator",
asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator",
toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
function define(obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
enumerable: !0,
configurable: !0,
writable: !0
}), obj[key];
}
try {
define({}, "");
} catch (err) {
define = function (obj, key, value) {
return obj[key] = value;
};
}
function wrap(innerFn, outerFn, self, tryLocsList) {
var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator,
generator = Object.create(protoGenerator.prototype),
context = new Context(tryLocsList || []);
return defineProperty(generator, "_invoke", {
value: makeInvokeMethod(innerFn, self, context)
}), generator;
}
function tryCatch(fn, obj, arg) {
try {
return {
type: "normal",
arg: fn.call(obj, arg)
};
} catch (err) {
return {
type: "throw",
arg: err
};
}
}
exports.wrap = wrap;
var ContinueSentinel = {};
function Generator() {}
function GeneratorFunction() {}
function GeneratorFunctionPrototype() {}
var IteratorPrototype = {};
define(IteratorPrototype, iteratorSymbol, function () {
return this;
});
var getProto = Object.getPrototypeOf,
NativeIteratorPrototype = getProto && getProto(getProto(values([])));
NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype);
var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
function defineIteratorMethods(prototype) {
["next", "throw", "return"].forEach(function (method) {
define(prototype, method, function (arg) {
return this._invoke(method, arg);
});
});
}
function AsyncIterator(generator, PromiseImpl) {
function invoke(method, arg, resolve, reject) {
var record = tryCatch(generator[method], generator, arg);
if ("throw" !== record.type) {
var result = record.arg,
value = result.value;
return value && "object" == typeof value && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) {
invoke("next", value, resolve, reject);
}, function (err) {
invoke("throw", err, resolve, reject);
}) : PromiseImpl.resolve(value).then(function (unwrapped) {
result.value = unwrapped, resolve(result);
}, function (error) {
return invoke("throw", error, resolve, reject);
});
}
reject(record.arg);
}
var previousPromise;
defineProperty(this, "_invoke", {
value: function (method, arg) {
function callInvokeWithMethodAndArg() {
return new PromiseImpl(function (resolve, reject) {
invoke(method, arg, resolve, reject);
});
}
return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
}
});
}
function makeInvokeMethod(innerFn, self, context) {
var state = "suspendedStart";
return function (method, arg) {
if ("executing" === state) throw new Error("Generator is already running");
if ("completed" === state) {
if ("throw" === method) throw arg;
return doneResult();
}
for (context.method = method, context.arg = arg;;) {
var delegate = context.delegate;
if (delegate) {
var delegateResult = maybeInvokeDelegate(delegate, context);
if (delegateResult) {
if (delegateResult === ContinueSentinel) continue;
return delegateResult;
}
}
if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) {
if ("suspendedStart" === state) throw state = "completed", context.arg;
context.dispatchException(context.arg);
} else "return" === context.method && context.abrupt("return", context.arg);
state = "executing";
var record = tryCatch(innerFn, self, context);
if ("normal" === record.type) {
if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue;
return {
value: record.arg,
done: context.done
};
}
"throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg);
}
};
}
function maybeInvokeDelegate(delegate, context) {
var methodName = context.method,
method = delegate.iterator[methodName];
if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator.return && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel;
var record = tryCatch(method, delegate.iterator, context.arg);
if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel;
var info = record.arg;
return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel);
}
function pushTryEntry(locs) {
var entry = {
tryLoc: locs[0]
};
1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry);
}
function resetTryEntry(entry) {
var record = entry.completion || {};
record.type = "normal", delete record.arg, entry.completion = record;
}
function Context(tryLocsList) {
this.tryEntries = [{
tryLoc: "root"
}], tryLocsList.forEach(pushTryEntry, this), this.reset(!0);
}
function values(iterable) {
if (iterable) {
var iteratorMethod = iterable[iteratorSymbol];
if (iteratorMethod) return iteratorMethod.call(iterable);
if ("function" == typeof iterable.next) return iterable;
if (!isNaN(iterable.length)) {
var i = -1,
next = function next() {
for (; ++i < iterable.length;) if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next;
return next.value = undefined, next.done = !0, next;
};
return next.next = next;
}
}
return {
next: doneResult
};
}
function doneResult() {
return {
value: undefined,
done: !0
};
}
return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", {
value: GeneratorFunctionPrototype,
configurable: !0
}), defineProperty(GeneratorFunctionPrototype, "constructor", {
value: GeneratorFunction,
configurable: !0
}), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) {
var ctor = "function" == typeof genFun && genFun.constructor;
return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name));
}, exports.mark = function (genFun) {
return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun;
}, exports.awrap = function (arg) {
return {
__await: arg
};
}, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () {
return this;
}), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
void 0 === PromiseImpl && (PromiseImpl = Promise);
var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) {
return result.done ? result.value : iter.next();
});
}, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () {
return this;
}), define(Gp, "toString", function () {
return "[object Generator]";
}), exports.keys = function (val) {
var object = Object(val),
keys = [];
for (var key in object) keys.push(key);
return keys.reverse(), function next() {
for (; keys.length;) {
var key = keys.pop();
if (key in object) return next.value = key, next.done = !1, next;
}
return next.done = !0, next;
};
}, exports.values = values, Context.prototype = {
constructor: Context,
reset: function (skipTempReset) {
if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined);
},
stop: function () {
this.done = !0;
var rootRecord = this.tryEntries[0].completion;
if ("throw" === rootRecord.type) throw rootRecord.arg;
return this.rval;
},
dispatchException: function (exception) {
if (this.done) throw exception;
var context = this;
function handle(loc, caught) {
return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught;
}
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i],
record = entry.completion;
if ("root" === entry.tryLoc) return handle("end");
if (entry.tryLoc <= this.prev) {
var hasCatch = hasOwn.call(entry, "catchLoc"),
hasFinally = hasOwn.call(entry, "finallyLoc");
if (hasCatch && hasFinally) {
if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);
if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);
} else if (hasCatch) {
if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);
} else {
if (!hasFinally) throw new Error("try statement without catch or finally");
if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);
}
}
}
},
abrupt: function (type, arg) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
var finallyEntry = entry;
break;
}
}
finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null);
var record = finallyEntry ? finallyEntry.completion : {};
return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record);
},
complete: function (record, afterLoc) {
if ("throw" === record.type) throw record.arg;
return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel;
},
finish: function (finallyLoc) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel;
}
},
catch: function (tryLoc) {
for (var i = this.tryEntries.length - 1; i >= 0; --i) {
var entry = this.tryEntries[i];
if (entry.tryLoc === tryLoc) {
var record = entry.completion;
if ("throw" === record.type) {
var thrown = record.arg;
resetTryEntry(entry);
}
return thrown;
}
}
throw new Error("illegal catch attempt");
},
delegateYield: function (iterable, resultName, nextLoc) {
return this.delegate = {
iterator: values(iterable),
resultName: resultName,
nextLoc: nextLoc
}, "next" === this.method && (this.arg = undefined), ContinueSentinel;
}
}, exports;
}
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function () {
var self = this,
args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _taggedTemplateLiteralLoose(strings, raw) {
if (!raw) {
raw = strings.slice(0);
}
strings.raw = raw;
return strings;
}
var _on, _on2, _on3, _on4, _on5, _on6, _states;
var initialContext = {
documentsFetched: [],
toSync: [],
syncOperations: [],
toLink: [],
linkOperations: [],
error: undefined,
errorMessage: undefined,
valid: false,
ready: false,
shopName: undefined
};
var syncMachine = /*#__PURE__*/xstate.Machine({
id: 'syncMachine',
initial: types.SyncStates.INIT,
context: initialContext,
states: (_states = {}, _states[types.SyncStates.INIT] = {
on: (_on = {}, _on[types.SyncEventType.Valid] = {
target: types.SyncStates.READY,
actions: ['onReady']
}, _on[types.SyncEventType.Invalid] = {
target: types.SyncStates.SETUP,
actions: ['onSetup']
}, _on)
}, _states[types.SyncStates.SETUP] = {
on: (_on2 = {}, _on2[types.SyncEventType.Valid] = {
target: types.SyncStates.READY,
actions: ['onReady']
}, _on2[types.SyncEventType.Invalid] = {
target: types.SyncStates.SETUP,
actions: ['onError']
}, _on2)
}, _states[types.SyncStates.READY] = {
on: (_on3 = {}, _on3[types.SyncEventType.Sync] = types.SyncStates.SYNCING, _on3[types.SyncEventType.ClearedSecrets] = {
target: types.SyncStates.SETUP,
actions: 'reset'
}, _on3)
}, _states[types.SyncStates.SYNCING] = {
on: (_on4 = {}, _on4[types.SyncEventType.DocumentsFetched] = {
internal: true,
actions: ['onDocumentsFetched']
}, _on4[types.SyncEventType.FetchComplete] = {
internal: true,
actions: ['onFetchedComplete']
}, _on4[types.SyncEventType.DocumentsSynced] = {
internal: true,
actions: ['onDocumentsSynced']
}, _on4[types.SyncEventType.DocumentsLinked] = {
internal: true,
actions: ['onDocumentLinked']
}, _on4[types.SyncEventType.Complete] = types.SyncStates.COMPLETE, _on4[types.SyncEventType.Errored] = {
target: types.SyncStates.SYNC_ERROR,
actions: ['onError']
}, _on4)
}, _states[types.SyncStates.COMPLETE] = {
on: (_on5 = {}, _on5[types.SyncEventType.Reset] = types.SyncStates.READY, _on5)
}, _states[types.SyncStates.SYNC_ERROR] = {
on: (_on6 = {}, _on6[types.SyncEventType.Reset] = types.SyncStates.READY, _on6)
}, _states)
}, {
actions: {
onReady: /*#__PURE__*/xstate.assign(function (_, event) {
return {
valid: true,
ready: true,
shopName: event.shopName,
errorMessage: undefined,
error: undefined
};
}),
onSetup: /*#__PURE__*/xstate.assign({
valid: false,
ready: true
}),
onError: /*#__PURE__*/xstate.assign({
errorMessage: function errorMessage(_, event) {
return event.errorMessage;
},
error: function error(_, event) {
return event.error;
},
valid: false
}),
onDocumentsFetched: /*#__PURE__*/xstate.assign({
documentsFetched: function documentsFetched(context, action) {
return [].concat(context.documentsFetched, action.shopifyDocuments);
}
}),
onFetchedComplete: /*#__PURE__*/xstate.assign({
toSync: function toSync(context) {
return context.documentsFetched;
},
toLink: function toLink(context) {
return context.documentsFetched;
}
}),
onDocumentsSynced: /*#__PURE__*/xstate.assign({
syncOperations: function syncOperations(context, action) {
return [].concat(context.syncOperations, [action.op]);
}
}),
onDocumentLinked: /*#__PURE__*/xstate.assign({
linkOperations: function linkOperations(context, action) {
return [].concat(context.linkOperations, [action.op]);
}
})
}
});
var syncStateMachine = function syncStateMachine(_ref) {
var onStateChange = _ref.onStateChange;
var initialState = syncMachine.initialState;
var service = xstate.interpret(syncMachine);
service.start();
service.onTransition(function (newState) {
onStateChange(newState);
});
var init = function init(valid, shopName) {
if (valid) {
service.send({
type: types.SyncEventType.Valid,
shopName: shopName
});
} else {
service.send(types.SyncEventType.Invalid);
}
};
var onSavedSecrets = function onSavedSecrets(shopName) {
service.send({
type: types.SyncEventType.Valid,
shopName: shopName
});
};
var onSavedSecretsError = function onSavedSecretsError(error, message) {
var errorMessage = message || error.message;
service.send({
type: types.SyncEventType.Errored,
error: error,
errorMessage: errorMessage
});
};
var onClearedSecrets = function onClearedSecrets() {
service.send({
type: types.SyncEventType.ClearedSecrets
});
};
var startSync = function startSync() {
service.send(types.SyncEventType.Sync);
};
var onDocumentsFetched = function onDocumentsFetched(shopifyDocuments) {
service.send({
type: types.SyncEventType.DocumentsFetched,
shopifyDocuments: shopifyDocuments
});
};
var onFetchComplete = function onFetchComplete(shopifyDocuments) {
service.send({
type: types.SyncEventType.FetchComplete,
shopifyDocuments: shopifyDocuments
});
};
var onDocumentSynced = function onDocumentSynced(op) {
service.send({
type: types.SyncEventType.DocumentsSynced,
op: op
});
};
var onDocumentLinked = function onDocumentLinked(op) {
service.send({
type: types.SyncEventType.DocumentsLinked,
op: op
});
};
var onComplete = function onComplete() {
service.send({
type: types.SyncEventType.Complete
});
};
var onError = function onError(error) {
service.send({
type: types.SyncEventType.Errored,
errorMessage: error.message,
error: error
});
};
return {
initialState: initialState,
startSync: startSync,
init: init,
onSavedSecrets: onSavedSecrets,
onSavedSecretsError: onSavedSecretsError,
onClearedSecrets: onClearedSecrets,
onDocumentsFetched: onDocumentsFetched,
onFetchComplete: onFetchComplete,
onDocumentSynced: onDocumentSynced,
onDocumentLinked: onDocumentLinked,
onComplete: onComplete,
onError: onError
};
};
var log = /*#__PURE__*/Debug('sane-shopify:patch');
var createLogger = function createLogger(cbs) {
if (cbs === void 0) {
cbs = {};
}
var logFetched = function logFetched(fetchedItems) {
var shopifyDocuments = Array.isArray(fetchedItems) ? fetchedItems : [fetchedItems];
log('fetched initial shopify documents:', shopifyDocuments);
cbs.onProgress && cbs.onProgress({
type: 'fetched',
shopifyDocuments: shopifyDocuments
});
};
var logSynced = function logSynced(op) {
log('synced document', op);
cbs.onProgress && cbs.onProgress(op);
};
var logLinked = function logLinked(sourceDoc, pairs) {
log('linked documents:', pairs);
cbs.onProgress && cbs.onProgress({
type: 'link',
sourceDoc: sourceDoc,
pairs: pairs
});
};
var logArchived = function logArchived(sourceDoc) {
log('archived document:', sourceDoc);
cbs.onProgress && cbs.onProgress({
type: 'archive',
sourceDoc: sourceDoc
});
};
var logComplete = function logComplete(op) {
log('completed sync operations', op);
var ops = Array.isArray(op) ? op : [op];
cbs.onComplete && cbs.onComplete(ops, 'completed sync operations');
};
return {
logFetched: logFetched,
logLinked: logLinked,
logSynced: logSynced,
logComplete: logComplete,
logArchived: logArchived
};
};
var CONFIG_DOC_TYPE = 'sane-shopify.storefront-config';
var CONFIG_DOC_ID_PREFIX = 'sane-shopify-storefront-config-';
var STOREFRONT_API_VERSION = '2022-10';
var getErrorMessage = function getErrorMessage(r) {
switch (r.status) {
case 401:
case 403:
return 'Authentication failed. Please make sure you have entered the correct Storefront name and API Key.';
default:
return "There was an error connecting to Shopify (" + r.status + ": " + r.statusText + ")";
}
};
var deduplicateFragments = function deduplicateFragments(queryString) {
if (!queryString) throw new Error('No query string provided');
return queryString.split(/\n\s+\n/).map(function (group) {
return group.replace(/^([\n\s])+/, '').replace(/\n+$/, '');
}).reduce(function (acc, current) {
if (acc.includes(current)) return acc;
return [].concat(acc, [current]);
}, []).join('\n\n');
};
var createShopifyClient = function createShopifyClient(secrets) {
if (!secrets) {
return {
query: function () {
var _query = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
throw new Error('You must provide a shopify storefront name and access token');
case 1:
case "end":
return _context.stop();
}
}, _callee);
}));
function query() {
return _query.apply(this, arguments);
}
return query;
}(),
shopName: ''
};
}
var shopName = secrets.shopName,
accessToken = secrets.accessToken;
var url = "https://" + shopName + ".myshopify.com/api/" + STOREFRONT_API_VERSION + "/graphql.json";
var headers = {
'Content-Type': 'application/json',
'X-Shopify-Storefront-Access-Token': accessToken
};
var bucket = new LeakyBucket({
capacity: 40,
interval: 30
});
var query = /*#__PURE__*/function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(q, variables) {
var _q$loc;
var queryString;
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
queryString = typeof q === 'string' ? q : deduplicateFragments(q == null ? void 0 : (_q$loc = q.loc) == null ? void 0 : _q$loc.source.body);
_context3.next = 3;
return bucket.throttle();
case 3:
return _context3.abrupt("return", fetch(url, {
headers: headers,
method: 'POST',
body: JSON.stringify({
variables: variables,
query: queryString
})
}).then( /*#__PURE__*/function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(r) {
var json;
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
if (r.ok) {
_context2.next = 2;
break;
}
throw new Error(getErrorMessage(r));
case 2:
_context2.next = 4;
return r.json();
case 4:
json = _context2.sent;
return _context2.abrupt("return", json);
case 6:
case "end":
return _context2.stop();
}
}, _callee2);
}));
return function (_x3) {
return _ref2.apply(this, arguments);
};
}()));
case 4:
case "end":
return _context3.stop();
}
}, _callee3);
}));
return function query(_x, _x2) {
return _ref.apply(this, arguments);
};
}();
return {
shopName: shopName,
query: query
};
};
var isMetafield = function isMetafield(obj) {
return Boolean(obj && obj.value && obj.namespace && obj.key);
};
var omit = function omit(obj, toOmit) {
return Object.entries(obj).reduce(function (prev, _ref) {
var _extends2;
var key = _ref[0],
value = _ref[1];
if (key === toOmit) return prev;
return _extends({}, prev, (_extends2 = {}, _extends2[key] = value, _extends2));
}, {});
};
var remapMetafields = function remapMetafields(item) {
var _remapped$variants, _remapped$variants$ed;
var itemWithEmptyMetafields = _extends({}, item, {
metafields: {
pageInfo: {
hasNextPage: false,
hasPreviousPage: false
},
edges: []
}
});
var remapped = Object.entries(item).reduce(function (prev, _ref2) {
var key = _ref2[0],
value = _ref2[1];
var metafieldMatch = key.match(/metafield_/);
if (metafieldMatch != null && metafieldMatch.input && value === null) {
return omit(prev, key);
}
if (metafieldMatch != null && metafieldMatch.input && isMetafield(value)) {
var _prev$metafields;
var metafieldMatchName = metafieldMatch.input;
var prevWithoutMetafieldProperty = omit(prev, metafieldMatchName);
var prevEdges = (prev == null ? void 0 : (_prev$metafields = prev.metafields) == null ? void 0 : _prev$metafields.edges) || [];
var metafieldValue = value.value,
namespace = value.namespace,
_key = value.key;
var newEdge = {
_key: namespace + "-" + _key + "-" + metafieldValue,
cursor: namespace + "-" + _key + "-" + metafieldValue,
node: {
namespace: namespace,
key: _key,
value: metafieldValue
}
};
return _extends({}, prevWithoutMetafieldProperty, {
metafields: _extends({}, prev.metafields, {
edges: [].concat(prevEdges, [newEdge])
})
});
}
return prev;
}, itemWithEmptyMetafields);
if (remapped.__typename === 'Product' && 'variants' in remapped && remapped != null && (_remapped$variants = remapped.variants) != null && (_remapped$variants$ed = _remapped$variants.edges) != null && _remapped$variants$ed.length) {
return _extends({}, remapped, {
variants: _extends({}, remapped.variants, {
edges: remapped.variants.edges.map(function (variantEdge) {
return _extends({}, variantEdge, {
node: remapMetafields(variantEdge.node)
});
})
})
});
}
return remapped;
};
var isSanityProduct = function isSanityProduct(doc) {
return doc._type === 'shopifyProduct';
};
var isSanityCollection = function isSanityCollection(doc) {
return doc._type === 'shopifyCollection';
};
var isShopifyProduct = function isShopifyProduct(doc) {
return doc.__typename === 'Product';
};
var isShopifyCollection = function isShopifyCollection(doc) {
return doc.__typename === 'Collection';
};
function definitely(items) {
if (!items) return [];
return items.filter(function (i) {
return Boolean(i);
});
}
var slugify = function slugify(text) {
return text.toString().toLowerCase().replace(/\s+/g, '-').replace(/[^\w\-]+/g, '').replace(/\-\-+/g, '-').replace(/^-+/, '').replace(/-+$/, '');
};
var last = function last(arr) {
return arr[arr.length - 1];
};
var getLastCursor = function getLastCursor(connection) {
if (!connection.edges || connection.edges.length === 0) return null;
var lastEdge = last(connection == null ? void 0 : connection.edges);
if (!lastEdge) return null;
return lastEdge.cursor;
};
var mergePaginatedResults = function mergePaginatedResults(p1, p2) {
if (!p1.pageInfo || !p2.pageInfo) throw new Error('Page info was not suplied');
return {
pageInfo: {
hasPrevPage: p1.pageInfo.hasPreviousPage,
hasPreviousPage: p1.pageInfo.hasPreviousPage,
hasNextPage: p2.pageInfo.hasNextPage
},
edges: [].concat(definitely(p1.edges), definitely(p2.edges))
};
};
var toStorefrontId = function toStorefrontId(id) {
return id.startsWith('gid://') ? btoa(id) : id;
};
var toAdminApiId = function toAdminApiId(id) {
return id.startsWith('gid://') ? id : atob(id);
};
var _templateObject, _templateObject2, _templateObject3;
var moneyFragment = "\n fragment MoneyV2Fragment on MoneyV2 {\n amount\n currencyCode\n }\n";
var mediaImageFragment = "\n fragment MediaImageFragment on MediaImage {\n image {\n __typename\n id\n altText\n originalSrc\n w100: transformedSrc(maxWidth: 100, crop: CENTER)\n w300: transformedSrc(maxWidth: 300, crop: CENTER)\n w800: transformedSrc(maxWidth: 800, crop: CENTER)\n w1200: transformedSrc(maxWidth: 1200, crop: CENTER)\n w1600: transformedSrc(maxWidth: 1600, crop: CENTER)\n }\n }\n";
var videoFragment = "\n fragment VideoFragment on Video {\n id\n alt\n sources {\n url\n format\n mimeType\n }\n }\n";
var imageFragment = "\n fragment ImageFragment on Image {\n __typename\n id\n altText\n originalSrc\n w100: transformedSrc(maxWidth: 100, crop: CENTER)\n w300: transformedSrc(maxWidth: 300, crop: CENTER)\n w800: transformedSrc(maxWidth: 800, crop: CENTER)\n w1200: transformedSrc(maxWidth: 1200, crop: CENTER)\n w1600: transformedSrc(maxWidth: 1600, crop: CENTER)\n }\n";
var createProductVariantFragment = function createProductVariantFragment(shopifyConfig) {
var _shopifyConfig$varian;
return gql(_templateObject || (_templateObject = _taggedTemplateLiteralLoose(["\n fragment ProductVariantFragment on ProductVariant {\n __typename\n availableForSale\n currentlyNotInStock\n id\n image {\n ...ImageFragment\n }\n priceV2 {\n ...MoneyV2Fragment\n }\n compareAtPriceV2 {\n ...MoneyV2Fragment\n }\n selectedOptions {\n value\n name\n }\n ", "\n requiresShipping\n sku\n title\n weight\n weightUnit\n }\n"])), metafieldsToQuery(shopifyConfig == null ? void 0 : (_shopifyConfig$varian = shopifyConfig.variants) == null ? void 0 : _shopifyConfig$varian.metafields));
};
var metafieldsToQuery = function metafieldsToQuery(metafields) {
return metafields ? metafields.map(function (_ref) {
var namespace = _ref.namespace,
key = _ref.key;
return "\n metafield_" + namespace + "_" + key + ": metafield(namespace: \"" + namespace + "\", key: \"" + key + "\"){\n namespace\n key\n value\n }\n ";
}) : '';
};
var createProductFragment = function createProductFragment(shopifyConfig) {
var _shopifyConfig$produc;
return gql(_templateObject2 || (_templateObject2 = _taggedTemplateLiteralLoose(["\n fragment ProductFragment on Product {\n __typename\n id\n updatedAt\n handle\n title\n description\n descriptionHtml\n availableForSale\n productType\n tags\n vendor\n createdAt\n publishedAt\n options {\n id\n name\n values\n }\n variants(first: 99) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n }\n edges {\n cursor\n node {\n ...ProductVariantFragment\n }\n }\n }\n ", "\n compareAtPriceRange {\n minVariantPrice {\n ...MoneyV2Fragment\n }\n maxVariantPrice {\n ...MoneyV2Fragment\n }\n }\n priceRange {\n minVariantPrice {\n ...MoneyV2Fragment\n }\n maxVariantPrice {\n ...MoneyV2Fragment\n }\n }\n media(first: 50) {\n edges {\n cursor\n node {\n ...MediaImageFragment\n ...VideoFragment\n }\n }\n }\n images(first: 50) {\n edges {\n cursor\n node {\n ...ImageFragment\n }\n }\n }\n }\n ", "\n ", "\n ", "\n ", "\n ", "\n"])), metafieldsToQuery(shopifyConfig == null ? void 0 : (_shopifyConfig$produc = shopifyConfig.products) == null ? void 0 : _shopifyConfig$produc.metafields), moneyFragment, mediaImageFragment, imageFragment, videoFragment, createProductVariantFragment(shopifyConfig));
};
var createCollectionFragment = function createCollectionFragment(shopifyConfig) {
var _shopifyConfig$collec;
return gql(_templateObject3 || (_templateObject3 = _taggedTemplateLiteralLoose(["\n fragment CollectionFragment on Collection {\n __typename\n id\n updatedAt\n handle\n title\n description\n descriptionHtml\n ", "\n image {\n ...ImageFragment\n }\n }\n ", "\n"])), metafieldsToQuery(shopifyConfig == null ? void 0 : (_shopifyConfig$collec = shopifyConfig.collections) == null ? void 0 : _shopifyConfig$collec.metafields), imageFragment);
};
var _templateObject$1, _templateObject2$1;
var log$1 = /*#__PURE__*/Debug('sane-shopify:fetching');
var createProductByHandle = function createProductByHandle(shopifyConfig) {
return gql(_templateObject$1 || (_templateObject$1 = _taggedTemplateLiteralLoose(["\n query ProductQuery(\n $handle: String!\n $collectionsFirst: Int!\n $collectionsAfter: String\n ) {\n productByHandle(handle: $handle) {\n ...ProductFragment\n collections(first: $collectionsFirst, after: $collectionsAfter) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n }\n edges {\n cursor\n node {\n id\n handle\n }\n }\n }\n }\n }\n ", "\n"])), createProductFragment(shopifyConfig));
};
var createProductById = function createProductById(shopifyConfig) {
return gql(_templateObject2$1 || (_templateObject2$1 = _taggedTemplateLiteralLoose(["\n query NodeQuery(\n $id: ID!\n $collectionsFirst: Int!\n $collectionsAfter: String\n ) {\n node(id: $id) {\n ... on Product {\n ...ProductFragment\n collections(first: $collectionsFirst, after: $collectionsAfter) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n }\n edges {\n cursor\n node {\n id\n handle\n }\n }\n }\n }\n }\n }\n ", "\n"])), createProductFragment(shopifyConfig));
};
var createQueries = function createQueries(shopifyConfig) {
return {
PRODUCT_BY_ID: createProductById(shopifyConfig),
PRODUCT_BY_HANDLE: createProductByHandle(shopifyConfig)
};
};
var getByHandle = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(shopifyClient, queryString, handle, collectionsAfter) {
var _result$data;
var result, product;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return shopifyClient.query(queryString, {
handle: handle,
collectionsFirst: 200,
collectionsAfter: collectionsAfter
});
case 2:
result = _context.sent;
product = result == null ? void 0 : (_result$data = result.data) == null ? void 0 : _result$data.productByHandle;
return _context.abrupt("return", product ? remapMetafields(product) : undefined);
case 5:
case "end":
return _context.stop();
}
}, _callee);
}));
return function getByHandle(_x, _x2, _x3, _x4) {
return _ref.apply(this, arguments);
};
}();
var getById = /*#__PURE__*/function () {
var _ref2 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(shopifyClient, queryString, id, collectionsAfter) {
var _result$data2;
var result, product;
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 2;
return shopifyClient.query(queryString, {
id: id,
collectionsFirst: 20,
collectionsAfter: collectionsAfter
});
case 2:
result = _context2.sent;
product = result == null ? void 0 : (_result$data2 = result.data) == null ? void 0 : _result$data2.node;
return _context2.abrupt("return", product ? remapMetafields(product) : undefined);
case 5:
case "end":
return _context2.stop();
}
}, _callee2);
}));
return function getById(_x5, _x6, _x7, _x8) {
return _ref2.apply(this, arguments);
};
}();
var fetchAllProductCollections = /*#__PURE__*/function () {
var _ref3 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(shopifyClient, metafieldsConfig, prevProduct) {
var _prevProduct$collecti, _prevProduct$collecti2, _product$collections, _product$collections$;
var collectionsAfter, _createQueries, PRODUCT_BY_HANDLE, nextProduct, product;
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
if ((_prevProduct$collecti = prevProduct.collections) != null && (_prevProduct$collecti2 = _prevProduct$collecti.pageInfo) != null && _prevProduct$collecti2.hasNextPage) {
_context3.next = 3;
break;
}
log$1("Fetched all collections for product " + prevProduct.handle, prevProduct);
return _context3.abrupt("return", prevProduct);
case 3:
collectionsAfter = getLastCursor(prevProduct.collections);
log$1("Fetching further products for product " + prevProduct.handle, prevProduct);
_createQueries = createQueries(metafieldsConfig), PRODUCT_BY_HANDLE = _createQueries.PRODUCT_BY_HANDLE;
_context3.next = 8;
return getByHandle(shopifyClient, PRODUCT_BY_HANDLE, prevProduct.handle, collectionsAfter ? collectionsAfter : undefined);
case 8:
nextProduct = _context3.sent;
product = nextProduct ? _extends({}, nextProduct, {
collections: nextProduct.collections ? mergePaginatedResults(prevProduct.collections, nextProduct.collections) : prevProduct.collections
}) : prevProduct;
if (!(product != null && (_product$collections = product.collections) != null && (_product$collections$ = _product$collections.pageInfo) != null && _product$collections$.hasNextPage)) {
_context3.next = 12;
break;
}
return _context3.abrupt("return", fetchAllProductCollections(shopifyClient, metafieldsConfig, product));
case 12:
log$1("Fetched all collections for product " + prevProduct.handle, prevProduct);
return _context3.abrupt("return", product);
case 14:
case "end":
return _context3.stop();
}
}, _callee3);
}));
return function fetchAllProductCollections(_x9, _x10, _x11) {
return _ref3.apply(this, arguments);
};
}();
var createFetchShopifyProduct = function createFetchShopifyProduct(shopifyClient, fetchMetafieldsConfig, cache) {
return /*#__PURE__*/function () {
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(params) {
var metafieldsConfig, id, handle, _createQueries2, PRODUCT_BY_ID, PRODUCT_BY_HANDLE, cachedProduct, fetchedProduct, product;
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
while (1) switch (_context4.prev = _context4.next) {
case 0:
_context4.next = 2;
return fetchMetafieldsConfig();
case 2:
metafieldsConfig = _context4.sent;
id = params.id, handle = params.handle;
if (!(!id && !handle)) {
_context4.next = 6;
break;
}
throw new Error('You must provide either an id or handle');
case 6:
_createQueries2 = createQueries(metafieldsConfig), PRODUCT_BY_ID = _createQueries2.PRODUCT_BY_ID, PRODUCT_BY_HANDLE = _createQueries2.PRODUCT_BY_HANDLE;
cachedProduct = id ? cache.getProductById(id) : handle ? cache.getProductByHandle(handle) : null;
if (!cachedProduct) {
_context4.next = 10;
break;
}
return _context4.abrupt("return", fetchAllProductCollections(shopifyClient, metafieldsConfig, cachedProduct));
case 10:
if (!id) {
_context4.next = 16;
break;
}
_context4.next = 13;
return getById(shopifyClient, PRODUCT_BY_ID, id);
case 13:
_context4.t0 = _context4.sent;
_context4.next = 24;
break;
case 16:
if (!handle) {
_context4.next = 22;
break;
}
_context4.next = 19;
return getByHandle(shopifyClient, PRODUCT_BY_HANDLE, handle);
case 19:
_context4.t1 = _context4.sent;
_context4.next = 23;
break;
case 22:
_context4.t1 = null;
case 23:
_context4.t0 = _context4.t1;
case 24:
fetchedProduct = _context4.t0;
if (fetchedProduct) {
_context4.next = 27;
break;
}
return _context4.abrupt("return", null);
case 27:
_context4.next = 29;
return fetchAllProductCollections(shopifyClient, metafieldsConfig, fetchedProduct);
case 29:
product = _context4.sent;
cache.set(product);
return _context4.abrupt("return", product);
case 32:
case "end":
return _context4.stop();
}
}, _callee4);
}));
return function (_x12) {
return _ref4.apply(this, arguments);
};
}();
};
var _templateObject$2, _templateObject2$2;
var log$2 = /*#__PURE__*/Debug('sane-shopify:fetching');
var createCollectionByHandle = function createCollectionByHandle(shopifyConfig) {
return gql(_templateObject$2 || (_templateObject$2 = _taggedTemplateLiteralLoose(["\n query CollectionQuery(\n $handle: String!\n $productsFirst: Int!\n $productsAfter: String\n ) {\n collectionByHandle(handle: $handle) {\n ...CollectionFragment\n products(first: $productsFirst, after: $productsAfter) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n }\n edges {\n cursor\n node {\n id\n handle\n }\n }\n }\n }\n }\n ", "\n"])), createCollectionFragment(shopifyConfig));
};
var createCollectionById = function createCollectionById(shopifyConfig) {
return gql(_templateObject2$2 || (_templateObject2$2 = _taggedTemplateLiteralLoose(["\n query NodeQuery($id: ID!, $productsFirst: Int!, $productsAfter: String) {\n node(id: $id) {\n ... on Collection {\n ...CollectionFragment\n products(first: $productsFirst, after: $productsAfter) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n }\n edges {\n cursor\n node {\n id\n handle\n }\n }\n }\n }\n }\n }\n ", "\n"])), createCollectionFragment(shopifyConfig));
};
var createQueries$1 = function createQueries(shopifyConfig) {
return {
COLLECTION_BY_ID: createCollectionById(shopifyConfig),
COLLECTION_BY_HANDLE: createCollectionByHandle(shopifyConfig)
};
};
var getByHandle$1 = /*#__PURE__*/function () {
var _ref = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(shopifyClient, queryString, handle, productsAfter) {
var _result$data;
var result;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return shopifyClient.query(queryString, {
handle: handle,
productsFirst: 50,
productsAfter: productsAfter
});
case 2:
result = _context.sent;
return _context.abrupt("return", result == null ? void 0 : (_result$data = result.data) == null ? void 0 : _result$data.collectionByHandle);
case 4:
case "end":
return _context.stop();
}
}, _callee);
}));
return function getByHandle(_x, _x2, _x3, _x4) {
return _ref.apply(this, arguments);
};
}();
var getById$1 = /*#__PURE__*/function () {
var _ref2 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(shopifyClient, queryString, id, productsAfter) {
var _result$data2;
var result;
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 2;
return shopifyClient.query(queryString, {
id: id,
productsFirst: 200,
productsAfter: productsAfter
});
case 2:
result = _context2.sent;
return _context2.abrupt("return", result == null ? void 0 : (_result$data2 = result.data) == null ? void 0 : _result$data2.node);
case 4:
case "end":
return _context2.stop();
}
}, _callee2);
}));
return function getById(_x5, _x6, _x7, _x8) {
return _ref2.apply(this, arguments);
};
}();
var fetchAllCollectionProducts = /*#__PURE__*/function () {
var _ref3 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(shopifyClient, metafieldsConfig, prevCollection) {
var _prevCollection$produ, _prevCollection$produ2, _collection$products, _collection$products$;
var productsAfter, _createQueries, COLLECTION_BY_HANDLE, nextCollection, collection;
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
if ((_prevCollection$produ = prevCollection.products) != null && (_prevCollection$produ2 = _prevCollection$produ.pageInfo) != null && _prevCollection$produ2.hasNextPage) {
_context3.next = 3;
brea