@sixtyninecommerce/admin 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4347 -171
- package/dist/catalog/assets.d.ts +120 -8
- package/dist/catalog/assets.js +98 -12
- package/dist/catalog/collections.d.ts +279 -14
- package/dist/catalog/collections.js +246 -15
- package/dist/catalog/index.d.ts +9 -2
- package/dist/catalog/index.js +4 -0
- package/dist/catalog/products.d.ts +159 -19
- package/dist/catalog/products.js +88 -13
- package/dist/catalog/properties.d.ts +102 -14
- package/dist/catalog/properties.js +13 -0
- package/dist/catalog/recommendations.d.ts +261 -0
- package/dist/catalog/recommendations.js +145 -0
- package/dist/catalog/reviews.d.ts +368 -0
- package/dist/catalog/reviews.js +318 -0
- package/dist/catalog/types.d.ts +17 -1
- package/dist/catalog/types.js +10 -0
- package/dist/catalog/variant-find.d.ts +136 -0
- package/dist/catalog/variant-find.js +239 -0
- package/dist/catalog/variants.d.ts +233 -26
- package/dist/catalog/variants.js +125 -7
- package/dist/catalog/visibility.d.ts +20 -5
- package/dist/catalog/visibility.js +19 -1
- package/dist/client.d.ts +95 -9
- package/dist/client.js +35 -7
- package/dist/content/assets.d.ts +286 -0
- package/dist/content/assets.js +181 -0
- package/dist/content/items.d.ts +269 -0
- package/dist/content/items.js +170 -0
- package/dist/content/types.d.ts +282 -0
- package/dist/content/types.js +100 -0
- package/dist/customers/age-verification.d.ts +66 -0
- package/dist/customers/age-verification.js +79 -0
- package/dist/customers/credit.d.ts +263 -0
- package/dist/customers/credit.js +244 -0
- package/dist/customers/delivery-preferences.d.ts +120 -0
- package/dist/customers/delivery-preferences.js +97 -0
- package/dist/customers/groups.d.ts +207 -0
- package/dist/customers/groups.js +438 -0
- package/dist/customers/index.d.ts +447 -37
- package/dist/customers/index.js +313 -40
- package/dist/customers/invitation-status.d.ts +57 -0
- package/dist/customers/invitation-status.js +21 -0
- package/dist/customers/notes.d.ts +67 -0
- package/dist/customers/notes.js +51 -0
- package/dist/customers/notification-recipients.d.ts +97 -0
- package/dist/customers/notification-recipients.js +84 -0
- package/dist/customers/saved-lists.d.ts +42 -0
- package/dist/customers/saved-lists.js +61 -0
- package/dist/customers/vat.d.ts +83 -0
- package/dist/customers/vat.js +46 -0
- package/dist/customers/wire.d.ts +20 -0
- package/dist/customers/wire.js +35 -0
- package/dist/documents/ar.d.ts +307 -0
- package/dist/documents/ar.js +254 -0
- package/dist/documents/index.d.ts +731 -21
- package/dist/documents/index.js +436 -24
- package/dist/documents/pdf.d.ts +2 -0
- package/dist/documents/pdf.js +11 -0
- package/dist/fulfillments/create.d.ts +167 -0
- package/dist/fulfillments/create.js +216 -0
- package/dist/fulfillments/index.d.ts +44 -10
- package/dist/fulfillments/index.js +11 -2
- package/dist/fulfillments/payment-policy.d.ts +64 -0
- package/dist/fulfillments/payment-policy.js +140 -0
- package/dist/fulfillments/warehouse.d.ts +724 -0
- package/dist/fulfillments/warehouse.js +914 -0
- package/dist/geo/index.d.ts +119 -0
- package/dist/geo/index.js +107 -0
- package/dist/index.d.ts +123 -35
- package/dist/index.js +45 -12
- package/dist/integrations/afas-actions.d.ts +234 -0
- package/dist/integrations/afas-actions.js +310 -0
- package/dist/integrations/afas-types.d.ts +483 -0
- package/dist/integrations/afas-types.js +5 -0
- package/dist/integrations/afas.d.ts +234 -0
- package/dist/integrations/afas.js +290 -0
- package/dist/integrations/connections.d.ts +103 -0
- package/dist/integrations/connections.js +55 -0
- package/dist/integrations/esp.d.ts +313 -0
- package/dist/integrations/esp.js +169 -0
- package/dist/integrations/exact-online-types.d.ts +423 -0
- package/dist/integrations/exact-online-types.js +6 -0
- package/dist/integrations/exact-online.d.ts +248 -0
- package/dist/integrations/exact-online.js +376 -0
- package/dist/integrations/index.d.ts +29 -3
- package/dist/integrations/index.js +18 -3
- package/dist/integrations/pipeline-keys.d.ts +13 -0
- package/dist/integrations/pipeline-keys.js +22 -0
- package/dist/integrations/pipelines.d.ts +15 -14
- package/dist/integrations/pipelines.js +6 -22
- package/dist/integrations/types.d.ts +146 -0
- package/dist/locations/index.d.ts +66 -0
- package/dist/locations/index.js +31 -0
- package/dist/meta/index.d.ts +162 -0
- package/dist/orders/cancel-with-money.d.ts +227 -0
- package/dist/orders/cancel-with-money.js +153 -0
- package/dist/orders/commit-edit.d.ts +7 -1
- package/dist/orders/commit-edit.js +5 -1
- package/dist/orders/drafts.d.ts +800 -0
- package/dist/orders/drafts.js +771 -0
- package/dist/orders/fields.d.ts +245 -0
- package/dist/orders/fields.js +188 -0
- package/dist/orders/get.d.ts +29 -19
- package/dist/orders/get.js +17 -8
- package/dist/orders/index.d.ts +49 -9
- package/dist/orders/index.js +22 -2
- package/dist/orders/lifecycle.d.ts +128 -0
- package/dist/orders/lifecycle.js +158 -0
- package/dist/orders/line-price-preview.d.ts +7 -2
- package/dist/orders/list.d.ts +222 -0
- package/dist/orders/list.js +377 -0
- package/dist/orders/manual-pricing.d.ts +5 -0
- package/dist/orders/order-entry.d.ts +20 -7
- package/dist/orders/plan-edit.d.ts +1 -1
- package/dist/orders/plan-edit.js +4 -1
- package/dist/orders/settings.d.ts +201 -0
- package/dist/orders/settings.js +325 -0
- package/dist/orders/status.d.ts +159 -13
- package/dist/orders/status.js +21 -0
- package/dist/orders/surcharges.d.ts +8 -1
- package/dist/orders/surcharges.js +3 -2
- package/dist/payments/account-credit.d.ts +30 -0
- package/dist/payments/account-credit.js +19 -0
- package/dist/payments/ar.d.ts +292 -0
- package/dist/payments/ar.js +223 -0
- package/dist/payments/connected-account.d.ts +47 -0
- package/dist/payments/connected-account.js +61 -0
- package/dist/payments/credit-noted-fields.d.ts +12 -0
- package/dist/payments/credit-noted-fields.js +37 -0
- package/dist/payments/index.d.ts +257 -11
- package/dist/payments/index.js +131 -1
- package/dist/payments/methods.d.ts +303 -8
- package/dist/payments/methods.js +337 -7
- package/dist/payments/mollie-methods.d.ts +159 -0
- package/dist/payments/mollie-methods.js +141 -0
- package/dist/payments/payment-links.d.ts +180 -0
- package/dist/payments/payment-links.js +97 -0
- package/dist/payments/provider-keys.d.ts +150 -0
- package/dist/payments/provider-keys.js +118 -0
- package/dist/payments/providers.d.ts +86 -11
- package/dist/payments/providers.js +29 -0
- package/dist/payments/requests.d.ts +144 -0
- package/dist/payments/requests.js +92 -0
- package/dist/payments/store-credit-fields.d.ts +15 -0
- package/dist/payments/store-credit-fields.js +51 -0
- package/dist/pickups/index.d.ts +104 -0
- package/dist/pickups/index.js +105 -0
- package/dist/platform/channels.d.ts +132 -0
- package/dist/platform/channels.js +128 -0
- package/dist/platform/geo.d.ts +123 -0
- package/dist/platform/geo.js +144 -0
- package/dist/platform/tax.d.ts +154 -0
- package/dist/platform/tax.js +139 -0
- package/dist/pos/anomalies.d.ts +158 -0
- package/dist/pos/anomalies.js +64 -0
- package/dist/pos/assisted-selling.d.ts +79 -0
- package/dist/pos/assisted-selling.js +38 -0
- package/dist/pos/exchanges.d.ts +103 -0
- package/dist/pos/exchanges.js +22 -0
- package/dist/pos/gift-cards.d.ts +135 -0
- package/dist/pos/gift-cards.js +47 -0
- package/dist/pos/index.d.ts +2125 -32
- package/dist/pos/index.js +742 -4
- package/dist/pos/no-receipt.d.ts +94 -0
- package/dist/pos/no-receipt.js +25 -0
- package/dist/pos/offline-sales.d.ts +187 -0
- package/dist/pos/offline-sales.js +116 -0
- package/dist/pos/pay-by-link.d.ts +143 -0
- package/dist/pos/pay-by-link.js +57 -0
- package/dist/pos/quick-keys.d.ts +103 -0
- package/dist/pos/quick-keys.js +45 -0
- package/dist/pos/reports.d.ts +360 -0
- package/dist/pos/reports.js +62 -0
- package/dist/pos/returns.d.ts +217 -0
- package/dist/pos/returns.js +53 -0
- package/dist/pricing/bulk-coupons.d.ts +139 -0
- package/dist/pricing/bulk-coupons.js +112 -0
- package/dist/pricing/index.d.ts +174 -4
- package/dist/pricing/index.js +174 -1
- package/dist/pricing/price-lists.d.ts +604 -0
- package/dist/pricing/price-lists.js +600 -0
- package/dist/purchasing/alerts.d.ts +89 -0
- package/dist/purchasing/alerts.js +62 -0
- package/dist/purchasing/cost.d.ts +110 -0
- package/dist/purchasing/cost.js +86 -0
- package/dist/purchasing/index.d.ts +36 -0
- package/dist/purchasing/index.js +16 -0
- package/dist/purchasing/purchase-orders.d.ts +548 -0
- package/dist/purchasing/purchase-orders.js +491 -0
- package/dist/purchasing/replenishment.d.ts +281 -0
- package/dist/purchasing/replenishment.js +240 -0
- package/dist/purchasing/settings.d.ts +152 -0
- package/dist/purchasing/settings.js +181 -0
- package/dist/purchasing/suppliers.d.ts +476 -0
- package/dist/purchasing/suppliers.js +438 -0
- package/dist/quotes/index.d.ts +501 -0
- package/dist/quotes/index.js +439 -0
- package/dist/reports/index.d.ts +71 -8
- package/dist/reports/index.js +74 -11
- package/dist/returns/index.d.ts +614 -21
- package/dist/returns/index.js +695 -11
- package/dist/search/index.d.ts +76 -1
- package/dist/search/index.js +63 -0
- package/dist/shipping/definitions.d.ts +29 -0
- package/dist/shipping/definitions.js +47 -0
- package/dist/shipping/fulfillment-profiles.d.ts +174 -0
- package/dist/shipping/fulfillment-profiles.js +104 -0
- package/dist/shipping/hendriks.d.ts +97 -0
- package/dist/shipping/hendriks.js +50 -0
- package/dist/shipping/index.d.ts +48 -0
- package/dist/shipping/index.js +25 -0
- package/dist/shipping/methods.d.ts +198 -0
- package/dist/shipping/methods.js +240 -0
- package/dist/shipping/myparcel.d.ts +254 -0
- package/dist/shipping/myparcel.js +178 -0
- package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
- package/dist/shipping/parcel-rule.d.ts +6 -5
- package/dist/shipping/parcel-rule.js +21 -23
- package/dist/shipping/rate-tables.d.ts +179 -0
- package/dist/shipping/rate-tables.js +184 -0
- package/dist/stock/index.d.ts +10 -3
- package/dist/stock/index.js +3 -0
- package/dist/stock/locations.d.ts +144 -0
- package/dist/stock/locations.js +168 -0
- package/dist/stock/transfers.d.ts +216 -43
- package/dist/stock/transfers.js +140 -13
- package/dist/stored-value/index.d.ts +214 -4
- package/dist/stored-value/index.js +152 -0
- package/dist/subscriptions/index.d.ts +682 -0
- package/dist/subscriptions/index.js +815 -0
- package/dist/tax/index.d.ts +76 -1
- package/dist/tax/index.js +50 -0
- package/dist/tenant/email-style.d.ts +102 -0
- package/dist/tenant/email-style.js +72 -0
- package/dist/tenant/email-templates.d.ts +66 -0
- package/dist/tenant/email-templates.js +54 -0
- package/dist/tenant/notifications.d.ts +23 -17
- package/dist/tenant/settings-sources.d.ts +1 -1
- package/dist/tenant/time-zone.d.ts +17 -0
- package/dist/tenant/time-zone.js +11 -0
- package/dist/types.d.ts +50 -3
- package/dist/users/index.d.ts +3 -0
- package/dist/users/index.js +2 -0
- package/dist/users/warehouses.d.ts +50 -0
- package/dist/users/warehouses.js +51 -0
- package/package.json +2 -2
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createPage, NotFoundError, readRestPage, } from '@sixtyninecommerce/core';
|
|
2
|
+
import { PIPELINE_DRAFT_PRESERVE_KEYS, PIPELINE_DRAFT_SLOW_TIMEOUT_MS } from './pipeline-keys.js';
|
|
3
|
+
/**
|
|
4
|
+
* The draft set plus a probe's `entityCounts`, keyed by the source's own entity names (a WordPress
|
|
5
|
+
* post type such as `product_brand`). `test` and `retest` answer the analysis at the top level,
|
|
6
|
+
* where no passthrough key covers it.
|
|
7
|
+
*/
|
|
8
|
+
export const PIPELINE_CONNECTION_PRESERVE_KEYS = new Set([
|
|
9
|
+
...PIPELINE_DRAFT_PRESERVE_KEYS,
|
|
10
|
+
'entity_counts',
|
|
11
|
+
'entityCounts',
|
|
12
|
+
]);
|
|
13
|
+
const CONNECTIONS = '/pipelines/connections';
|
|
14
|
+
const segment = (value) => encodeURIComponent(value);
|
|
15
|
+
export function createPipelineConnectionsModule(transport) {
|
|
16
|
+
const call = (method, path, body, options, timeoutMs) => transport.rest('plugins', { method, path, ...(body === undefined ? {} : { body }) }, {
|
|
17
|
+
...options,
|
|
18
|
+
preserveKeys: PIPELINE_CONNECTION_PRESERVE_KEYS,
|
|
19
|
+
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
20
|
+
});
|
|
21
|
+
async function list(options) {
|
|
22
|
+
const body = await transport.rest('plugins', {
|
|
23
|
+
method: 'GET',
|
|
24
|
+
path: CONNECTIONS,
|
|
25
|
+
query: { cursor: 1, after: options?.after, limit: options?.limit },
|
|
26
|
+
}, { ...options, preserveKeys: PIPELINE_CONNECTION_PRESERVE_KEYS });
|
|
27
|
+
const { items, meta } = readRestPage(body);
|
|
28
|
+
return createPage(items, meta, (cursor) => list({ ...options, after: cursor }));
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
list,
|
|
32
|
+
async get(id, options) {
|
|
33
|
+
try {
|
|
34
|
+
return await call('GET', `${CONNECTIONS}/${segment(id)}`, undefined, options);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error instanceof NotFoundError)
|
|
38
|
+
return null;
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
create: (input, options) => call('POST', CONNECTIONS, input, options, PIPELINE_DRAFT_SLOW_TIMEOUT_MS),
|
|
43
|
+
update: (id, input, options) => call('PATCH', `${CONNECTIONS}/${segment(id)}`, input, options, PIPELINE_DRAFT_SLOW_TIMEOUT_MS),
|
|
44
|
+
async delete(id, options) {
|
|
45
|
+
await transport.rest('plugins', { method: 'DELETE', path: `${CONNECTIONS}/${segment(id)}`, expect: 'void' }, options);
|
|
46
|
+
},
|
|
47
|
+
test: (input, options) => call('POST', `${CONNECTIONS}/test`, input, options, PIPELINE_DRAFT_SLOW_TIMEOUT_MS),
|
|
48
|
+
retest: (id, options) => call('POST', `${CONNECTIONS}/${segment(id)}/test`, undefined, options, PIPELINE_DRAFT_SLOW_TIMEOUT_MS),
|
|
49
|
+
detectConfig: (input, options) => call('POST', `${CONNECTIONS}/detect-config`, input, options, PIPELINE_DRAFT_SLOW_TIMEOUT_MS),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** The connectors this deployment offers, `coming_soon` ones included. */
|
|
53
|
+
export async function listPipelineConnectors(transport, options) {
|
|
54
|
+
return transport.rest('plugins', { method: 'GET', path: '/pipelines/connectors' }, { ...options, preserveKeys: PIPELINE_CONNECTION_PRESERVE_KEYS });
|
|
55
|
+
}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { type Page, type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Call, ListOptions } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* State of the credentials the engine hands BACK to the e-mail platform (its read access to
|
|
5
|
+
* this store), as the connect handshake or a retry left it.
|
|
6
|
+
*/
|
|
7
|
+
export interface EspCredentialsPushState {
|
|
8
|
+
/** ISO-8601: when the platform accepted them. */
|
|
9
|
+
pushedAt?: string;
|
|
10
|
+
/** Why the platform refused them, in a sentence for staff. */
|
|
11
|
+
error?: string;
|
|
12
|
+
/** ISO-8601: the last attempt. */
|
|
13
|
+
attemptedAt?: string;
|
|
14
|
+
/** The first characters of the token handed over; never the token. */
|
|
15
|
+
tokenPrefix?: string;
|
|
16
|
+
adminApiUrl?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Whether repeating could change the outcome. `false` for a contract or credential fault the
|
|
19
|
+
* same request would hit again: reconnect instead of retrying.
|
|
20
|
+
*/
|
|
21
|
+
retryable?: boolean;
|
|
22
|
+
/** What the platform did with its first import: `queued` or `already_running`. */
|
|
23
|
+
initialSync?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* State of the REVERSE direction: the platform pushing suppressions, bounces, complaints and
|
|
27
|
+
* consent changes back to this engine. Soft like the credentials push: without it the engine
|
|
28
|
+
* still learns of them, 15 minutes later, from its reconcile poll.
|
|
29
|
+
*/
|
|
30
|
+
export interface EspInboundWebhookState {
|
|
31
|
+
registered: boolean;
|
|
32
|
+
subscriptionId?: string;
|
|
33
|
+
error?: string;
|
|
34
|
+
/** ISO-8601. */
|
|
35
|
+
at?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* What the one-paste connect handshake recorded; null on a connection configured by hand.
|
|
39
|
+
* Carries no secret. Every member is optional: an older connection recorded less.
|
|
40
|
+
*/
|
|
41
|
+
export interface EspConnectMetadata {
|
|
42
|
+
webhookUrl?: string;
|
|
43
|
+
events?: string[];
|
|
44
|
+
apiEndpoint?: string;
|
|
45
|
+
/** ISO-8601. */
|
|
46
|
+
connectedAt?: string;
|
|
47
|
+
pluginVersion?: string;
|
|
48
|
+
credentialsPush?: EspCredentialsPushState;
|
|
49
|
+
emailGateway?: {
|
|
50
|
+
provisioned: boolean;
|
|
51
|
+
skippedReason?: string;
|
|
52
|
+
at?: string;
|
|
53
|
+
};
|
|
54
|
+
inboundWebhook?: EspInboundWebhookState;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A store's connection to its e-mail marketing platform (sixtynine.email): one per store. The
|
|
58
|
+
* API key and webhook secret are never read back in any form.
|
|
59
|
+
*/
|
|
60
|
+
export interface EspConnection {
|
|
61
|
+
id: string;
|
|
62
|
+
channelId: string;
|
|
63
|
+
/** `sixtynine_email`, the one provider today. */
|
|
64
|
+
provider: string;
|
|
65
|
+
/** Whether the store's customers, orders, products and carts are sent. */
|
|
66
|
+
enabled: boolean;
|
|
67
|
+
/** The platform the store's data and stored key go to; a host the deployment allows. */
|
|
68
|
+
apiBaseUrl: string;
|
|
69
|
+
/** The store's id on the platform; null on a connection configured by hand without one. */
|
|
70
|
+
storeId: string | null;
|
|
71
|
+
defaultListId: string | null;
|
|
72
|
+
syncContacts: boolean;
|
|
73
|
+
syncOrders: boolean;
|
|
74
|
+
syncProducts: boolean;
|
|
75
|
+
syncCarts: boolean;
|
|
76
|
+
syncSubscriptions: boolean;
|
|
77
|
+
/** How long a cart sits unchanged before it is reported abandoned. */
|
|
78
|
+
cartIdleMinutes: number;
|
|
79
|
+
/** A cart last changed longer ago is never reported. */
|
|
80
|
+
cartMaxAgeDays: number;
|
|
81
|
+
/** How far back the first order import reaches. */
|
|
82
|
+
orderBackfillDays: number;
|
|
83
|
+
/** Platform field → store field, stored exactly as it was sent. */
|
|
84
|
+
fieldMappings: unknown;
|
|
85
|
+
connectMetadata: EspConnectMetadata | null;
|
|
86
|
+
/** ISO-8601. */
|
|
87
|
+
createdAt: string;
|
|
88
|
+
/** ISO-8601. */
|
|
89
|
+
updatedAt: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* A PATCH: a key left out keeps the stored value. The first save must carry `apiBaseUrl`,
|
|
93
|
+
* `apiKey` and `webhookSecret` (`connectWithToken` is the one-paste way in). The two credentials
|
|
94
|
+
* are write-only: absent, null or empty keeps the stored one.
|
|
95
|
+
*/
|
|
96
|
+
export interface UpdateEspConnectionInput {
|
|
97
|
+
provider?: string;
|
|
98
|
+
enabled?: boolean;
|
|
99
|
+
apiBaseUrl?: string;
|
|
100
|
+
storeId?: string | null;
|
|
101
|
+
apiKey?: string | null;
|
|
102
|
+
webhookSecret?: string | null;
|
|
103
|
+
defaultListId?: string | null;
|
|
104
|
+
syncContacts?: boolean;
|
|
105
|
+
syncOrders?: boolean;
|
|
106
|
+
syncProducts?: boolean;
|
|
107
|
+
syncCarts?: boolean;
|
|
108
|
+
syncSubscriptions?: boolean;
|
|
109
|
+
cartIdleMinutes?: number;
|
|
110
|
+
/** At least 1, and longer than `cartIdleMinutes`. */
|
|
111
|
+
cartMaxAgeDays?: number;
|
|
112
|
+
orderBackfillDays?: number;
|
|
113
|
+
fieldMappings?: unknown;
|
|
114
|
+
}
|
|
115
|
+
/** The one-paste way in: where the platform lives, and the one-time token copied out of it. */
|
|
116
|
+
export interface ConnectEspWithTokenInput {
|
|
117
|
+
apiBaseUrl: string;
|
|
118
|
+
connectToken: string;
|
|
119
|
+
}
|
|
120
|
+
/** What `test` found: a result, not a refusal. */
|
|
121
|
+
export interface EspConnectionTestResult {
|
|
122
|
+
ok: boolean;
|
|
123
|
+
message: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* What a backfill can send, in the order a full one sends it: products first, so order lines
|
|
127
|
+
* can match a product the platform already holds; customer groups before customers, because a
|
|
128
|
+
* group the platform first meets inside a customer has only its id and name. Pinned to the
|
|
129
|
+
* engine's list by this package's spec.
|
|
130
|
+
*/
|
|
131
|
+
export declare const ESP_BACKFILL_RESOURCES: readonly ["products", "customer_groups", "customers", "orders"];
|
|
132
|
+
export type EspBackfillResource = (typeof ESP_BACKFILL_RESOURCES)[number];
|
|
133
|
+
/**
|
|
134
|
+
* One attempt to send one record to the e-mail platform. The request the engine sent and the
|
|
135
|
+
* platform's raw answer are deliberately not read here: they carry the customer's personal data
|
|
136
|
+
* and are kept as audit evidence, not as an API.
|
|
137
|
+
*/
|
|
138
|
+
export interface EspSyncLog {
|
|
139
|
+
id: string;
|
|
140
|
+
channelId: string;
|
|
141
|
+
provider: string;
|
|
142
|
+
/** `customer`, `order`, `product`, `cart`, `subscription`, `customer_group`. */
|
|
143
|
+
entityType: string;
|
|
144
|
+
entityId: string;
|
|
145
|
+
/** The platform's reference for the record, when it answered one. */
|
|
146
|
+
externalRef: string | null;
|
|
147
|
+
/** The dotted event sent, e.g. `order.created`. */
|
|
148
|
+
eventType: string;
|
|
149
|
+
/** `pending`, `success`, `failed` or `skipped`; only a `failed` attempt can be retried. */
|
|
150
|
+
status: string;
|
|
151
|
+
/** The platform's HTTP status; null when it never answered. */
|
|
152
|
+
responseStatus: number | null;
|
|
153
|
+
/** Why it failed, in a sentence for staff; null otherwise. */
|
|
154
|
+
error: string | null;
|
|
155
|
+
attempt: number;
|
|
156
|
+
durationMs: number | null;
|
|
157
|
+
/** ISO-8601. */
|
|
158
|
+
createdAt: string;
|
|
159
|
+
}
|
|
160
|
+
/** Which attempts `syncLogs` lists; every member narrows, and none means all. */
|
|
161
|
+
export interface EspSyncLogFilter {
|
|
162
|
+
entityType?: string;
|
|
163
|
+
entityId?: string;
|
|
164
|
+
status?: string;
|
|
165
|
+
}
|
|
166
|
+
/** The largest page `syncLogs` asks for; the default is 25. */
|
|
167
|
+
export declare const ESP_SYNC_LOG_PAGE_LIMIT = 100;
|
|
168
|
+
/**
|
|
169
|
+
* The store's e-mail marketing connection (sixtynine.email): connecting and configuring it,
|
|
170
|
+
* sending the store's history, and the log of what was sent (`admin.integrations.esp`). Always
|
|
171
|
+
* the store the client is scoped to; a SuperAdmin head acts on ANOTHER store with
|
|
172
|
+
* `admin.withTenant({ scope: { kind: 'channel', code } })`, or a per-call `tenant`.
|
|
173
|
+
*
|
|
174
|
+
* Every method needs `UpdateSettings` (the reads too: the engine guards them with the write's
|
|
175
|
+
* permission). An app installation is refused the connection lifecycle
|
|
176
|
+
* (`APP_CREDENTIAL_NOT_ALLOWED`), and a store without the e-mail marketing plugin every method
|
|
177
|
+
* (`PLUGIN_ACCESS_DENIED`, 403; never for a SuperAdmin).
|
|
178
|
+
*/
|
|
179
|
+
export interface EspModule {
|
|
180
|
+
/**
|
|
181
|
+
* The store's connection, or `null` when it has none.
|
|
182
|
+
*
|
|
183
|
+
* @effect read
|
|
184
|
+
* @permission UpdateSettings
|
|
185
|
+
*/
|
|
186
|
+
connection(options?: Call): Promise<EspConnection | null>;
|
|
187
|
+
/**
|
|
188
|
+
* Configure the connection by hand; the first call creates it. Answers the saved connection.
|
|
189
|
+
*
|
|
190
|
+
* Refused, with nothing saved:
|
|
191
|
+
* - `ESP_INPUT_INVALID` (`ValidationError`, 400): a first save without `apiBaseUrl`, `apiKey`
|
|
192
|
+
* or `webhookSecret`; an abandoned-cart window that can never report a cart; an explicit
|
|
193
|
+
* null for a stored setting. `details[]` names each field;
|
|
194
|
+
* - `ESP_API_BASE_URL_INVALID` (400): a URL that is not https, carries credentials, or names a
|
|
195
|
+
* host the deployment does not allow;
|
|
196
|
+
* - `ESP_HOST_CHANGE_REQUIRES_CREDENTIALS` (422): moving to another host without that host's
|
|
197
|
+
* `apiKey` AND `webhookSecret` in the same call;
|
|
198
|
+
* - `ORGANIZATION_WORKSPACE_NOT_A_STORE` (422): switching on, or storing a credential, in an
|
|
199
|
+
* organization's workspace.
|
|
200
|
+
*
|
|
201
|
+
* @effect write
|
|
202
|
+
* @permission UpdateSettings
|
|
203
|
+
*/
|
|
204
|
+
update(input: UpdateEspConnectionInput, options?: Call): Promise<EspConnection>;
|
|
205
|
+
/**
|
|
206
|
+
* The one-paste way in: spend a one-time connect token at the platform for the store's
|
|
207
|
+
* credentials, store them, switch the connection on, and hand the platform back a read
|
|
208
|
+
* credential for this store, with which it starts importing the store's customers, orders and
|
|
209
|
+
* products. Answers the connection.
|
|
210
|
+
*
|
|
211
|
+
* The hand-back, the e-mail gateway and the inbound webhook are SOFT: a failure there still
|
|
212
|
+
* answers the (live) connection, with the reason in `connectMetadata.credentialsPush.error`,
|
|
213
|
+
* `.emailGateway.skippedReason` or `.inboundWebhook.error`. Read them: a resolved call is not
|
|
214
|
+
* a full success.
|
|
215
|
+
*
|
|
216
|
+
* Refused, with nothing saved: `ESP_INPUT_INVALID` (400, a blank token);
|
|
217
|
+
* `ESP_API_BASE_URL_INVALID` (400); `ESP_CONNECT_TOKEN_REJECTED` (422, the platform refused
|
|
218
|
+
* the token: unknown, used, expired, or too many attempts; the sentence says which);
|
|
219
|
+
* `ESP_PROVIDER_UNAVAILABLE` (422, the platform could not be reached or answered something
|
|
220
|
+
* unusable; the token may still be good); `ORGANIZATION_WORKSPACE_NOT_A_STORE` (422).
|
|
221
|
+
*
|
|
222
|
+
* @effect irreversible
|
|
223
|
+
* @permission UpdateSettings
|
|
224
|
+
*/
|
|
225
|
+
connectWithToken(input: ConnectEspWithTokenInput, options?: Call): Promise<EspConnection>;
|
|
226
|
+
/**
|
|
227
|
+
* Hand the platform a FRESH read credential for this store (the previous one is not resent:
|
|
228
|
+
* the engine never stores it). Soft like the connect: a refusal answers the connection with
|
|
229
|
+
* `connectMetadata.credentialsPush.error` set, and `.retryable` says whether repeating helps.
|
|
230
|
+
*
|
|
231
|
+
* Refused: `ESP_CONNECTION_NOT_FOUND` (404); `ESP_RECONNECT_REQUIRED` (422, a connection
|
|
232
|
+
* configured by hand has no store id on the platform).
|
|
233
|
+
*
|
|
234
|
+
* @effect irreversible
|
|
235
|
+
* @permission UpdateSettings
|
|
236
|
+
*/
|
|
237
|
+
retryCredentialsPush(options?: Call): Promise<EspConnection>;
|
|
238
|
+
/**
|
|
239
|
+
* Ask the platform again to send suppressions, bounces, complaints and consent changes back
|
|
240
|
+
* to this store. Soft: a failure answers the connection with
|
|
241
|
+
* `connectMetadata.inboundWebhook.error` set.
|
|
242
|
+
*
|
|
243
|
+
* Refused: `ESP_CONNECTION_NOT_FOUND` (404).
|
|
244
|
+
*
|
|
245
|
+
* @effect write
|
|
246
|
+
* @permission UpdateSettings
|
|
247
|
+
*/
|
|
248
|
+
retryInboundWebhook(options?: Call): Promise<EspConnection>;
|
|
249
|
+
/**
|
|
250
|
+
* Remove the store's connection: the platform is told to stop sending first, then the stored
|
|
251
|
+
* credentials are deleted. `true` when a connection was removed, `false` when there was none.
|
|
252
|
+
* A platform that cannot be told never blocks the removal.
|
|
253
|
+
*
|
|
254
|
+
* @effect destructive
|
|
255
|
+
* @permission UpdateSettings
|
|
256
|
+
*/
|
|
257
|
+
delete(options?: Call): Promise<boolean>;
|
|
258
|
+
/**
|
|
259
|
+
* Ask the platform whether the stored credentials work. Never refuses for what it finds: no
|
|
260
|
+
* connection, or credentials the platform rejects, answers `ok: false` with the reason.
|
|
261
|
+
*
|
|
262
|
+
* @effect read
|
|
263
|
+
* @permission UpdateSettings
|
|
264
|
+
*/
|
|
265
|
+
test(options?: Call): Promise<EspConnectionTestResult>;
|
|
266
|
+
/**
|
|
267
|
+
* Send the store's history to the platform, without firing its automations: the named
|
|
268
|
+
* resources, in {@link ESP_BACKFILL_RESOURCES} order whatever order they are named in, or
|
|
269
|
+
* every resource when none are named. Each resource goes only while its sync is on
|
|
270
|
+
* (`syncProducts`, `syncContacts` for customers and groups, `syncOrders`). Queued: the call
|
|
271
|
+
* answers once the work is queued, and the sync log shows each record.
|
|
272
|
+
*
|
|
273
|
+
* It sends personal data (the customer list) to a third party, which cannot be taken back.
|
|
274
|
+
*
|
|
275
|
+
* Refused, with nothing queued: `ESP_INPUT_INVALID` (400, an empty list, or a resource the
|
|
276
|
+
* backfill does not know); `ESP_CONNECTION_NOT_FOUND` (404); `ESP_CONNECTION_DISABLED` (422).
|
|
277
|
+
*
|
|
278
|
+
* @effect irreversible
|
|
279
|
+
* @permission UpdateSettings
|
|
280
|
+
*/
|
|
281
|
+
backfill(resources?: readonly EspBackfillResource[], options?: Call): Promise<void>;
|
|
282
|
+
/**
|
|
283
|
+
* The attempts to send this store's records, newest first, 25 to a page (at most
|
|
284
|
+
* {@link ESP_SYNC_LOG_PAGE_LIMIT}).
|
|
285
|
+
*
|
|
286
|
+
* @effect read
|
|
287
|
+
* @permission UpdateSettings
|
|
288
|
+
*/
|
|
289
|
+
syncLogs(filter?: EspSyncLogFilter & ListOptions): Promise<Page<EspSyncLog>>;
|
|
290
|
+
/**
|
|
291
|
+
* Queue a FAILED attempt again, rebuilt from what it recorded. Answers the attempt retried
|
|
292
|
+
* (its row is not changed; the new attempt gets a row of its own).
|
|
293
|
+
*
|
|
294
|
+
* Refused, with nothing queued: `ESP_SYNC_LOG_NOT_FOUND` (404, not this store's);
|
|
295
|
+
* `ESP_SYNC_NOT_RETRYABLE` (422, the attempt did not fail); `ESP_SYNC_RETRY_NOT_POSSIBLE` (422,
|
|
296
|
+
* it failed but cannot be rebuilt; the sentence says what to do by hand).
|
|
297
|
+
*
|
|
298
|
+
* @effect irreversible
|
|
299
|
+
* @permission UpdateSettings
|
|
300
|
+
*/
|
|
301
|
+
retrySync(syncLogId: string, options?: Call): Promise<EspSyncLog>;
|
|
302
|
+
}
|
|
303
|
+
export declare const ESP_CONNECTION_QUERY = "\n query EspConnection {\n espConnection { \n id\n channelId\n provider\n enabled\n apiBaseUrl\n storeId\n defaultListId\n syncContacts\n syncOrders\n syncProducts\n syncCarts\n syncSubscriptions\n cartIdleMinutes\n cartMaxAgeDays\n orderBackfillDays\n fieldMappings\n connectMetadata\n createdAt\n updatedAt\n }\n }\n";
|
|
304
|
+
export declare const UPDATE_ESP_CONNECTION_MUTATION = "\n mutation UpdateEspConnection($input: UpdateEspConnectionInput!) {\n updateEspConnection(input: $input) { \n id\n channelId\n provider\n enabled\n apiBaseUrl\n storeId\n defaultListId\n syncContacts\n syncOrders\n syncProducts\n syncCarts\n syncSubscriptions\n cartIdleMinutes\n cartMaxAgeDays\n orderBackfillDays\n fieldMappings\n connectMetadata\n createdAt\n updatedAt\n }\n }\n";
|
|
305
|
+
export declare const CONNECT_ESP_WITH_TOKEN_MUTATION = "\n mutation ConnectEspWithToken($input: ConnectEspWithTokenInput!) {\n connectEspWithToken(input: $input) { \n id\n channelId\n provider\n enabled\n apiBaseUrl\n storeId\n defaultListId\n syncContacts\n syncOrders\n syncProducts\n syncCarts\n syncSubscriptions\n cartIdleMinutes\n cartMaxAgeDays\n orderBackfillDays\n fieldMappings\n connectMetadata\n createdAt\n updatedAt\n }\n }\n";
|
|
306
|
+
export declare const RETRY_ESP_CREDENTIALS_PUSH_MUTATION = "\n mutation RetryEspCredentialsPush {\n retryEspCredentialsPush { \n id\n channelId\n provider\n enabled\n apiBaseUrl\n storeId\n defaultListId\n syncContacts\n syncOrders\n syncProducts\n syncCarts\n syncSubscriptions\n cartIdleMinutes\n cartMaxAgeDays\n orderBackfillDays\n fieldMappings\n connectMetadata\n createdAt\n updatedAt\n }\n }\n";
|
|
307
|
+
export declare const RETRY_ESP_INBOUND_WEBHOOK_MUTATION = "\n mutation RetryEspInboundWebhook {\n retryEspInboundWebhook { \n id\n channelId\n provider\n enabled\n apiBaseUrl\n storeId\n defaultListId\n syncContacts\n syncOrders\n syncProducts\n syncCarts\n syncSubscriptions\n cartIdleMinutes\n cartMaxAgeDays\n orderBackfillDays\n fieldMappings\n connectMetadata\n createdAt\n updatedAt\n }\n }\n";
|
|
308
|
+
export declare const DELETE_ESP_CONNECTION_MUTATION = "\n mutation DeleteEspConnection {\n deleteEspConnection\n }\n";
|
|
309
|
+
export declare const TEST_ESP_CONNECTION_MUTATION = "\n mutation TestEspConnection {\n testEspConnection { ok message }\n }\n";
|
|
310
|
+
export declare const TRIGGER_ESP_BACKFILL_MUTATION = "\n mutation TriggerMarketingBackfill($resources: [String!]) {\n triggerMarketingBackfill(resources: $resources)\n }\n";
|
|
311
|
+
export declare const ESP_SYNC_LOGS_QUERY = "\n query EspSyncLogs($options: EspSyncLogListOptions) {\n espSyncLogs(options: $options) {\n items { \n id\n channelId\n provider\n entityType\n entityId\n externalRef\n eventType\n status\n responseStatus\n error\n attempt\n durationMs\n createdAt\n }\n totalItems\n }\n }\n";
|
|
312
|
+
export declare const RETRY_ESP_SYNC_MUTATION = "\n mutation RetryEspSync($syncLogId: ID!) {\n retryEspSync(syncLogId: $syncLogId) { \n id\n channelId\n provider\n entityType\n entityId\n externalRef\n eventType\n status\n responseStatus\n error\n attempt\n durationMs\n createdAt\n }\n }\n";
|
|
313
|
+
export declare function createEspModule(transport: Transport): EspModule;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { pageFromVendureList, readOffsetCursor, } from '@sixtyninecommerce/core';
|
|
2
|
+
/**
|
|
3
|
+
* What a backfill can send, in the order a full one sends it: products first, so order lines
|
|
4
|
+
* can match a product the platform already holds; customer groups before customers, because a
|
|
5
|
+
* group the platform first meets inside a customer has only its id and name. Pinned to the
|
|
6
|
+
* engine's list by this package's spec.
|
|
7
|
+
*/
|
|
8
|
+
export const ESP_BACKFILL_RESOURCES = [
|
|
9
|
+
'products',
|
|
10
|
+
'customer_groups',
|
|
11
|
+
'customers',
|
|
12
|
+
'orders',
|
|
13
|
+
];
|
|
14
|
+
/** The largest page `syncLogs` asks for; the default is 25. */
|
|
15
|
+
export const ESP_SYNC_LOG_PAGE_LIMIT = 100;
|
|
16
|
+
const ESP_SYNC_LOG_PAGE_SIZE = 25;
|
|
17
|
+
const CONNECTION_FIELDS = /* GraphQL */ `
|
|
18
|
+
id
|
|
19
|
+
channelId
|
|
20
|
+
provider
|
|
21
|
+
enabled
|
|
22
|
+
apiBaseUrl
|
|
23
|
+
storeId
|
|
24
|
+
defaultListId
|
|
25
|
+
syncContacts
|
|
26
|
+
syncOrders
|
|
27
|
+
syncProducts
|
|
28
|
+
syncCarts
|
|
29
|
+
syncSubscriptions
|
|
30
|
+
cartIdleMinutes
|
|
31
|
+
cartMaxAgeDays
|
|
32
|
+
orderBackfillDays
|
|
33
|
+
fieldMappings
|
|
34
|
+
connectMetadata
|
|
35
|
+
createdAt
|
|
36
|
+
updatedAt
|
|
37
|
+
`;
|
|
38
|
+
const SYNC_LOG_FIELDS = /* GraphQL */ `
|
|
39
|
+
id
|
|
40
|
+
channelId
|
|
41
|
+
provider
|
|
42
|
+
entityType
|
|
43
|
+
entityId
|
|
44
|
+
externalRef
|
|
45
|
+
eventType
|
|
46
|
+
status
|
|
47
|
+
responseStatus
|
|
48
|
+
error
|
|
49
|
+
attempt
|
|
50
|
+
durationMs
|
|
51
|
+
createdAt
|
|
52
|
+
`;
|
|
53
|
+
export const ESP_CONNECTION_QUERY = /* GraphQL */ `
|
|
54
|
+
query EspConnection {
|
|
55
|
+
espConnection { ${CONNECTION_FIELDS} }
|
|
56
|
+
}
|
|
57
|
+
`;
|
|
58
|
+
export const UPDATE_ESP_CONNECTION_MUTATION = /* GraphQL */ `
|
|
59
|
+
mutation UpdateEspConnection($input: UpdateEspConnectionInput!) {
|
|
60
|
+
updateEspConnection(input: $input) { ${CONNECTION_FIELDS} }
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
export const CONNECT_ESP_WITH_TOKEN_MUTATION = /* GraphQL */ `
|
|
64
|
+
mutation ConnectEspWithToken($input: ConnectEspWithTokenInput!) {
|
|
65
|
+
connectEspWithToken(input: $input) { ${CONNECTION_FIELDS} }
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
export const RETRY_ESP_CREDENTIALS_PUSH_MUTATION = /* GraphQL */ `
|
|
69
|
+
mutation RetryEspCredentialsPush {
|
|
70
|
+
retryEspCredentialsPush { ${CONNECTION_FIELDS} }
|
|
71
|
+
}
|
|
72
|
+
`;
|
|
73
|
+
export const RETRY_ESP_INBOUND_WEBHOOK_MUTATION = /* GraphQL */ `
|
|
74
|
+
mutation RetryEspInboundWebhook {
|
|
75
|
+
retryEspInboundWebhook { ${CONNECTION_FIELDS} }
|
|
76
|
+
}
|
|
77
|
+
`;
|
|
78
|
+
export const DELETE_ESP_CONNECTION_MUTATION = /* GraphQL */ `
|
|
79
|
+
mutation DeleteEspConnection {
|
|
80
|
+
deleteEspConnection
|
|
81
|
+
}
|
|
82
|
+
`;
|
|
83
|
+
export const TEST_ESP_CONNECTION_MUTATION = /* GraphQL */ `
|
|
84
|
+
mutation TestEspConnection {
|
|
85
|
+
testEspConnection { ok message }
|
|
86
|
+
}
|
|
87
|
+
`;
|
|
88
|
+
export const TRIGGER_ESP_BACKFILL_MUTATION = /* GraphQL */ `
|
|
89
|
+
mutation TriggerMarketingBackfill($resources: [String!]) {
|
|
90
|
+
triggerMarketingBackfill(resources: $resources)
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
export const ESP_SYNC_LOGS_QUERY = /* GraphQL */ `
|
|
94
|
+
query EspSyncLogs($options: EspSyncLogListOptions) {
|
|
95
|
+
espSyncLogs(options: $options) {
|
|
96
|
+
items { ${SYNC_LOG_FIELDS} }
|
|
97
|
+
totalItems
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
`;
|
|
101
|
+
export const RETRY_ESP_SYNC_MUTATION = /* GraphQL */ `
|
|
102
|
+
mutation RetryEspSync($syncLogId: ID!) {
|
|
103
|
+
retryEspSync(syncLogId: $syncLogId) { ${SYNC_LOG_FIELDS} }
|
|
104
|
+
}
|
|
105
|
+
`;
|
|
106
|
+
export function createEspModule(transport) {
|
|
107
|
+
const connectionMutation = async (query, field, variables, options) => {
|
|
108
|
+
const data = await transport.graphql({ api: 'admin', query, ...(variables ? { variables } : {}) }, options);
|
|
109
|
+
const connection = data[field];
|
|
110
|
+
if (!connection)
|
|
111
|
+
throw new Error(`The engine answered no ${field}`);
|
|
112
|
+
return connection;
|
|
113
|
+
};
|
|
114
|
+
const syncLogPage = async (filter, skip, take, options) => {
|
|
115
|
+
const data = await transport.graphql({
|
|
116
|
+
api: 'admin',
|
|
117
|
+
query: ESP_SYNC_LOGS_QUERY,
|
|
118
|
+
variables: { options: { ...filter, skip, take } },
|
|
119
|
+
}, options);
|
|
120
|
+
return pageFromVendureList(data.espSyncLogs, skip, take, (cursor) => syncLogPage(filter, readOffsetCursor(cursor), take, options));
|
|
121
|
+
};
|
|
122
|
+
return {
|
|
123
|
+
async connection(options) {
|
|
124
|
+
const data = await transport.graphql({ api: 'admin', query: ESP_CONNECTION_QUERY }, options);
|
|
125
|
+
return data.espConnection ?? null;
|
|
126
|
+
},
|
|
127
|
+
update(input, options) {
|
|
128
|
+
// Sent as given: an absent key keeps the stored value, and the engine names anything it
|
|
129
|
+
// refuses.
|
|
130
|
+
return connectionMutation(UPDATE_ESP_CONNECTION_MUTATION, 'updateEspConnection', { input }, options);
|
|
131
|
+
},
|
|
132
|
+
connectWithToken(input, options) {
|
|
133
|
+
return connectionMutation(CONNECT_ESP_WITH_TOKEN_MUTATION, 'connectEspWithToken', { input }, options);
|
|
134
|
+
},
|
|
135
|
+
retryCredentialsPush(options) {
|
|
136
|
+
return connectionMutation(RETRY_ESP_CREDENTIALS_PUSH_MUTATION, 'retryEspCredentialsPush', undefined, options);
|
|
137
|
+
},
|
|
138
|
+
retryInboundWebhook(options) {
|
|
139
|
+
return connectionMutation(RETRY_ESP_INBOUND_WEBHOOK_MUTATION, 'retryEspInboundWebhook', undefined, options);
|
|
140
|
+
},
|
|
141
|
+
async delete(options) {
|
|
142
|
+
const data = await transport.graphql({ api: 'admin', query: DELETE_ESP_CONNECTION_MUTATION }, options);
|
|
143
|
+
return data.deleteEspConnection === true;
|
|
144
|
+
},
|
|
145
|
+
async test(options) {
|
|
146
|
+
const data = await transport.graphql({ api: 'admin', query: TEST_ESP_CONNECTION_MUTATION }, options);
|
|
147
|
+
return data.testEspConnection;
|
|
148
|
+
},
|
|
149
|
+
async backfill(resources, options) {
|
|
150
|
+
// `undefined` stays off the wire (every resource); a list goes as given, an empty one
|
|
151
|
+
// included, so the engine is the one that refuses it.
|
|
152
|
+
await transport.graphql({
|
|
153
|
+
api: 'admin',
|
|
154
|
+
query: TRIGGER_ESP_BACKFILL_MUTATION,
|
|
155
|
+
variables: { resources: resources === undefined ? undefined : [...resources] },
|
|
156
|
+
}, options);
|
|
157
|
+
},
|
|
158
|
+
syncLogs(filter) {
|
|
159
|
+
const { after, limit, entityType, entityId, status, ...options } = filter ?? {};
|
|
160
|
+
const take = Math.min(Math.max(limit ?? ESP_SYNC_LOG_PAGE_SIZE, 1), ESP_SYNC_LOG_PAGE_LIMIT);
|
|
161
|
+
const skip = after === undefined ? 0 : readOffsetCursor(after);
|
|
162
|
+
return syncLogPage({ entityType, entityId, status }, skip, take, options);
|
|
163
|
+
},
|
|
164
|
+
async retrySync(syncLogId, options) {
|
|
165
|
+
const data = await transport.graphql({ api: 'admin', query: RETRY_ESP_SYNC_MUTATION, variables: { syncLogId } }, options);
|
|
166
|
+
return data.retryEspSync;
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|