@sixtyninecommerce/admin 0.7.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 +368 -2
- package/dist/payments/index.js +138 -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
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { createPage } from '@sixtyninecommerce/core';
|
|
2
|
+
import { assertDeleted, DELETION_FIELDS, fieldOf, } from './types.js';
|
|
3
|
+
const PROPERTY_FIELDS = /* GraphQL */ `
|
|
4
|
+
id
|
|
5
|
+
createdAt
|
|
6
|
+
updatedAt
|
|
7
|
+
slug
|
|
8
|
+
fieldType
|
|
9
|
+
isFilterable
|
|
10
|
+
isRequired
|
|
11
|
+
position
|
|
12
|
+
config {
|
|
13
|
+
options {
|
|
14
|
+
value
|
|
15
|
+
label
|
|
16
|
+
}
|
|
17
|
+
min
|
|
18
|
+
max
|
|
19
|
+
maxLength
|
|
20
|
+
allowedCollectionIds
|
|
21
|
+
filterableFieldSlugs
|
|
22
|
+
productFilter
|
|
23
|
+
}
|
|
24
|
+
facetId
|
|
25
|
+
translations {
|
|
26
|
+
id
|
|
27
|
+
languageCode
|
|
28
|
+
name
|
|
29
|
+
helpText
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
export const PROPERTY_GROUP_FIELDS = /* GraphQL */ `
|
|
33
|
+
id
|
|
34
|
+
createdAt
|
|
35
|
+
updatedAt
|
|
36
|
+
position
|
|
37
|
+
translations {
|
|
38
|
+
id
|
|
39
|
+
languageCode
|
|
40
|
+
name
|
|
41
|
+
}
|
|
42
|
+
properties { ${PROPERTY_FIELDS} }
|
|
43
|
+
editableHere
|
|
44
|
+
`;
|
|
45
|
+
export const PROPERTY_GROUPS_QUERY = /* GraphQL */ `
|
|
46
|
+
query CatalogPropertyGroups {
|
|
47
|
+
propertyGroups { ${PROPERTY_GROUP_FIELDS} }
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
50
|
+
export const PROPERTY_GROUP_QUERY = /* GraphQL */ `
|
|
51
|
+
query CatalogPropertyGroup($id: ID!) {
|
|
52
|
+
propertyGroup(id: $id) { ${PROPERTY_GROUP_FIELDS} }
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
export const CREATE_PROPERTY_GROUP_MUTATION = /* GraphQL */ `
|
|
56
|
+
mutation CatalogCreatePropertyGroup($input: CreatePropertyGroupInput!) {
|
|
57
|
+
createPropertyGroup(input: $input) { ${PROPERTY_GROUP_FIELDS} }
|
|
58
|
+
}
|
|
59
|
+
`;
|
|
60
|
+
export const UPDATE_PROPERTY_GROUP_MUTATION = /* GraphQL */ `
|
|
61
|
+
mutation CatalogUpdatePropertyGroup($input: UpdatePropertyGroupInput!) {
|
|
62
|
+
updatePropertyGroup(input: $input) { ${PROPERTY_GROUP_FIELDS} }
|
|
63
|
+
}
|
|
64
|
+
`;
|
|
65
|
+
export const DELETE_PROPERTY_GROUP_MUTATION = /* GraphQL */ `
|
|
66
|
+
mutation CatalogDeletePropertyGroup($id: ID!) {
|
|
67
|
+
deletePropertyGroup(id: $id) { ${DELETION_FIELDS} }
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
export const REORDER_PROPERTY_GROUPS_MUTATION = /* GraphQL */ `
|
|
71
|
+
mutation CatalogReorderPropertyGroups($ids: [ID!]!) {
|
|
72
|
+
reorderPropertyGroups(ids: $ids) { ${PROPERTY_GROUP_FIELDS} }
|
|
73
|
+
}
|
|
74
|
+
`;
|
|
75
|
+
export const CREATE_PROPERTY_MUTATION = /* GraphQL */ `
|
|
76
|
+
mutation CatalogCreateProperty($input: CreatePropertyInput!) {
|
|
77
|
+
createProperty(input: $input) { ${PROPERTY_FIELDS} }
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
export const UPDATE_PROPERTY_MUTATION = /* GraphQL */ `
|
|
81
|
+
mutation CatalogUpdateProperty($input: UpdatePropertyInput!) {
|
|
82
|
+
updateProperty(input: $input) { ${PROPERTY_FIELDS} }
|
|
83
|
+
}
|
|
84
|
+
`;
|
|
85
|
+
export const DELETE_PROPERTY_MUTATION = /* GraphQL */ `
|
|
86
|
+
mutation CatalogDeleteProperty($id: ID!) {
|
|
87
|
+
deleteProperty(id: $id) { ${DELETION_FIELDS} }
|
|
88
|
+
}
|
|
89
|
+
`;
|
|
90
|
+
export const REORDER_PROPERTIES_MUTATION = /* GraphQL */ `
|
|
91
|
+
mutation CatalogReorderProperties($groupId: ID!, $propertyIds: [ID!]!) {
|
|
92
|
+
reorderProperties(groupId: $groupId, propertyIds: $propertyIds) { ${PROPERTY_FIELDS} }
|
|
93
|
+
}
|
|
94
|
+
`;
|
|
95
|
+
export const PRODUCT_PROPERTY_VALUES_QUERY = /* GraphQL */ `
|
|
96
|
+
query CatalogProductPropertyValues($productId: ID!) {
|
|
97
|
+
productPropertyValues(productId: $productId) {
|
|
98
|
+
group { ${PROPERTY_GROUP_FIELDS} }
|
|
99
|
+
values {
|
|
100
|
+
id
|
|
101
|
+
propertyId
|
|
102
|
+
languageCode
|
|
103
|
+
value
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
`;
|
|
108
|
+
export const SET_PRODUCT_PROPERTY_VALUES_MUTATION = /* GraphQL */ `
|
|
109
|
+
mutation CatalogSetProductPropertyValues($productId: ID!, $values: [SetProductPropertyValueInput!]!) {
|
|
110
|
+
setProductPropertyValues(productId: $productId, values: $values)
|
|
111
|
+
}
|
|
112
|
+
`;
|
|
113
|
+
export const SYNC_PROPERTY_FACETS_MUTATION = /* GraphQL */ `
|
|
114
|
+
mutation CatalogSyncPropertyFacets($propertyId: ID!) {
|
|
115
|
+
syncPropertyFacets(propertyId: $propertyId) {
|
|
116
|
+
propertyId
|
|
117
|
+
items
|
|
118
|
+
unresolved
|
|
119
|
+
fieldFacets
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
`;
|
|
123
|
+
/** `catalog.syncContentFacets`; its contract is on {@link CatalogModule.syncContentFacets}. */
|
|
124
|
+
export function syncContentFacets(transport, propertyId, options) {
|
|
125
|
+
return fieldOf(transport, SYNC_PROPERTY_FACETS_MUTATION, 'syncPropertyFacets', { propertyId }, options);
|
|
126
|
+
}
|
|
127
|
+
export function createPropertiesModule(transport) {
|
|
128
|
+
const call = (document, field, variables, options) => fieldOf(transport, document, field, variables, options);
|
|
129
|
+
const deleted = async (document, field, code, id, options) => {
|
|
130
|
+
assertDeleted(code, [await call(document, field, { id }, options)]);
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
groups: {
|
|
134
|
+
async list(options) {
|
|
135
|
+
const items = await call(PROPERTY_GROUPS_QUERY, 'propertyGroups', {}, options);
|
|
136
|
+
return createPage(items, { nextCursor: null, hasNext: false, total: items.length }, () => {
|
|
137
|
+
// Unreachable while `hasNext` is false — `Page.next()` short-circuits.
|
|
138
|
+
throw new Error('propertyGroups returns a complete list; there is no next page');
|
|
139
|
+
});
|
|
140
|
+
},
|
|
141
|
+
get: (id, options) => call(PROPERTY_GROUP_QUERY, 'propertyGroup', { id }, options),
|
|
142
|
+
create: (input, options) => call(CREATE_PROPERTY_GROUP_MUTATION, 'createPropertyGroup', { input }, options),
|
|
143
|
+
update: (input, options) => call(UPDATE_PROPERTY_GROUP_MUTATION, 'updatePropertyGroup', { input }, options),
|
|
144
|
+
delete: (id, options) => deleted(DELETE_PROPERTY_GROUP_MUTATION, 'deletePropertyGroup', 'PROPERTY_GROUP_NOT_DELETED', id, options),
|
|
145
|
+
reorder: (ids, options) => call(REORDER_PROPERTY_GROUPS_MUTATION, 'reorderPropertyGroups', { ids }, options),
|
|
146
|
+
},
|
|
147
|
+
create: (input, options) => call(CREATE_PROPERTY_MUTATION, 'createProperty', { input }, options),
|
|
148
|
+
update: (input, options) => call(UPDATE_PROPERTY_MUTATION, 'updateProperty', { input }, options),
|
|
149
|
+
delete: (id, options) => deleted(DELETE_PROPERTY_MUTATION, 'deleteProperty', 'PROPERTY_NOT_DELETED', id, options),
|
|
150
|
+
reorder: (groupId, propertyIds, options) => call(REORDER_PROPERTIES_MUTATION, 'reorderProperties', { groupId, propertyIds }, options),
|
|
151
|
+
values: {
|
|
152
|
+
get: (productId, options) => call(PRODUCT_PROPERTY_VALUES_QUERY, 'productPropertyValues', { productId }, options),
|
|
153
|
+
async set(productId, values, options) {
|
|
154
|
+
await call(SET_PRODUCT_PROPERTY_VALUES_MUTATION, 'setProductPropertyValues', { productId, values }, options);
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { type Page, type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Call, ListOptions } from '../types.js';
|
|
3
|
+
/** A language code as Vendure spells it: `en`, `nl`, `pt_BR`. */
|
|
4
|
+
export type LanguageCode = string;
|
|
5
|
+
/** An asset as the catalog projects it — enough to render and to re-assign it. */
|
|
6
|
+
export interface AssetRef {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
/** A preview URL the asset server scales; absolute or relative to the engine. */
|
|
10
|
+
preview: string;
|
|
11
|
+
source: string;
|
|
12
|
+
}
|
|
13
|
+
export interface FacetValueRef {
|
|
14
|
+
id: string;
|
|
15
|
+
code: string;
|
|
16
|
+
name: string;
|
|
17
|
+
facet: {
|
|
18
|
+
id: string;
|
|
19
|
+
code: string;
|
|
20
|
+
name: string;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A product's own availability (the pre-order engine, merged 2026-09-18).
|
|
25
|
+
*
|
|
26
|
+
* - `none` — ordinary stock rules.
|
|
27
|
+
* - `comingSoon` — shown, but nobody can order it, not even from stock.
|
|
28
|
+
* - `preorder` — customers allowed to backorder may order beyond stock; everyone
|
|
29
|
+
* else can still buy what is in stock.
|
|
30
|
+
*/
|
|
31
|
+
export type ProductAvailabilityState = 'none' | 'comingSoon' | 'preorder';
|
|
32
|
+
/** A variant's: the product's states plus `inherit` (use the product's state, date and limit). */
|
|
33
|
+
export type VariantAvailabilityState = 'inherit' | ProductAvailabilityState;
|
|
34
|
+
/**
|
|
35
|
+
* Availability fields as they are READ. Every writer shares one shape: a state
|
|
36
|
+
* that is not `inherit` uses this row's own `availableFrom` and `preorderLimit`,
|
|
37
|
+
* empty ones included.
|
|
38
|
+
*/
|
|
39
|
+
export interface Availability<State extends string> {
|
|
40
|
+
availabilityState: State;
|
|
41
|
+
/**
|
|
42
|
+
* ISO-8601 UTC instant at which the state ends on its own — from then on the
|
|
43
|
+
* ordinary stock and backorder rules apply again. Null: it ends by hand.
|
|
44
|
+
*/
|
|
45
|
+
availableFrom: string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Under `preorder`: the most units per variant that may be pre-ordered beyond
|
|
48
|
+
* stock across all open orders. Null: no limit. Ignored under every other
|
|
49
|
+
* state.
|
|
50
|
+
*/
|
|
51
|
+
preorderLimit: number | null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Availability fields as they are WRITTEN. Omit a field to leave it alone, pass
|
|
55
|
+
* null to clear it.
|
|
56
|
+
*/
|
|
57
|
+
export interface AvailabilityInput<State extends string> {
|
|
58
|
+
availabilityState?: State;
|
|
59
|
+
/**
|
|
60
|
+
* An ISO-8601 instant WITH an explicit offset (`Z` or `±HH:mm`). One without
|
|
61
|
+
* is refused before the request leaves (`INVALID_DATETIME`), because the
|
|
62
|
+
* engine would read it in its own zone, not yours or the store's.
|
|
63
|
+
*/
|
|
64
|
+
availableFrom?: string | null;
|
|
65
|
+
/** A whole number ≥ 0, or null for no limit. */
|
|
66
|
+
preorderLimit?: number | null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A price the caller STATES. `basis` says which side of tax the amount is on,
|
|
70
|
+
* and must equal the store's own (`pricesIncludeTax`): the Admin API stores
|
|
71
|
+
* one amount in the store's basis and derives the other, so a net amount
|
|
72
|
+
* written into a gross store would silently lose a whole VAT rate. A mismatch
|
|
73
|
+
* is refused (`PRICE_BASIS_MISMATCH`) — the SDK never converts, because the
|
|
74
|
+
* rate that would convert it depends on the zone of each order.
|
|
75
|
+
*/
|
|
76
|
+
export type PriceBasis = 'net' | 'gross';
|
|
77
|
+
/** Omit a key to leave it; unknown keys are not accepted by the Admin API. */
|
|
78
|
+
export interface TranslationInput {
|
|
79
|
+
languageCode: LanguageCode;
|
|
80
|
+
/** Present on update to edit that translation row rather than add one. */
|
|
81
|
+
id?: string;
|
|
82
|
+
}
|
|
83
|
+
/** Vendure's `ConfigurableOperationInput`: a collection filter, a promotion action. */
|
|
84
|
+
export interface ConfigurableOperationInput {
|
|
85
|
+
code: string;
|
|
86
|
+
/** Every argument is a STRING on the wire — lists and booleans JSON-encoded. */
|
|
87
|
+
arguments: Array<{
|
|
88
|
+
name: string;
|
|
89
|
+
value: string;
|
|
90
|
+
}>;
|
|
91
|
+
}
|
|
92
|
+
/** Vendure's `ConfigurableOperation`, as read back. */
|
|
93
|
+
export interface ConfigurableOperation {
|
|
94
|
+
code: string;
|
|
95
|
+
args: Array<{
|
|
96
|
+
name: string;
|
|
97
|
+
value: string;
|
|
98
|
+
}>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Whose catalogue a row belongs to, as the ACTIVE channel sees it (multi-region spec §5.4):
|
|
102
|
+
* - `LOCAL` — the store's own row, or a row its organization keeps but has not shared yet.
|
|
103
|
+
* - `SHARED` — kept by the organization and shared: in a member store, a row of its
|
|
104
|
+
* organization's workspace; in the workspace, a row at least one member store holds.
|
|
105
|
+
*
|
|
106
|
+
* A string on the wire: a newer engine may answer a state this SDK does not name yet.
|
|
107
|
+
*/
|
|
108
|
+
export type CatalogueOwnershipState = 'LOCAL' | 'SHARED';
|
|
109
|
+
export interface CatalogueOwnership {
|
|
110
|
+
state: CatalogueOwnershipState | (string & {});
|
|
111
|
+
/** The organization that keeps the row while it is `SHARED`; null while `LOCAL`. */
|
|
112
|
+
organizationName: string | null;
|
|
113
|
+
/**
|
|
114
|
+
* Whether the caller may change the row from the active channel: it holds the update permission
|
|
115
|
+
* here and on every other store holding the row, and, in a member store, a `SHARED` row is
|
|
116
|
+
* changed only in its organization's workspace, by everyone (a write from the store is refused
|
|
117
|
+
* `MANAGED_BY_ORGANIZATION`). A store's own values on a shared row (its prices, its exclusion)
|
|
118
|
+
* stay the store's to change. Disable an edit form on `false`; the engine refuses it anyway.
|
|
119
|
+
*/
|
|
120
|
+
editableHere: boolean;
|
|
121
|
+
}
|
|
122
|
+
/** `catalogueOwnership` on the top-level row of each catalogue read (never on nested refs). */
|
|
123
|
+
export declare const CATALOGUE_OWNERSHIP_FIELDS = "\n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n";
|
|
124
|
+
export declare const ASSET_REF_FIELDS = "\n id\n name\n preview\n source\n";
|
|
125
|
+
export declare const FACET_VALUE_REF_FIELDS = "\n id\n code\n name\n facet {\n id\n code\n name\n }\n";
|
|
126
|
+
/**
|
|
127
|
+
* Refuse a datetime with no offset, or one that is not a date at all (spec
|
|
128
|
+
* §9.3). Returns the value unchanged — the engine stores the instant, and
|
|
129
|
+
* re-serialising it here would only risk changing its precision.
|
|
130
|
+
*/
|
|
131
|
+
export declare function assertInstant(field: string, value: string | null | undefined): void;
|
|
132
|
+
/**
|
|
133
|
+
* Split an availability input into the custom fields the Admin API takes. Only
|
|
134
|
+
* PRESENT keys are copied — an omitted field must reach the server as omitted,
|
|
135
|
+
* never as null, or a partial update would clear it.
|
|
136
|
+
*/
|
|
137
|
+
export declare function availabilityCustomFields<State extends string>(input: AvailabilityInput<State>): Record<string, unknown>;
|
|
138
|
+
/** Vendure's `DeletionResponse`. */
|
|
139
|
+
export interface DeletionResponse {
|
|
140
|
+
result: 'DELETED' | 'NOT_DELETED';
|
|
141
|
+
message?: string | null;
|
|
142
|
+
}
|
|
143
|
+
export declare const DELETION_FIELDS = "\n result\n message\n";
|
|
144
|
+
/**
|
|
145
|
+
* `NOT_DELETED` arrives at HTTP 200 with no error, so a caller awaiting a void
|
|
146
|
+
* promise would read a refusal as success. It becomes a `ConflictError`
|
|
147
|
+
* carrying the server's own sentence ("The FacetValue … is assigned to 3
|
|
148
|
+
* Products").
|
|
149
|
+
*/
|
|
150
|
+
export declare function assertDeleted(code: string, responses: DeletionResponse[]): void;
|
|
151
|
+
/** Throw a Vendure ErrorResult (`MimeTypeError`, `ProductOptionInUseError`) as itself. */
|
|
152
|
+
export declare function unwrapResult<T>(value: T | {
|
|
153
|
+
errorCode: string;
|
|
154
|
+
message: string;
|
|
155
|
+
}): T;
|
|
156
|
+
export declare const DEFAULT_PAGE_SIZE = 25;
|
|
157
|
+
/** Vendure's `adminListQueryLimit` default; a larger `take` is refused by the engine. */
|
|
158
|
+
export declare const MAX_PAGE_SIZE = 1000;
|
|
159
|
+
/**
|
|
160
|
+
* Wrap one of Vendure's `skip/take` lists in a `Page<T>`. The offset hides
|
|
161
|
+
* inside the cursor (spec §9.3), and every following page re-sends the same
|
|
162
|
+
* filter, sort and per-call options — a page that forgot its tenant would walk
|
|
163
|
+
* another store's catalogue.
|
|
164
|
+
*/
|
|
165
|
+
export declare function vendureListPage<W, T = W>(transport: Transport, document: string, field: string, variables: (skip: number, take: number) => Record<string, unknown>, options: ListOptions | undefined, map?: (wire: W) => T): Promise<Page<T>>;
|
|
166
|
+
/**
|
|
167
|
+
* Run one Admin API document and answer its single root field — the shape of
|
|
168
|
+
* almost every catalog call. The field is read by NAME from the response, so a
|
|
169
|
+
* document and its field name must be kept in step: an ABSENT field is refused
|
|
170
|
+
* rather than answered as `undefined` (a null one is a real answer), and
|
|
171
|
+
* `catalog-call-sites.spec.ts` drives every call site with a responder keyed
|
|
172
|
+
* on the document's own root field.
|
|
173
|
+
*/
|
|
174
|
+
export declare function fieldOf<T>(transport: Transport, document: string, field: string, variables: Record<string, unknown>, options: Call | undefined): Promise<T>;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { ConflictError, errorFromErrorResult, isErrorResult, pageFromVendureList, readOffsetCursor, UpstreamError, ValidationError, } from '@sixtyninecommerce/core';
|
|
2
|
+
/** `catalogueOwnership` on the top-level row of each catalogue read (never on nested refs). */
|
|
3
|
+
export const CATALOGUE_OWNERSHIP_FIELDS = /* GraphQL */ `
|
|
4
|
+
catalogueOwnership {
|
|
5
|
+
state
|
|
6
|
+
organizationName
|
|
7
|
+
editableHere
|
|
8
|
+
}
|
|
9
|
+
`;
|
|
10
|
+
export const ASSET_REF_FIELDS = /* GraphQL */ `
|
|
11
|
+
id
|
|
12
|
+
name
|
|
13
|
+
preview
|
|
14
|
+
source
|
|
15
|
+
`;
|
|
16
|
+
export const FACET_VALUE_REF_FIELDS = /* GraphQL */ `
|
|
17
|
+
id
|
|
18
|
+
code
|
|
19
|
+
name
|
|
20
|
+
facet {
|
|
21
|
+
id
|
|
22
|
+
code
|
|
23
|
+
name
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
const INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
27
|
+
/**
|
|
28
|
+
* Refuse a datetime with no offset, or one that is not a date at all (spec
|
|
29
|
+
* §9.3). Returns the value unchanged — the engine stores the instant, and
|
|
30
|
+
* re-serialising it here would only risk changing its precision.
|
|
31
|
+
*/
|
|
32
|
+
export function assertInstant(field, value) {
|
|
33
|
+
if (value === null || value === undefined)
|
|
34
|
+
return;
|
|
35
|
+
if (typeof value === 'string' && INSTANT.test(value) && !Number.isNaN(Date.parse(value)))
|
|
36
|
+
return;
|
|
37
|
+
throw new ValidationError({
|
|
38
|
+
code: 'INVALID_DATETIME',
|
|
39
|
+
message: `${field} must be an ISO-8601 instant with an explicit offset, such as "2026-10-01T09:00:00+02:00" or "2026-10-01T07:00:00Z"; got ${JSON.stringify(value)}.`,
|
|
40
|
+
status: 400,
|
|
41
|
+
service: 'vendure',
|
|
42
|
+
details: [{ field, code: 'INVALID_DATETIME', message: 'An offset (Z or ±HH:mm) is required.' }],
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Split an availability input into the custom fields the Admin API takes. Only
|
|
47
|
+
* PRESENT keys are copied — an omitted field must reach the server as omitted,
|
|
48
|
+
* never as null, or a partial update would clear it.
|
|
49
|
+
*/
|
|
50
|
+
export function availabilityCustomFields(input) {
|
|
51
|
+
assertInstant('availableFrom', input.availableFrom);
|
|
52
|
+
const fields = {};
|
|
53
|
+
if (input.availabilityState !== undefined)
|
|
54
|
+
fields.availabilityState = input.availabilityState;
|
|
55
|
+
if (input.availableFrom !== undefined)
|
|
56
|
+
fields.availableFrom = input.availableFrom;
|
|
57
|
+
if (input.preorderLimit !== undefined)
|
|
58
|
+
fields.preorderLimit = input.preorderLimit;
|
|
59
|
+
return fields;
|
|
60
|
+
}
|
|
61
|
+
export const DELETION_FIELDS = /* GraphQL */ `
|
|
62
|
+
result
|
|
63
|
+
message
|
|
64
|
+
`;
|
|
65
|
+
/**
|
|
66
|
+
* `NOT_DELETED` arrives at HTTP 200 with no error, so a caller awaiting a void
|
|
67
|
+
* promise would read a refusal as success. It becomes a `ConflictError`
|
|
68
|
+
* carrying the server's own sentence ("The FacetValue … is assigned to 3
|
|
69
|
+
* Products").
|
|
70
|
+
*/
|
|
71
|
+
export function assertDeleted(code, responses) {
|
|
72
|
+
const refused = responses.filter((response) => response.result !== 'DELETED');
|
|
73
|
+
if (refused.length === 0)
|
|
74
|
+
return;
|
|
75
|
+
throw new ConflictError({
|
|
76
|
+
code,
|
|
77
|
+
message: refused.map((response) => response.message ?? 'The server gave no reason.').join('; '),
|
|
78
|
+
status: 409,
|
|
79
|
+
service: 'vendure',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/** Throw a Vendure ErrorResult (`MimeTypeError`, `ProductOptionInUseError`) as itself. */
|
|
83
|
+
export function unwrapResult(value) {
|
|
84
|
+
if (isErrorResult(value))
|
|
85
|
+
throw errorFromErrorResult(value);
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
export const DEFAULT_PAGE_SIZE = 25;
|
|
89
|
+
/** Vendure's `adminListQueryLimit` default; a larger `take` is refused by the engine. */
|
|
90
|
+
export const MAX_PAGE_SIZE = 1000;
|
|
91
|
+
/**
|
|
92
|
+
* Wrap one of Vendure's `skip/take` lists in a `Page<T>`. The offset hides
|
|
93
|
+
* inside the cursor (spec §9.3), and every following page re-sends the same
|
|
94
|
+
* filter, sort and per-call options — a page that forgot its tenant would walk
|
|
95
|
+
* another store's catalogue.
|
|
96
|
+
*/
|
|
97
|
+
export async function vendureListPage(transport, document, field, variables, options, map = (wire) => wire) {
|
|
98
|
+
const take = options?.limit ?? DEFAULT_PAGE_SIZE;
|
|
99
|
+
if (!Number.isInteger(take) || take < 1 || take > MAX_PAGE_SIZE) {
|
|
100
|
+
throw new ValidationError({
|
|
101
|
+
code: 'INVALID_PAGE_SIZE',
|
|
102
|
+
message: `limit must be a whole number from 1 to ${String(MAX_PAGE_SIZE)}; got ${String(take)}.`,
|
|
103
|
+
status: 400,
|
|
104
|
+
service: 'vendure',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const fetchPage = async (skip) => {
|
|
108
|
+
const data = await transport.graphql({ api: 'admin', query: document, variables: variables(skip, take) }, options);
|
|
109
|
+
const list = data[field];
|
|
110
|
+
if (!list) {
|
|
111
|
+
throw new UpstreamError({
|
|
112
|
+
code: 'UNEXPECTED_RESPONSE',
|
|
113
|
+
message: `The engine answered without "${field}".`,
|
|
114
|
+
status: 502,
|
|
115
|
+
service: 'vendure',
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return pageFromVendureList({ items: list.items.map(map), totalItems: list.totalItems }, skip, take, (cursor) => fetchPage(readOffsetCursor(cursor)));
|
|
119
|
+
};
|
|
120
|
+
return fetchPage(options?.after === undefined ? 0 : readOffsetCursor(options.after));
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Run one Admin API document and answer its single root field — the shape of
|
|
124
|
+
* almost every catalog call. The field is read by NAME from the response, so a
|
|
125
|
+
* document and its field name must be kept in step: an ABSENT field is refused
|
|
126
|
+
* rather than answered as `undefined` (a null one is a real answer), and
|
|
127
|
+
* `catalog-call-sites.spec.ts` drives every call site with a responder keyed
|
|
128
|
+
* on the document's own root field.
|
|
129
|
+
*/
|
|
130
|
+
export async function fieldOf(transport, document, field, variables, options) {
|
|
131
|
+
const data = await transport.graphql({ api: 'admin', query: document, variables }, options);
|
|
132
|
+
if (data === null || typeof data !== 'object' || !Object.hasOwn(data, field)) {
|
|
133
|
+
throw new UpstreamError({
|
|
134
|
+
code: 'UNEXPECTED_RESPONSE',
|
|
135
|
+
message: `The engine answered without "${field}".`,
|
|
136
|
+
status: 502,
|
|
137
|
+
service: 'vendure',
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return data[field];
|
|
141
|
+
}
|