@sixtyninecommerce/admin 0.6.0 → 0.8.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.
Files changed (39) hide show
  1. package/README.md +359 -2
  2. package/dist/apps/assertion.d.ts +30 -3
  3. package/dist/apps/assertion.js +40 -3
  4. package/dist/apps/config.d.ts +39 -0
  5. package/dist/apps/config.js +22 -0
  6. package/dist/apps/credential.d.ts +5 -0
  7. package/dist/apps/credential.js +55 -4
  8. package/dist/apps/index.d.ts +11 -0
  9. package/dist/client.d.ts +54 -1
  10. package/dist/client.js +34 -1
  11. package/dist/custom-objects/index.d.ts +66 -0
  12. package/dist/custom-objects/index.js +48 -0
  13. package/dist/customers/index.d.ts +225 -0
  14. package/dist/customers/index.js +279 -0
  15. package/dist/documents/index.d.ts +432 -0
  16. package/dist/documents/index.js +289 -0
  17. package/dist/index.d.ts +34 -2
  18. package/dist/index.js +16 -1
  19. package/dist/jobs/index.d.ts +143 -0
  20. package/dist/jobs/index.js +132 -0
  21. package/dist/metafields/index.d.ts +291 -0
  22. package/dist/metafields/index.js +141 -0
  23. package/dist/orders/index.d.ts +106 -0
  24. package/dist/orders/index.js +115 -0
  25. package/dist/orders/surcharges.d.ts +121 -0
  26. package/dist/orders/surcharges.js +110 -0
  27. package/dist/payments/index.d.ts +244 -0
  28. package/dist/payments/index.js +103 -0
  29. package/dist/payments/providers.d.ts +281 -0
  30. package/dist/payments/providers.js +205 -0
  31. package/dist/platform/provision-store.d.ts +9 -26
  32. package/dist/platform/provision-store.js +8 -66
  33. package/dist/tax/index.d.ts +128 -0
  34. package/dist/tax/index.js +101 -0
  35. package/dist/tenant/capabilities.d.ts +15 -0
  36. package/dist/types.d.ts +20 -3
  37. package/dist/uploads/index.d.ts +146 -0
  38. package/dist/uploads/index.js +72 -0
  39. package/package.json +3 -3
@@ -0,0 +1,279 @@
1
+ import { errorFromErrorResult, isErrorResult, pageFromVendureList, readOffsetCursor, } from '@sixtyninecommerce/core';
2
+ /**
3
+ * Customers — the commerce master record (headless spec §6.5).
4
+ *
5
+ * Commerce owns customer identity and addresses; a vertical stores a
6
+ * `platformCustomerId` and asks here. The two things worth knowing before
7
+ * reading further are both traps this module exists to close:
8
+ *
9
+ * 1. **`create` wraps `createChannelCustomer`, never core `createCustomer`.**
10
+ * Vendure's own mutation silently SHARES a customer across channels when the
11
+ * email already exists anywhere on the platform (ADR-016): it finds that
12
+ * customer and pushes the new channel onto them. On a multi-tenant platform
13
+ * that is a cross-tenant data leak wearing the clothes of a convenience.
14
+ * There is no way to reach the leaking path through this SDK.
15
+ * 2. **`erase` is a scrub, not a delete.** It removes the person and keeps the
16
+ * record, the orders and the documents. It is the only destructive customer
17
+ * operation the platform has.
18
+ */
19
+ export const CUSTOMER_FIELDS = /* GraphQL */ `
20
+ id
21
+ createdAt
22
+ updatedAt
23
+ title
24
+ firstName
25
+ lastName
26
+ emailAddress
27
+ phoneNumber
28
+ groups {
29
+ id
30
+ name
31
+ }
32
+ `;
33
+ export const CUSTOMER_ADDRESS_FIELDS = /* GraphQL */ `
34
+ id
35
+ fullName
36
+ company
37
+ streetLine1
38
+ streetLine2
39
+ city
40
+ province
41
+ postalCode
42
+ country {
43
+ code
44
+ name
45
+ }
46
+ phoneNumber
47
+ defaultShippingAddress
48
+ defaultBillingAddress
49
+ `;
50
+ export const LIST_QUERY = /* GraphQL */ `
51
+ query Customers($options: CustomerListOptions) {
52
+ customers(options: $options) {
53
+ items { ${CUSTOMER_FIELDS} }
54
+ totalItems
55
+ }
56
+ }
57
+ `;
58
+ export const GET_QUERY = /* GraphQL */ `
59
+ query CustomerById($id: ID!) {
60
+ customer(id: $id) { ${CUSTOMER_FIELDS} }
61
+ }
62
+ `;
63
+ export const ADDRESSES_QUERY = /* GraphQL */ `
64
+ query CustomerAddresses($id: ID!) {
65
+ customer(id: $id) {
66
+ id
67
+ addresses { ${CUSTOMER_ADDRESS_FIELDS} }
68
+ }
69
+ }
70
+ `;
71
+ /**
72
+ * The CHANNEL-SCOPED creation mutation. See the module docblock — core
73
+ * `createCustomer` is not an option, and this SDK exposes no path to it.
74
+ */
75
+ export const CREATE_MUTATION = /* GraphQL */ `
76
+ mutation CreateChannelCustomer($input: CreateCustomerInput!, $password: String) {
77
+ createChannelCustomer(input: $input, password: $password) {
78
+ id
79
+ emailAddress
80
+ createdNew
81
+ }
82
+ }
83
+ `;
84
+ export const UPDATE_MUTATION = /* GraphQL */ `
85
+ mutation UpdateCustomer($input: UpdateCustomerInput!) {
86
+ updateCustomer(input: $input) {
87
+ ... on Customer { ${CUSTOMER_FIELDS} }
88
+ ... on ErrorResult { errorCode message }
89
+ }
90
+ }
91
+ `;
92
+ export const INVITE_MUTATION = /* GraphQL */ `
93
+ mutation InviteCustomer($customerId: ID!, $mode: CustomerInviteMode) {
94
+ inviteCustomer(customerId: $customerId, mode: $mode) {
95
+ customerId
96
+ emailAddress
97
+ mode
98
+ sentAt
99
+ }
100
+ }
101
+ `;
102
+ export const RESEND_INVITE_MUTATION = /* GraphQL */ `
103
+ mutation ResendCustomerInvitation($customerId: ID!, $mode: CustomerInviteMode) {
104
+ resendCustomerInvitation(customerId: $customerId, mode: $mode) {
105
+ customerId
106
+ emailAddress
107
+ mode
108
+ sentAt
109
+ }
110
+ }
111
+ `;
112
+ export const ERASE_MUTATION = /* GraphQL */ `
113
+ mutation EraseCustomer(
114
+ $customerId: ID!
115
+ $reason: String!
116
+ $force: Boolean
117
+ $idempotencyKey: String
118
+ ) {
119
+ eraseCustomer(
120
+ customerId: $customerId
121
+ reason: $reason
122
+ force: $force
123
+ idempotencyKey: $idempotencyKey
124
+ ) {
125
+ customerId
126
+ erasedAt
127
+ ordersRetained
128
+ documentsRetained
129
+ forced
130
+ reason
131
+ }
132
+ }
133
+ `;
134
+ export const ERASURE_QUERY = /* GraphQL */ `
135
+ query CustomerErasure($customerId: ID!) {
136
+ customerErasure(customerId: $customerId) {
137
+ customerId
138
+ erasedAt
139
+ ordersRetained
140
+ documentsRetained
141
+ forced
142
+ reason
143
+ }
144
+ }
145
+ `;
146
+ export const ADD_TO_GROUP_MUTATION = /* GraphQL */ `
147
+ mutation AddCustomersToGroup($customerGroupId: ID!, $customerIds: [ID!]!) {
148
+ addCustomersToGroup(customerGroupId: $customerGroupId, customerIds: $customerIds) {
149
+ id
150
+ name
151
+ }
152
+ }
153
+ `;
154
+ export const REMOVE_FROM_GROUP_MUTATION = /* GraphQL */ `
155
+ mutation RemoveCustomersFromGroup($customerGroupId: ID!, $customerIds: [ID!]!) {
156
+ removeCustomersFromGroup(customerGroupId: $customerGroupId, customerIds: $customerIds) {
157
+ id
158
+ name
159
+ }
160
+ }
161
+ `;
162
+ export const CREATE_ADDRESS_MUTATION = /* GraphQL */ `
163
+ mutation CreateCustomerAddress($customerId: ID!, $input: CreateAddressInput!) {
164
+ createCustomerAddress(customerId: $customerId, input: $input) {
165
+ ${CUSTOMER_ADDRESS_FIELDS}
166
+ }
167
+ }
168
+ `;
169
+ export const UPDATE_ADDRESS_MUTATION = /* GraphQL */ `
170
+ mutation UpdateCustomerAddress($input: UpdateAddressInput!) {
171
+ updateCustomerAddress(input: $input) { ${CUSTOMER_ADDRESS_FIELDS} }
172
+ }
173
+ `;
174
+ export const DELETE_ADDRESS_MUTATION = /* GraphQL */ `
175
+ mutation DeleteCustomerAddress($id: ID!) {
176
+ deleteCustomerAddress(id: $id) { success }
177
+ }
178
+ `;
179
+ const DEFAULT_PAGE_SIZE = 25;
180
+ export function createCustomersModule(transport) {
181
+ const listPage = async (skip, take, options) => {
182
+ const data = await transport.graphql({ api: 'admin', query: LIST_QUERY, variables: { options: { skip, take } } }, options);
183
+ return pageFromVendureList(data.customers, skip, take, (cursor) => listPage(readOffsetCursor(cursor), take, options));
184
+ };
185
+ return {
186
+ list(options) {
187
+ // The Admin API is offset-paged; the offset hides inside the cursor so a
188
+ // consumer only ever sees `Page<T>` (spec §9.3).
189
+ const take = options?.limit ?? DEFAULT_PAGE_SIZE;
190
+ const skip = options?.after === undefined ? 0 : readOffsetCursor(options.after);
191
+ return listPage(skip, take, options);
192
+ },
193
+ async get(id, options) {
194
+ const data = await transport.graphql({ api: 'admin', query: GET_QUERY, variables: { id } }, options);
195
+ return data.customer;
196
+ },
197
+ async create(input, options) {
198
+ const data = await transport.graphql({
199
+ api: 'admin',
200
+ query: CREATE_MUTATION,
201
+ variables: { input, password: options?.password ?? null },
202
+ }, options);
203
+ return data.createChannelCustomer;
204
+ },
205
+ async update(id, input, options) {
206
+ const data = await transport.graphql({ api: 'admin', query: UPDATE_MUTATION, variables: { input: { id, ...input } } }, options);
207
+ // `updateCustomer` is a UNION — `Customer | EmailAddressConflictError` —
208
+ // delivered at HTTP 200, so the transport never throws for it. Returned
209
+ // unchecked, a rename onto an address already taken on the channel
210
+ // resolved "successfully" with an error object, and the caller saw a
211
+ // `Customer` whose `id` was undefined.
212
+ if (isErrorResult(data.updateCustomer))
213
+ throw errorFromErrorResult(data.updateCustomer);
214
+ return data.updateCustomer;
215
+ },
216
+ async invite(id, options) {
217
+ // `resend` picks the SEPARATE mutation rather than a flag on one: the two
218
+ // behave identically on the server and exist apart only so a dashboard
219
+ // can label the repeat honestly. A still-valid set-password token is
220
+ // reused rather than rotated, so a link already in the customer's inbox
221
+ // keeps working.
222
+ const query = options?.resend === true ? RESEND_INVITE_MUTATION : INVITE_MUTATION;
223
+ const data = await transport.graphql({ api: 'admin', query, variables: { customerId: id, mode: options?.mode ?? null } }, options);
224
+ return (data.inviteCustomer ?? data.resendCustomerInvitation);
225
+ },
226
+ async erase(id, options) {
227
+ const data = await transport.graphql({
228
+ api: 'admin',
229
+ query: ERASE_MUTATION,
230
+ variables: {
231
+ customerId: id,
232
+ reason: options.reason,
233
+ force: options.force ?? null,
234
+ idempotencyKey: options.idempotencyKey ?? null,
235
+ },
236
+ }, options);
237
+ return data.eraseCustomer;
238
+ },
239
+ async erasure(id, options) {
240
+ const data = await transport.graphql({ api: 'admin', query: ERASURE_QUERY, variables: { customerId: id } }, options);
241
+ return data.customerErasure;
242
+ },
243
+ groups: {
244
+ async add(groupId, customerIds, options) {
245
+ const data = await transport.graphql({
246
+ api: 'admin',
247
+ query: ADD_TO_GROUP_MUTATION,
248
+ variables: { customerGroupId: groupId, customerIds },
249
+ }, options);
250
+ return data.addCustomersToGroup;
251
+ },
252
+ async remove(groupId, customerIds, options) {
253
+ const data = await transport.graphql({
254
+ api: 'admin',
255
+ query: REMOVE_FROM_GROUP_MUTATION,
256
+ variables: { customerGroupId: groupId, customerIds },
257
+ }, options);
258
+ return data.removeCustomersFromGroup;
259
+ },
260
+ },
261
+ addresses: {
262
+ async list(customerId, options) {
263
+ const data = await transport.graphql({ api: 'admin', query: ADDRESSES_QUERY, variables: { id: customerId } }, options);
264
+ return data.customer?.addresses ?? [];
265
+ },
266
+ async create(customerId, input, options) {
267
+ const data = await transport.graphql({ api: 'admin', query: CREATE_ADDRESS_MUTATION, variables: { customerId, input } }, options);
268
+ return data.createCustomerAddress;
269
+ },
270
+ async update(input, options) {
271
+ const data = await transport.graphql({ api: 'admin', query: UPDATE_ADDRESS_MUTATION, variables: { input } }, options);
272
+ return data.updateCustomerAddress;
273
+ },
274
+ async delete(id, options) {
275
+ await transport.graphql({ api: 'admin', query: DELETE_ADDRESS_MUTATION, variables: { id } }, options);
276
+ },
277
+ },
278
+ };
279
+ }