@sixtyninecommerce/admin 0.8.0 → 0.9.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 +2445 -17
- package/dist/api-tokens/index.d.ts +15 -5
- package/dist/api-tokens/index.js +1 -0
- package/dist/apps/event-subscription.d.ts +59 -0
- package/dist/apps/event-subscription.js +32 -0
- package/dist/apps/hook-secret.d.ts +22 -0
- package/dist/apps/hook-secret.js +36 -0
- package/dist/apps/index.d.ts +54 -3
- package/dist/apps/index.js +17 -0
- package/dist/audit/index.d.ts +7 -0
- package/dist/auth/queries.d.ts +5 -1
- package/dist/auth/queries.js +6 -0
- package/dist/bulk/index.d.ts +323 -0
- package/dist/bulk/index.js +162 -0
- package/dist/catalog/assets.d.ts +147 -0
- package/dist/catalog/assets.js +164 -0
- package/dist/catalog/collections.d.ts +109 -0
- package/dist/catalog/collections.js +91 -0
- package/dist/catalog/facets.d.ts +103 -0
- package/dist/catalog/facets.js +100 -0
- package/dist/catalog/index.d.ts +115 -0
- package/dist/catalog/index.js +21 -0
- package/dist/catalog/options.d.ts +89 -0
- package/dist/catalog/options.js +88 -0
- package/dist/catalog/products-bulk.d.ts +21 -0
- package/dist/catalog/products-bulk.js +58 -0
- package/dist/catalog/products.d.ts +489 -0
- package/dist/catalog/products.js +365 -0
- package/dist/catalog/properties.d.ts +234 -0
- package/dist/catalog/properties.js +158 -0
- package/dist/catalog/types.d.ts +174 -0
- package/dist/catalog/types.js +141 -0
- package/dist/catalog/variants.d.ts +274 -0
- package/dist/catalog/variants.js +258 -0
- package/dist/catalog/visibility.d.ts +57 -0
- package/dist/catalog/visibility.js +59 -0
- package/dist/client.d.ts +171 -3
- package/dist/client.js +81 -12
- package/dist/compliance/index.d.ts +88 -0
- package/dist/compliance/index.js +88 -0
- package/dist/customer-data-redaction.d.ts +14 -0
- package/dist/customer-data-redaction.js +22 -0
- package/dist/customers/index.d.ts +428 -17
- package/dist/customers/index.js +322 -15
- package/dist/documents/index.d.ts +513 -16
- package/dist/documents/index.js +229 -3
- package/dist/events/index.d.ts +259 -0
- package/dist/events/index.js +147 -0
- package/dist/feeds/ai.d.ts +46 -0
- package/dist/feeds/ai.js +43 -0
- package/dist/feeds/categories.d.ts +50 -0
- package/dist/feeds/categories.js +56 -0
- package/dist/feeds/configs.d.ts +54 -0
- package/dist/feeds/configs.js +85 -0
- package/dist/feeds/identifier-fields.d.ts +25 -0
- package/dist/feeds/identifier-fields.js +29 -0
- package/dist/feeds/index.d.ts +54 -0
- package/dist/feeds/index.js +46 -0
- package/dist/feeds/preserve.d.ts +38 -0
- package/dist/feeds/preserve.js +74 -0
- package/dist/feeds/rules.d.ts +42 -0
- package/dist/feeds/rules.js +56 -0
- package/dist/feeds/types.d.ts +654 -0
- package/dist/feeds/types.js +135 -0
- package/dist/fulfillments/index.d.ts +360 -0
- package/dist/fulfillments/index.js +425 -0
- package/dist/heads/index.d.ts +60 -0
- package/dist/heads/index.js +45 -0
- package/dist/hooks/assignments.d.ts +90 -0
- package/dist/hooks/assignments.js +53 -0
- package/dist/hooks/index.d.ts +97 -0
- package/dist/hooks/index.js +76 -0
- package/dist/index.d.ts +84 -9
- package/dist/index.js +16 -1
- package/dist/jobs/bulk-action-run.d.ts +65 -0
- package/dist/jobs/bulk-action-run.js +70 -0
- package/dist/locations/index.d.ts +6 -2
- package/dist/meta/index.d.ts +32 -0
- package/dist/orders/commit-edit.d.ts +123 -0
- package/dist/orders/commit-edit.js +142 -0
- package/dist/orders/get.d.ts +722 -0
- package/dist/orders/get.js +530 -0
- package/dist/orders/index.d.ts +105 -20
- package/dist/orders/index.js +44 -0
- package/dist/orders/line-price-preview.d.ts +297 -0
- package/dist/orders/line-price-preview.js +50 -0
- package/dist/orders/manual-discounts.d.ts +132 -0
- package/dist/orders/manual-discounts.js +95 -0
- package/dist/orders/manual-pricing.d.ts +192 -0
- package/dist/orders/manual-pricing.js +72 -0
- package/dist/orders/order-entry.d.ts +566 -0
- package/dist/orders/order-entry.js +129 -0
- package/dist/orders/parcel-charge.d.ts +45 -0
- package/dist/orders/parcel-charge.js +55 -0
- package/dist/orders/plan-edit.d.ts +489 -0
- package/dist/orders/plan-edit.js +93 -0
- package/dist/orders/status.d.ts +235 -0
- package/dist/orders/status.js +96 -0
- package/dist/orders/surcharges.d.ts +75 -2
- package/dist/orders/surcharges.js +110 -4
- package/dist/payments/account-credit.d.ts +171 -0
- package/dist/payments/account-credit.js +107 -0
- package/dist/payments/index.d.ts +234 -9
- package/dist/payments/index.js +90 -0
- package/dist/platform/catalog.d.ts +148 -0
- package/dist/platform/catalog.js +74 -0
- package/dist/platform/entitlements.d.ts +111 -0
- package/dist/platform/entitlements.js +86 -0
- package/dist/platform/legal-entities.d.ts +139 -0
- package/dist/platform/legal-entities.js +126 -0
- package/dist/platform/legal-entity-numbering.d.ts +103 -0
- package/dist/platform/legal-entity-numbering.js +101 -0
- package/dist/platform/organization-membership.d.ts +80 -0
- package/dist/platform/organization-membership.js +71 -0
- package/dist/platform/organization-settings.d.ts +33 -0
- package/dist/platform/organization-settings.js +42 -0
- package/dist/platform/organization-sharing.d.ts +172 -0
- package/dist/platform/organization-sharing.js +120 -0
- package/dist/platform/organizations.d.ts +205 -0
- package/dist/platform/organizations.js +180 -0
- package/dist/platform/provision-store.d.ts +88 -8
- package/dist/platform/provision-store.js +12 -0
- package/dist/platform/reports.d.ts +46 -0
- package/dist/platform/reports.js +31 -0
- package/dist/platform/server-metrics.d.ts +58 -0
- package/dist/platform/server-metrics.js +11 -0
- package/dist/pos/index.d.ts +567 -0
- package/dist/pos/index.js +205 -0
- package/dist/pricing/index.d.ts +405 -0
- package/dist/pricing/index.js +351 -0
- package/dist/provenance/index.d.ts +93 -0
- package/dist/provenance/index.js +53 -0
- package/dist/reports/index.d.ts +199 -0
- package/dist/reports/index.js +154 -0
- package/dist/shipping/parcel-count-suggestion.d.ts +52 -0
- package/dist/shipping/parcel-count-suggestion.js +73 -0
- package/dist/shipping/parcel-rule.d.ts +48 -0
- package/dist/shipping/parcel-rule.js +91 -0
- package/dist/stock/index.d.ts +166 -0
- package/dist/stock/index.js +115 -0
- package/dist/stock/transfers.d.ts +520 -0
- package/dist/stock/transfers.js +437 -0
- package/dist/stored-value/index.d.ts +154 -0
- package/dist/stored-value/index.js +130 -0
- package/dist/tenant/capabilities.d.ts +10 -0
- package/dist/tenant/entitlements.d.ts +35 -0
- package/dist/tenant/entitlements.js +15 -0
- package/dist/tenant/field-groups.d.ts +64 -0
- package/dist/tenant/field-groups.js +34 -0
- package/dist/tenant/legal-entity.d.ts +32 -0
- package/dist/tenant/legal-entity.js +41 -0
- package/dist/tenant/notifications.d.ts +148 -0
- package/dist/tenant/notifications.js +79 -0
- package/dist/tenant/retention.d.ts +10 -4
- package/dist/tenant/settings-sources.d.ts +103 -0
- package/dist/tenant/settings-sources.js +92 -0
- package/dist/types.d.ts +86 -11
- package/dist/uploads/index.d.ts +11 -7
- package/dist/users/index.d.ts +104 -0
- package/dist/users/index.js +80 -0
- package/package.json +3 -2
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type Page, type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import { type CatalogueOwnership } from '../catalog/types.js';
|
|
3
|
+
import { type ComplianceRequest } from '../compliance/index.js';
|
|
2
4
|
import type { Call, ListOptions } from '../types.js';
|
|
3
5
|
/**
|
|
4
6
|
* Customers — the commerce master record (headless spec §6.5).
|
|
@@ -16,6 +18,31 @@ import type { Call, ListOptions } from '../types.js';
|
|
|
16
18
|
* 2. **`erase` is a scrub, not a delete.** It removes the person and keeps the
|
|
17
19
|
* record, the orders and the documents. It is the only destructive customer
|
|
18
20
|
* operation the platform has.
|
|
21
|
+
*
|
|
22
|
+
* ## Acting inside a customer's cart: `actAs`
|
|
23
|
+
*
|
|
24
|
+
* `actAs(customerId, { reason })` answers a trusted-agent session: a Shop API
|
|
25
|
+
* bearer for that customer, valid 15 minutes and never renewed. It is usable
|
|
26
|
+
* in exactly ONE way — as the customer token of a storefront client for the
|
|
27
|
+
* same store:
|
|
28
|
+
*
|
|
29
|
+
* ```ts
|
|
30
|
+
* const session = await admin.customers.actAs(customerId, { reason: 'Phone order' });
|
|
31
|
+
* const shop = await createStorefrontClient({
|
|
32
|
+
* storeCode: 'my-store',
|
|
33
|
+
* cdnUrl,
|
|
34
|
+
* customerToken: session.token, // @sixtyninecommerce/client
|
|
35
|
+
* });
|
|
36
|
+
* await shop.commerce.addToCart(variantId, 2); // the customer's own cart
|
|
37
|
+
* await admin.customers.endAgentSession(session.id);
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* The Admin API, the CMS and the plugins service all refuse it. On the Shop
|
|
41
|
+
* API it may run cart and checkout only; an address-book edit, a password or
|
|
42
|
+
* email change, order history beyond the active order, or anything else is
|
|
43
|
+
* refused with `PermissionDeniedError` `AGENT_SESSION_SCOPE`. Every order row
|
|
44
|
+
* it writes records the caller as `on_behalf_of`; the customer sees the order
|
|
45
|
+
* as their own.
|
|
19
46
|
*/
|
|
20
47
|
export declare const CUSTOMER_FIELDS = "\n id\n createdAt\n updatedAt\n title\n firstName\n lastName\n emailAddress\n phoneNumber\n groups {\n id\n name\n }\n";
|
|
21
48
|
export declare const CUSTOMER_ADDRESS_FIELDS = "\n id\n fullName\n company\n streetLine1\n streetLine2\n city\n province\n postalCode\n country {\n code\n name\n }\n phoneNumber\n defaultShippingAddress\n defaultBillingAddress\n";
|
|
@@ -25,15 +52,48 @@ export declare const ADDRESSES_QUERY = "\n query CustomerAddresses($id: ID!) {\
|
|
|
25
52
|
/**
|
|
26
53
|
* The CHANNEL-SCOPED creation mutation. See the module docblock — core
|
|
27
54
|
* `createCustomer` is not an option, and this SDK exposes no path to it.
|
|
55
|
+
*
|
|
56
|
+
* No `password` argument: the server ignores one (and a later release refuses
|
|
57
|
+
* it with `CUSTOMER_PASSWORD_NOT_ALLOWED`), because staff and API tokens never
|
|
58
|
+
* set a customer's password. `invite` is how a customer gets one.
|
|
28
59
|
*/
|
|
29
|
-
export declare const CREATE_MUTATION = "\n mutation CreateChannelCustomer($input: CreateCustomerInput
|
|
60
|
+
export declare const CREATE_MUTATION = "\n mutation CreateChannelCustomer($input: CreateCustomerInput!) {\n createChannelCustomer(input: $input) {\n id\n emailAddress\n createdNew\n }\n }\n";
|
|
30
61
|
export declare const UPDATE_MUTATION = "\n mutation UpdateCustomer($input: UpdateCustomerInput!) {\n updateCustomer(input: $input) {\n ... on Customer { \n id\n createdAt\n updatedAt\n title\n firstName\n lastName\n emailAddress\n phoneNumber\n groups {\n id\n name\n }\n }\n ... on ErrorResult { errorCode message }\n }\n }\n";
|
|
31
62
|
export declare const INVITE_MUTATION = "\n mutation InviteCustomer($customerId: ID!, $mode: CustomerInviteMode) {\n inviteCustomer(customerId: $customerId, mode: $mode) {\n customerId\n emailAddress\n mode\n sentAt\n }\n }\n";
|
|
32
63
|
export declare const RESEND_INVITE_MUTATION = "\n mutation ResendCustomerInvitation($customerId: ID!, $mode: CustomerInviteMode) {\n resendCustomerInvitation(customerId: $customerId, mode: $mode) {\n customerId\n emailAddress\n mode\n sentAt\n }\n }\n";
|
|
64
|
+
/**
|
|
65
|
+
* "Invite all trade customers" — the whole channel's B2B-group members in one
|
|
66
|
+
* call. Counts always come back; unless `dryRun`, a background job sends the
|
|
67
|
+
* invitations and `jobId` names it.
|
|
68
|
+
*/
|
|
69
|
+
export declare const INVITE_B2B_MUTATION = "\n mutation InviteB2BCustomers($input: InviteB2BCustomersInput) {\n inviteB2BCustomers(input: $input) {\n dryRun\n total\n eligible\n skippedHasPassword\n skippedPending\n skippedUnreachable\n jobId\n }\n }\n";
|
|
33
70
|
export declare const ERASE_MUTATION = "\n mutation EraseCustomer(\n $customerId: ID!\n $reason: String!\n $force: Boolean\n $idempotencyKey: String\n ) {\n eraseCustomer(\n customerId: $customerId\n reason: $reason\n force: $force\n idempotencyKey: $idempotencyKey\n ) {\n customerId\n erasedAt\n ordersRetained\n documentsRetained\n forced\n reason\n }\n }\n";
|
|
34
71
|
export declare const ERASURE_QUERY = "\n query CustomerErasure($customerId: ID!) {\n customerErasure(customerId: $customerId) {\n customerId\n erasedAt\n ordersRetained\n documentsRetained\n forced\n reason\n }\n }\n";
|
|
72
|
+
export declare const ACT_AS_MUTATION = "\n mutation ActAsCustomer($customerId: ID!, $reason: String!) {\n actAsCustomer(customerId: $customerId, reason: $reason) {\n id\n customerId\n token\n expiresAt\n }\n }\n";
|
|
73
|
+
export declare const REQUEST_DATA_MUTATION = "\n mutation RequestCustomerData($customerId: ID!, $reason: String!, $idempotencyKey: String) {\n requestCustomerData(customerId: $customerId, reason: $reason, idempotencyKey: $idempotencyKey) {\n \n id\n kind\n subjectId\n requestedBy\n reason\n requestedAt\n dueAt\n addressedInstallationIds\n acknowledgements { id requestId installationId acknowledgedAt note }\n overdueInstallationIds\n overdue\n\n }\n }\n";
|
|
74
|
+
export declare const END_AGENT_SESSION_MUTATION = "\n mutation EndCustomerAgentSession($sessionId: ID!) {\n endCustomerAgentSession(sessionId: $sessionId) {\n id\n customerId\n revokedAt\n }\n }\n";
|
|
35
75
|
export declare const ADD_TO_GROUP_MUTATION = "\n mutation AddCustomersToGroup($customerGroupId: ID!, $customerIds: [ID!]!) {\n addCustomersToGroup(customerGroupId: $customerGroupId, customerIds: $customerIds) {\n id\n name\n }\n }\n";
|
|
36
76
|
export declare const REMOVE_FROM_GROUP_MUTATION = "\n mutation RemoveCustomersFromGroup($customerGroupId: ID!, $customerIds: [ID!]!) {\n removeCustomersFromGroup(customerGroupId: $customerGroupId, customerIds: $customerIds) {\n id\n name\n }\n }\n";
|
|
77
|
+
/**
|
|
78
|
+
* External keys (incentives program decision 7): when another system is the customer master it
|
|
79
|
+
* addresses this store's customers and segments by its own keys. Every key is this store's: another
|
|
80
|
+
* store's key reads as one nobody filed. Each document is its own request, so a client ahead of the
|
|
81
|
+
* engine fails only that call, never the customer page.
|
|
82
|
+
*/
|
|
83
|
+
export declare const CUSTOMER_EXTERNAL_REF_FIELDS = "\n id\n createdAt\n updatedAt\n system\n ref\n";
|
|
84
|
+
export declare const EXTERNAL_KEYED_GROUP_FIELDS = "\n id\n name\n externalKey\n \n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n\n";
|
|
85
|
+
export declare const BY_EXTERNAL_REF_QUERY = "\n query CustomerByExternalRef($system: String!, $ref: String!) {\n customerByExternalRef(system: $system, ref: $ref) { \n id\n createdAt\n updatedAt\n title\n firstName\n lastName\n emailAddress\n phoneNumber\n groups {\n id\n name\n }\n }\n }\n";
|
|
86
|
+
export declare const EXTERNAL_REFS_QUERY = "\n query CustomerExternalRefs($id: ID!) {\n customer(id: $id) {\n id\n externalRefs { \n id\n createdAt\n updatedAt\n system\n ref\n }\n }\n }\n";
|
|
87
|
+
export declare const UPSERT_BY_EXTERNAL_REF_MUTATION = "\n mutation UpsertCustomerByExternalRef(\n $input: UpsertCustomerByExternalRefInput!\n $idempotencyKey: String\n ) {\n upsertCustomerByExternalRef(input: $input, idempotencyKey: $idempotencyKey) {\n customer { \n id\n createdAt\n updatedAt\n title\n firstName\n lastName\n emailAddress\n phoneNumber\n groups {\n id\n name\n }\n }\n created\n matchedByEmail\n updated\n }\n }\n";
|
|
88
|
+
export declare const GROUP_BY_EXTERNAL_KEY_QUERY = "\n query CustomerGroupByExternalKey($key: String!) {\n customerGroupByExternalKey(key: $key) { \n id\n name\n externalKey\n \n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n\n }\n }\n";
|
|
89
|
+
/** A customer group as {@link CustomerGroupsModule.get} reads it. */
|
|
90
|
+
export declare const CUSTOMER_GROUP_FIELDS = "\n id\n createdAt\n updatedAt\n name\n externalKey\n \n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n\n";
|
|
91
|
+
export declare const CUSTOMER_GROUP_QUERY = "\n query CustomerGroup($id: ID!) {\n customerGroup(id: $id) { \n id\n createdAt\n updatedAt\n name\n externalKey\n \n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n\n }\n }\n";
|
|
92
|
+
export declare const GROUP_EXTERNAL_KEY_QUERY = "\n query CustomerGroupExternalKey($id: ID!) {\n customerGroup(id: $id) {\n id\n externalKey\n }\n }\n";
|
|
93
|
+
export declare const UPSERT_GROUP_BY_EXTERNAL_KEY_MUTATION = "\n mutation UpsertCustomerGroupByExternalKey($key: String!, $name: String!) {\n upsertCustomerGroupByExternalKey(key: $key, name: $name) {\n customerGroup { \n id\n name\n externalKey\n \n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n\n }\n created\n renamed\n }\n }\n";
|
|
94
|
+
export declare const REPLACE_GROUP_MEMBERS_MUTATION = "\n mutation ReplaceCustomerGroupMembers(\n $key: String!\n $customerExternalRefs: [CustomerExternalRefInput!]!\n $idempotencyKey: String\n ) {\n replaceCustomerGroupMembers(\n key: $key\n customerExternalRefs: $customerExternalRefs\n idempotencyKey: $idempotencyKey\n ) {\n customerGroup { \n id\n name\n externalKey\n \n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n\n }\n memberCount\n added\n removed\n unknownRefs {\n system\n ref\n }\n }\n }\n";
|
|
95
|
+
/** The most member keys one `customers.groups.replaceMembers` call takes. */
|
|
96
|
+
export declare const MAX_REPLACE_GROUP_MEMBERS = 5000;
|
|
37
97
|
export declare const CREATE_ADDRESS_MUTATION = "\n mutation CreateCustomerAddress($customerId: ID!, $input: CreateAddressInput!) {\n createCustomerAddress(customerId: $customerId, input: $input) {\n \n id\n fullName\n company\n streetLine1\n streetLine2\n city\n province\n postalCode\n country {\n code\n name\n }\n phoneNumber\n defaultShippingAddress\n defaultBillingAddress\n\n }\n }\n";
|
|
38
98
|
export declare const UPDATE_ADDRESS_MUTATION = "\n mutation UpdateCustomerAddress($input: UpdateAddressInput!) {\n updateCustomerAddress(input: $input) { \n id\n fullName\n company\n streetLine1\n streetLine2\n city\n province\n postalCode\n country {\n code\n name\n }\n phoneNumber\n defaultShippingAddress\n defaultBillingAddress\n }\n }\n";
|
|
39
99
|
export declare const DELETE_ADDRESS_MUTATION = "\n mutation DeleteCustomerAddress($id: ID!) {\n deleteCustomerAddress(id: $id) { success }\n }\n";
|
|
@@ -41,6 +101,93 @@ export interface CustomerGroupRef {
|
|
|
41
101
|
id: string;
|
|
42
102
|
name: string;
|
|
43
103
|
}
|
|
104
|
+
/** Another system's key for a customer of this store. */
|
|
105
|
+
export interface CustomerExternalRef {
|
|
106
|
+
id: string;
|
|
107
|
+
createdAt: string;
|
|
108
|
+
updatedAt: string;
|
|
109
|
+
/** The master system's name: a lower-case slug such as `visos`. */
|
|
110
|
+
system: string;
|
|
111
|
+
/** The master system's own id for the customer, compared exactly. */
|
|
112
|
+
ref: string;
|
|
113
|
+
[extra: string]: unknown;
|
|
114
|
+
}
|
|
115
|
+
/** A customer key as sent: which system, and its id there. */
|
|
116
|
+
export interface CustomerExternalRefKey {
|
|
117
|
+
system: string;
|
|
118
|
+
ref: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* A customer as the master system holds it. Every field but the key is a PATCH: absent or `null`
|
|
122
|
+
* keeps what the store has.
|
|
123
|
+
*/
|
|
124
|
+
export interface UpsertCustomerByExternalRefInput {
|
|
125
|
+
/** A lower-case slug: letters, digits, `.`, `_`, `-`, at most 64 characters. */
|
|
126
|
+
system: string;
|
|
127
|
+
/** At most 255 characters; compared exactly, surrounding whitespace trimmed. */
|
|
128
|
+
ref: string;
|
|
129
|
+
/**
|
|
130
|
+
* Required when the store does not know the key yet. A customer of this store with this address
|
|
131
|
+
* (any letter case) is LINKED to the key rather than duplicated. On a customer the key already
|
|
132
|
+
* names, a changed address follows {@link UpdateCustomerInput.emailAddress}'s rules.
|
|
133
|
+
*/
|
|
134
|
+
emailAddress?: string | null;
|
|
135
|
+
firstName?: string | null;
|
|
136
|
+
lastName?: string | null;
|
|
137
|
+
phoneNumber?: string | null;
|
|
138
|
+
title?: string | null;
|
|
139
|
+
}
|
|
140
|
+
/** What {@link CustomersModule.upsertByExternalRef} answers. */
|
|
141
|
+
export interface UpsertedCustomer {
|
|
142
|
+
customer: Customer;
|
|
143
|
+
/** A customer was created for this store. */
|
|
144
|
+
created: boolean;
|
|
145
|
+
/** The key was unknown and linked to the store's existing customer with the address. */
|
|
146
|
+
matchedByEmail: boolean;
|
|
147
|
+
/** Fields of an existing customer were written. */
|
|
148
|
+
updated: boolean;
|
|
149
|
+
}
|
|
150
|
+
/** One of the store's customer groups, as {@link CustomerGroupsModule.get} answers it. */
|
|
151
|
+
export interface CustomerGroup {
|
|
152
|
+
id: string;
|
|
153
|
+
/** ISO-8601 UTC. */
|
|
154
|
+
createdAt: string;
|
|
155
|
+
/** ISO-8601 UTC. */
|
|
156
|
+
updatedAt: string;
|
|
157
|
+
name: string;
|
|
158
|
+
/** This store's key for the group in the customer master, or `null` when no master keys it. */
|
|
159
|
+
externalKey: string | null;
|
|
160
|
+
/**
|
|
161
|
+
* The store's own group, or its organization's (shared while the organization shares
|
|
162
|
+
* `customer_groups`); see {@link CatalogueOwnership}. `editableHere` false: rename it in the
|
|
163
|
+
* workspace.
|
|
164
|
+
*/
|
|
165
|
+
catalogueOwnership: CatalogueOwnership;
|
|
166
|
+
}
|
|
167
|
+
/** A customer group with this store's external key, or `null` for a group nobody keyed. */
|
|
168
|
+
export interface ExternalKeyedCustomerGroup {
|
|
169
|
+
id: string;
|
|
170
|
+
name: string;
|
|
171
|
+
externalKey: string | null;
|
|
172
|
+
/** The store's own group, or its organization's; see {@link CatalogueOwnership}. */
|
|
173
|
+
catalogueOwnership: CatalogueOwnership;
|
|
174
|
+
}
|
|
175
|
+
/** What {@link CustomerGroupsModule.upsertByExternalKey} answers. */
|
|
176
|
+
export interface UpsertedCustomerGroup {
|
|
177
|
+
customerGroup: ExternalKeyedCustomerGroup;
|
|
178
|
+
created: boolean;
|
|
179
|
+
renamed: boolean;
|
|
180
|
+
}
|
|
181
|
+
/** What {@link CustomerGroupsModule.replaceMembers} answers. */
|
|
182
|
+
export interface ReplacedCustomerGroupMembers {
|
|
183
|
+
customerGroup: ExternalKeyedCustomerGroup;
|
|
184
|
+
/** The group's members in this store after the call. */
|
|
185
|
+
memberCount: number;
|
|
186
|
+
added: number;
|
|
187
|
+
removed: number;
|
|
188
|
+
/** Keys no customer of this store carries, in the order sent. Reported, never created. */
|
|
189
|
+
unknownRefs: CustomerExternalRefKey[];
|
|
190
|
+
}
|
|
44
191
|
export interface Customer {
|
|
45
192
|
id: string;
|
|
46
193
|
createdAt: string;
|
|
@@ -51,6 +198,14 @@ export interface Customer {
|
|
|
51
198
|
emailAddress: string;
|
|
52
199
|
phoneNumber: string | null;
|
|
53
200
|
groups: CustomerGroupRef[];
|
|
201
|
+
/**
|
|
202
|
+
* Set when this customer was read by an app installation below `customerData:
|
|
203
|
+
* full`: the fields its level withholds came back blanked — `null`, or `""`
|
|
204
|
+
* where the field is never null (`firstName`, `lastName`, `emailAddress`). An
|
|
205
|
+
* empty string here means "not granted", not "none on record". Absent for a
|
|
206
|
+
* customer nothing was withheld from.
|
|
207
|
+
*/
|
|
208
|
+
redacted?: true;
|
|
54
209
|
/** Forward-compat: fields a later release adds arrive camelised and untouched. */
|
|
55
210
|
[extra: string]: unknown;
|
|
56
211
|
}
|
|
@@ -71,6 +226,12 @@ export interface CustomerAddress {
|
|
|
71
226
|
defaultShippingAddress: boolean | null;
|
|
72
227
|
defaultBillingAddress: boolean | null;
|
|
73
228
|
[extra: string]: unknown;
|
|
229
|
+
/**
|
|
230
|
+
* Set when the caller's customer-data level blanked this address (an app
|
|
231
|
+
* installation below `full` reads only its country): `null`/`""` then means
|
|
232
|
+
* "not granted", not "none on record". Never write such an address back.
|
|
233
|
+
*/
|
|
234
|
+
redacted?: true;
|
|
74
235
|
}
|
|
75
236
|
export interface CreateCustomerInput {
|
|
76
237
|
emailAddress: string;
|
|
@@ -85,6 +246,23 @@ export interface UpdateCustomerInput {
|
|
|
85
246
|
firstName?: string;
|
|
86
247
|
lastName?: string;
|
|
87
248
|
phoneNumber?: string;
|
|
249
|
+
/**
|
|
250
|
+
* A new address for the customer in THIS store. For a customer with an account, the store's
|
|
251
|
+
* customer (orders, addresses, groups, prices, credit, ERP links) moves to the account of the
|
|
252
|
+
* new address: the one that already exists for it on the platform, else a new one with no
|
|
253
|
+
* password. No account is ever renamed, nothing is mailed, and the old address stops signing in
|
|
254
|
+
* to this store; send `invite` for the new address to sign in. The customer's records in other
|
|
255
|
+
* stores keep their address and account. A guest customer (no account) simply gets the address.
|
|
256
|
+
* Sending the current address back unchanged (any letter case) is not a change and passes.
|
|
257
|
+
*
|
|
258
|
+
* Refused, for every caller: `PermissionDeniedError` `CUSTOMER_EMAIL_CHANGE_NOT_ALLOWED` for an
|
|
259
|
+
* erased customer (add a new customer instead), `PermissionDeniedError`
|
|
260
|
+
* `SHARED_CUSTOMER_NOT_ALLOWED` for one customer record another store holds too, and
|
|
261
|
+
* `BusinessRuleError` `EMAIL_ADDRESS_CONFLICT_ERROR` when something else in this store already
|
|
262
|
+
* answers to the address (another customer, or another account's sign-in), and
|
|
263
|
+
* `ValidationError` `CUSTOMER_EMAIL_INVALID` for a value that is not an email address given to a
|
|
264
|
+
* customer with an account, or any value longer than 255 characters.
|
|
265
|
+
*/
|
|
88
266
|
emailAddress?: string;
|
|
89
267
|
customFields?: Record<string, unknown>;
|
|
90
268
|
}
|
|
@@ -98,6 +276,11 @@ export interface CreatedCustomer {
|
|
|
98
276
|
* whole point of the channel-scoped mutation.
|
|
99
277
|
*/
|
|
100
278
|
createdNew: boolean;
|
|
279
|
+
/**
|
|
280
|
+
* Set when the caller's customer-data level blanked `emailAddress` (an app
|
|
281
|
+
* installation below `identity`): "" then means "not granted".
|
|
282
|
+
*/
|
|
283
|
+
redacted?: true;
|
|
101
284
|
}
|
|
102
285
|
export type CustomerInviteMode = 'PASSWORD_SETUP' | 'MAGIC_LINK';
|
|
103
286
|
export interface CustomerInvitation {
|
|
@@ -106,6 +289,32 @@ export interface CustomerInvitation {
|
|
|
106
289
|
mode: CustomerInviteMode;
|
|
107
290
|
sentAt: string;
|
|
108
291
|
}
|
|
292
|
+
export interface InviteB2BCustomersOptions extends Call {
|
|
293
|
+
/** Count only; send nothing and start no job. */
|
|
294
|
+
dryRun?: boolean;
|
|
295
|
+
/**
|
|
296
|
+
* Also invite customers who already hold a live, unexpired set-password link.
|
|
297
|
+
* Their link is re-sent, not replaced, so the one already in their inbox keeps
|
|
298
|
+
* working. Off by default: they are counted as `skippedPending` instead.
|
|
299
|
+
*/
|
|
300
|
+
includePending?: boolean;
|
|
301
|
+
}
|
|
302
|
+
/** What {@link CustomersModule.inviteB2B} answers. */
|
|
303
|
+
export interface InviteB2BCustomersResult {
|
|
304
|
+
dryRun: boolean;
|
|
305
|
+
/** B2B-group customers on this store, one per login account. */
|
|
306
|
+
total: number;
|
|
307
|
+
/** Customers who would be (dry run) or were queued for an invitation. */
|
|
308
|
+
eligible: number;
|
|
309
|
+
/** Already have a password. */
|
|
310
|
+
skippedHasPassword: number;
|
|
311
|
+
/** Hold a live, unexpired set-password link; always 0 with `includePending`. */
|
|
312
|
+
skippedPending: number;
|
|
313
|
+
/** No email address, a `*.invalid` placeholder address, or no login account. */
|
|
314
|
+
skippedUnreachable: number;
|
|
315
|
+
/** The background job sending the invitations; `null` on a dry run or when `eligible` is 0. */
|
|
316
|
+
jobId: string | null;
|
|
317
|
+
}
|
|
109
318
|
/** The record of an erasure. See {@link CustomersModule.erase}. */
|
|
110
319
|
export interface CustomerErasureRecord {
|
|
111
320
|
customerId: string;
|
|
@@ -137,6 +346,37 @@ export interface EraseCustomerOptions extends Call {
|
|
|
137
346
|
/** Your own request id, recorded for provenance. */
|
|
138
347
|
idempotencyKey?: string;
|
|
139
348
|
}
|
|
349
|
+
/** A trusted-agent session. See {@link CustomersModule.actAs}. */
|
|
350
|
+
export interface CustomerAgentSession {
|
|
351
|
+
/** What {@link CustomersModule.endAgentSession} takes. */
|
|
352
|
+
id: string;
|
|
353
|
+
customerId: string;
|
|
354
|
+
/**
|
|
355
|
+
* The Shop API bearer, shown once. Pass it as `customerToken` to
|
|
356
|
+
* `createStorefrontClient` from `@sixtyninecommerce/client` — the only way it works.
|
|
357
|
+
*/
|
|
358
|
+
token: string;
|
|
359
|
+
/** ISO-8601. Fixed: refused from this instant on, and nothing renews it. */
|
|
360
|
+
expiresAt: string;
|
|
361
|
+
}
|
|
362
|
+
/** The answer to {@link CustomersModule.endAgentSession}. */
|
|
363
|
+
export interface EndedCustomerAgentSession {
|
|
364
|
+
id: string;
|
|
365
|
+
customerId: string;
|
|
366
|
+
/** ISO-8601. Ending an ended session answers the first end. */
|
|
367
|
+
revokedAt: string;
|
|
368
|
+
}
|
|
369
|
+
export interface RequestCustomerDataOptions extends Call {
|
|
370
|
+
/**
|
|
371
|
+
* Why — recorded on the request, never sent to apps, blanked if the customer
|
|
372
|
+
* is later erased. 1–1000 characters.
|
|
373
|
+
*/
|
|
374
|
+
reason: string;
|
|
375
|
+
}
|
|
376
|
+
export interface ActAsCustomerOptions extends Call {
|
|
377
|
+
/** Why — stored on the session and required. Free text, 1–1000 characters. */
|
|
378
|
+
reason: string;
|
|
379
|
+
}
|
|
140
380
|
export interface CustomerAddressesModule {
|
|
141
381
|
list(customerId: string, options?: Call): Promise<CustomerAddress[]>;
|
|
142
382
|
create(customerId: string, input: Record<string, unknown>, options?: Call): Promise<CustomerAddress>;
|
|
@@ -146,20 +386,72 @@ export interface CustomerAddressesModule {
|
|
|
146
386
|
delete(id: string, options?: Call): Promise<void>;
|
|
147
387
|
}
|
|
148
388
|
export interface CustomerGroupsModule {
|
|
149
|
-
/**
|
|
389
|
+
/**
|
|
390
|
+
* One of the ACTIVE store's customer groups by id, its `catalogueOwnership` included, or `null`
|
|
391
|
+
* for a group the store does not hold (another store's, a deleted one, an unknown id), the same
|
|
392
|
+
* for each, like every other entity `get` here. A badge shows `null` as "not found", never as
|
|
393
|
+
* the store's own group. An id that is not a uuid is refused before the engine looks with core's
|
|
394
|
+
* `ENTITY_NOT_FOUND`: branch on the `NotFoundError` class, not the code. Needs `ReadCustomer` or `ReadCustomerGroup`. Requires
|
|
395
|
+
* a platform release that serves `catalogueOwnership`: an older engine fails the call as a whole.
|
|
396
|
+
*/
|
|
397
|
+
get(id: string, options?: Call): Promise<CustomerGroup | null>;
|
|
398
|
+
/**
|
|
399
|
+
* Add customers to a group. Emits one `customer.group_changed` per customer added; a customer
|
|
400
|
+
* already in the group is left as it is and emits nothing, so naming only members emits none.
|
|
401
|
+
*/
|
|
150
402
|
add(groupId: string, customerIds: string[], options?: Call): Promise<CustomerGroupRef>;
|
|
151
403
|
remove(groupId: string, customerIds: string[], options?: Call): Promise<CustomerGroupRef>;
|
|
404
|
+
/** The store's group under the master system's segment key, or `null`. Needs `ReadCustomerGroup`. */
|
|
405
|
+
byExternalKey(key: string, options?: Call): Promise<ExternalKeyedCustomerGroup | null>;
|
|
406
|
+
/** This store's external key for a group, or `null` when no master keys it. */
|
|
407
|
+
externalKey(groupId: string, options?: Call): Promise<string | null>;
|
|
408
|
+
/**
|
|
409
|
+
* Create the store's group for a segment key, or rename the one it names. Twice is ONE group.
|
|
410
|
+
* Creating needs `CreateCustomerGroup`; renaming needs `UpdateCustomerGroup`, and for a group
|
|
411
|
+
* other stores hold too, that permission in each of them (`SHARED_CUSTOMER_GROUP_NOT_ALLOWED`).
|
|
412
|
+
* Renaming a group a member store holds from its organization's workspace is refused
|
|
413
|
+
* `MANAGED_BY_ORGANIZATION` (422 `BusinessRuleError`): rename it in the workspace
|
|
414
|
+
* (`catalogueOwnership.editableHere` is false).
|
|
415
|
+
*/
|
|
416
|
+
upsertByExternalKey(key: string, name: string, options?: Call): Promise<UpsertedCustomerGroup>;
|
|
417
|
+
/**
|
|
418
|
+
* Make the group under `key` hold EXACTLY the customers these keys name, in one transaction.
|
|
419
|
+
* At most {@link MAX_REPLACE_GROUP_MEMBERS} keys (`CUSTOMER_GROUP_MEMBERS_TOO_MANY`); a key no
|
|
420
|
+
* customer of this store carries comes back in `unknownRefs` and is never created; only this
|
|
421
|
+
* store's customers are added or removed. Needs `UpdateCustomerGroup`. A repeat under the same
|
|
422
|
+
* `idempotencyKey` answers the first call. Emits one `customer.group_changed` per customer
|
|
423
|
+
* added or removed, and a promotion on the group follows on the order's next recalculation.
|
|
424
|
+
*
|
|
425
|
+
* Known limit: atomic against other replaces and upserts of the same key, not against
|
|
426
|
+
* `add`/`remove` (core's membership doors) running at the same moment, which do not take the
|
|
427
|
+
* key's lock: a membership edit made by hand meanwhile can survive the replace or be undone.
|
|
428
|
+
*/
|
|
429
|
+
replaceMembers(key: string, customerExternalRefs: CustomerExternalRefKey[], options?: Call): Promise<ReplacedCustomerGroupMembers>;
|
|
152
430
|
}
|
|
153
431
|
export interface CustomersModule {
|
|
154
432
|
list(options?: ListOptions): Promise<Page<Customer>>;
|
|
155
433
|
get(id: string, options?: Call): Promise<Customer | null>;
|
|
156
434
|
/**
|
|
157
|
-
* Create a customer ON THIS CHANNEL
|
|
158
|
-
*
|
|
435
|
+
* Create a customer ON THIS CHANNEL, with no usable login: the customer
|
|
436
|
+
* cannot sign in until they set a password through the link `invite` mails
|
|
437
|
+
* them (or sign in with a magic link). Staff and API tokens never set a
|
|
438
|
+
* customer's password, so there is no option for one.
|
|
439
|
+
*/
|
|
440
|
+
create(input: CreateCustomerInput, options?: Call): Promise<CreatedCustomer>;
|
|
441
|
+
/**
|
|
442
|
+
* Update a customer of this store. A changed `emailAddress` of a customer with an account moves
|
|
443
|
+
* the store's customer to the account of the new address, and is refused for an erased customer
|
|
444
|
+
* (`CUSTOMER_EMAIL_CHANGE_NOT_ALLOWED`), for one record another store also holds
|
|
445
|
+
* (`SHARED_CUSTOMER_NOT_ALLOWED`), both `PermissionDeniedError`s, and for an address the store
|
|
446
|
+
* already uses (`EMAIL_ADDRESS_CONFLICT_ERROR`, a `BusinessRuleError`); see
|
|
447
|
+
* {@link UpdateCustomerInput.emailAddress}.
|
|
448
|
+
*
|
|
449
|
+
* While an app or API token owns Customer details on the store, a change of the customer's
|
|
450
|
+
* title, name, email address, phone number or VAT number by anyone else is refused
|
|
451
|
+
* `FIELD_GROUP_LOCKED` (`BusinessRuleError`); an unchanged value passes. So is adding,
|
|
452
|
+
* changing or removing one of their addresses (`addresses.*`), and deleting the customer.
|
|
453
|
+
* Creating a customer is never refused.
|
|
159
454
|
*/
|
|
160
|
-
create(input: CreateCustomerInput, options?: Call & {
|
|
161
|
-
password?: string;
|
|
162
|
-
}): Promise<CreatedCustomer>;
|
|
163
455
|
update(id: string, input: UpdateCustomerInput, options?: Call): Promise<Customer>;
|
|
164
456
|
/**
|
|
165
457
|
* Mail the customer a way in: a set-password link, or a magic-link sign-in.
|
|
@@ -171,6 +463,26 @@ export interface CustomersModule {
|
|
|
171
463
|
mode?: CustomerInviteMode;
|
|
172
464
|
resend?: boolean;
|
|
173
465
|
}): Promise<CustomerInvitation>;
|
|
466
|
+
/**
|
|
467
|
+
* Invite every trade (B2B) customer on this store to set a password: the
|
|
468
|
+
* members of the store's configured B2B customer groups, one per login
|
|
469
|
+
* account. Needs `UpdateCustomer`.
|
|
470
|
+
*
|
|
471
|
+
* Always answers the counts. Skipped, by reason: customers who already have a
|
|
472
|
+
* password, customers who cannot be reached (no email address, a `*.invalid`
|
|
473
|
+
* placeholder, no login account), and customers holding a live set-password
|
|
474
|
+
* link (unless `includePending`). With `dryRun` nothing is sent. Otherwise a
|
|
475
|
+
* background job sends the invitations one at a time, paced, and `jobId`
|
|
476
|
+
* names it; it checks every customer again when it reaches them, so what it
|
|
477
|
+
* finally sends can differ from `eligible`. Its result is
|
|
478
|
+
* `{ sent, skippedHasPassword, skippedPending, skippedUnreachable, failed }`,
|
|
479
|
+
* and one customer failing never stops the rest.
|
|
480
|
+
*
|
|
481
|
+
* Refused on the platform root channel, and — unless `dryRun` — when the store
|
|
482
|
+
* has no storefront URL or its customer-invitation email is switched off or
|
|
483
|
+
* has no recipient: the same refusals as {@link invite}.
|
|
484
|
+
*/
|
|
485
|
+
inviteB2B(options?: InviteB2BCustomersOptions): Promise<InviteB2BCustomersResult>;
|
|
174
486
|
/**
|
|
175
487
|
* GDPR erasure: scrub the person, keep the record.
|
|
176
488
|
*
|
|
@@ -187,17 +499,53 @@ export interface CustomersModule {
|
|
|
187
499
|
* that name no customer at all, which is how an invoice email log kept an
|
|
188
500
|
* erased person's address.
|
|
189
501
|
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
502
|
+
* Vendure's own JOB PAYLOADS go too, classified per queue rather than by one
|
|
503
|
+
* verdict over a column that has forty-five shapes: a declared JSON path
|
|
504
|
+
* anchored on the customer id or their address; the whole serialized Express
|
|
505
|
+
* request clone of any job that is theirs, emptied rather than picked over
|
|
506
|
+
* because its body carries the GraphQL document the shopper sent; the session
|
|
507
|
+
* token and principal identifier of a job the erased person themselves
|
|
508
|
+
* triggered (a review or a magic-link login carries their own); and an
|
|
509
|
+
* exact-address sweep for the payloads whose contracts are open. A match by
|
|
510
|
+
* ADDRESS only reaches a row whose payload names this store's channel (the
|
|
511
|
+
* table has no channel column); a match by customer id reaches it whichever
|
|
512
|
+
* channel it names, because an id belongs to one person. A row that
|
|
513
|
+
* names them ONLY as a substring inside that document, with no id to anchor
|
|
514
|
+
* on, is left alone — a substring decision about personal data in a write
|
|
515
|
+
* path is what this feature's own security review forbade.
|
|
516
|
+
* Unbounded, because settled job rows are pruned by
|
|
517
|
+
* COUNT — the newest thousand survive indefinitely — and an unsettled row is
|
|
518
|
+
* never pruned at all. Two gaps, both stated: a job that is RUNNING at that
|
|
519
|
+
* instant holds its payload in memory and writes it back when it settles, and
|
|
520
|
+
* a job's RESULT is retained (a warehouse document job returns a storage key
|
|
521
|
+
* for a PDF that renders the shipping address).
|
|
522
|
+
*
|
|
523
|
+
* Refused while a legal hold placed with `placeRetentionHold` is active
|
|
524
|
+
* (`RETENTION_HOLD_ACTIVE`; the store's retention window, `holdUntil`, does
|
|
525
|
+
* not refuse), while the customer is party to an open unpaid order (`CUSTOMER_HAS_OPEN_ORDERS`;
|
|
192
526
|
* a SuperAdmin may pass `force`), while they hold a subscription that has not
|
|
193
|
-
* ended (`CUSTOMER_HAS_ACTIVE_SUBSCRIPTIONS`),
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
527
|
+
* ended (`CUSTOMER_HAS_ACTIVE_SUBSCRIPTIONS`), while the store still holds
|
|
528
|
+
* their money as unapplied cash on their account
|
|
529
|
+
* (`CUSTOMER_HAS_UNAPPLIED_CASH`: pay it back or apply it to an invoice first
|
|
530
|
+
* and wait for the payout's refund to complete, `payments.accountCredit.list`
|
|
531
|
+
* shows what is held; `force` does not override it), when other stores on the
|
|
532
|
+
* platform hold them and the caller cannot delete customers in all of those
|
|
533
|
+
* stores (`CUSTOMER_SHARED_ACROSS_STORES`), and when the tenant context names
|
|
534
|
+
* the platform root channel rather than the customer's own
|
|
535
|
+
* (`CUSTOMER_ERASURE_CHANNEL_INVALID`).
|
|
536
|
+
*
|
|
537
|
+
* A customer other stores hold too (their login backs a customer there, or the
|
|
538
|
+
* row sits there too) is erased on EVERY one of those stores in the same call,
|
|
539
|
+
* because the login it scrubs is theirs as well. That takes a SuperAdmin, or
|
|
540
|
+
* `DeleteCustomer` on each of those stores. Every store's hold, unpaid orders
|
|
541
|
+
* and subscriptions are checked first (a refusal names the store that blocks),
|
|
542
|
+
* and each store gets its own record and `customer.deleted`. The answer is this
|
|
543
|
+
* store's record. When the login also backs a record on the platform root,
|
|
544
|
+
* outside any store, only a SuperAdmin may erase (same code, its own message).
|
|
197
545
|
*
|
|
198
|
-
* `force` overrides the OPEN-ORDER refusal and nothing else
|
|
199
|
-
* mandate will charge this person again next cycle,
|
|
200
|
-
*
|
|
546
|
+
* `force` overrides the OPEN-ORDER refusal and nothing else: a live payment
|
|
547
|
+
* mandate will charge this person again next cycle, which is not a
|
|
548
|
+
* SuperAdmin's to waive.
|
|
201
549
|
*
|
|
202
550
|
* Idempotent: erasing an already-erased customer returns the original record.
|
|
203
551
|
*
|
|
@@ -214,11 +562,74 @@ export interface CustomersModule {
|
|
|
214
562
|
*
|
|
215
563
|
* That event keeps its ids and its `external_refs`: it is the one moment an
|
|
216
564
|
* ESP, ERP, CRM or PSP can erase its own copy of the person, and blanking it
|
|
217
|
-
* would destroy the only keys to them.
|
|
565
|
+
* would destroy the only keys to them. Beside the custom-field ids, each
|
|
566
|
+
* store's event carries the keys a customer master filed there, by system
|
|
567
|
+
* name ({@link upsertByExternalRef}: `{ visos: 'P-123' }`), which the erasure
|
|
568
|
+
* then deletes: a master that knows the person only by its own key finds the
|
|
569
|
+
* record to erase, and its next sync of that key makes a NEW customer.
|
|
218
570
|
*/
|
|
219
571
|
erase(id: string, options: EraseCustomerOptions): Promise<CustomerErasureRecord>;
|
|
572
|
+
/**
|
|
573
|
+
* A SUBJECT-ACCESS REQUEST: ask every app installed on this store for the
|
|
574
|
+
* personal data it holds about this customer. Emits `customer.data_requested`,
|
|
575
|
+
* which every app installation receives whatever its event filters say; each
|
|
576
|
+
* acknowledges it within 30 days through `admin.compliance.acknowledge`, and
|
|
577
|
+
* `admin.compliance.list` shows who has not. Needs `ReadCustomer` and
|
|
578
|
+
* `UpdateCustomer`. Refused for an erased customer (`CUSTOMER_ERASED`). A
|
|
579
|
+
* repeat under the same `idempotencyKey` answers the first request.
|
|
580
|
+
*/
|
|
581
|
+
requestData(id: string, options: RequestCustomerDataOptions): Promise<ComplianceRequest>;
|
|
220
582
|
/** The erasure record, or `null` if this customer has not been erased. */
|
|
221
583
|
erasure(id: string, options?: Call): Promise<CustomerErasureRecord | null>;
|
|
584
|
+
/**
|
|
585
|
+
* Act inside a customer's cart: a 15-minute, non-renewable Shop API session
|
|
586
|
+
* for them, bounded to cart and checkout (headless spec §6.5). Needs
|
|
587
|
+
* `UpdateCustomer` AND `UpdateOrder`. Emits `customer.agent_session_started`.
|
|
588
|
+
*
|
|
589
|
+
* THE HANDOFF: the returned `token` is usable only as the `customerToken` of a
|
|
590
|
+
* storefront client for the same store — `createStorefrontClient({ storeCode,
|
|
591
|
+
* cdnUrl, customerToken: session.token })` from `@sixtyninecommerce/client`.
|
|
592
|
+
* The Admin API, the CMS and the plugins service refuse it; on the Shop API
|
|
593
|
+
* anything beyond cart and checkout is refused with `PermissionDeniedError`
|
|
594
|
+
* `AGENT_SESSION_SCOPE`.
|
|
595
|
+
*
|
|
596
|
+
* NOT idempotent, deliberately: every call mints a new session and a new
|
|
597
|
+
* token — the answer carries a credential, and an idempotency store would
|
|
598
|
+
* keep and replay it. Retrying after a timeout at worst leaves an unused
|
|
599
|
+
* session that expires on its own; end the one you are not using.
|
|
600
|
+
*
|
|
601
|
+
* Refused for an erased customer (`CUSTOMER_ERASED`), a guest record with no
|
|
602
|
+
* login (`CUSTOMER_HAS_NO_ACCOUNT`), a customer of another store
|
|
603
|
+
* (`NotFoundError` `CUSTOMER_NOT_FOUND`), the platform root channel and a
|
|
604
|
+
* location-restricted credential (`AGENT_SESSION_LOCATION_NOT_ALLOWED`).
|
|
605
|
+
*/
|
|
606
|
+
actAs(customerId: string, options: ActAsCustomerOptions): Promise<CustomerAgentSession>;
|
|
607
|
+
/**
|
|
608
|
+
* End an agent session now. The next Shop API call with its token answers 401.
|
|
609
|
+
* Ending an ended session answers the first end.
|
|
610
|
+
*/
|
|
611
|
+
endAgentSession(sessionId: string, options?: Call): Promise<EndedCustomerAgentSession>;
|
|
612
|
+
/**
|
|
613
|
+
* The store's customer under another system's key, or `null` (an unknown key, another store's,
|
|
614
|
+
* or one whose customer was deleted). Needs `ReadCustomer`.
|
|
615
|
+
*/
|
|
616
|
+
byExternalRef(system: string, ref: string, options?: Call): Promise<Customer | null>;
|
|
617
|
+
/** This store's external keys for a customer; `[]` for none or for a customer it does not hold. */
|
|
618
|
+
externalRefs(customerId: string, options?: Call): Promise<CustomerExternalRef[]>;
|
|
619
|
+
/**
|
|
620
|
+
* Create the store's customer for a master system's key, or update the one it names. Never a
|
|
621
|
+
* second customer: not on a repeat under the same `idempotencyKey`, not on a concurrent call,
|
|
622
|
+
* and not for an address the store already has (that customer is linked, `matchedByEmail`).
|
|
623
|
+
* Creating needs `CreateCustomer`; linking or changing an existing customer `UpdateCustomer`;
|
|
624
|
+
* answering a customer the key already names `ReadCustomer` or `UpdateCustomer`.
|
|
625
|
+
*
|
|
626
|
+
* Refusals: `CUSTOMER_EXTERNAL_REF_INVALID` (a malformed key),
|
|
627
|
+
* `CUSTOMER_EXTERNAL_REF_EMAIL_INVALID` (a new customer without a usable address),
|
|
628
|
+
* `CUSTOMER_EXTERNAL_REF_CONFLICT` (the customer with that address already carries another key
|
|
629
|
+
* of the same system), `CUSTOMER_EXTERNAL_REF_WRITE_CONFLICT` (a concurrent call won; send it again),
|
|
630
|
+
* and the address rules of {@link update}.
|
|
631
|
+
*/
|
|
632
|
+
upsertByExternalRef(input: UpsertCustomerByExternalRefInput, options?: Call): Promise<UpsertedCustomer>;
|
|
222
633
|
groups: CustomerGroupsModule;
|
|
223
634
|
addresses: CustomerAddressesModule;
|
|
224
635
|
}
|