@sixtyninecommerce/admin 0.8.0 → 0.10.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 +2739 -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 +650 -0
- package/dist/catalog/products.js +458 -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 +324 -0
- package/dist/catalog/variants.js +288 -0
- package/dist/catalog/visibility.d.ts +57 -0
- package/dist/catalog/visibility.js +59 -0
- package/dist/client.d.ts +192 -3
- package/dist/client.js +87 -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 +437 -0
- package/dist/fulfillments/index.js +534 -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 +95 -9
- package/dist/index.js +21 -1
- package/dist/integrations/index.d.ts +14 -0
- package/dist/integrations/index.js +9 -0
- package/dist/integrations/pipelines.d.ts +113 -0
- package/dist/integrations/pipelines.js +62 -0
- package/dist/integrations/types.d.ts +176 -0
- package/dist/integrations/types.js +8 -0
- package/dist/jobs/bulk-action-run.d.ts +74 -0
- package/dist/jobs/bulk-action-run.js +69 -0
- package/dist/locations/index.d.ts +6 -2
- package/dist/meta/index.d.ts +32 -0
- package/dist/orders/bulk.d.ts +75 -0
- package/dist/orders/bulk.js +150 -0
- package/dist/orders/commit-edit.d.ts +123 -0
- package/dist/orders/commit-edit.js +142 -0
- package/dist/orders/deposit-policy.d.ts +103 -0
- package/dist/orders/deposit-policy.js +202 -0
- package/dist/orders/get.d.ts +722 -0
- package/dist/orders/get.js +530 -0
- package/dist/orders/index.d.ts +186 -21
- package/dist/orders/index.js +57 -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 +141 -0
- package/dist/orders/manual-discounts.js +97 -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 +241 -9
- package/dist/payments/index.js +92 -0
- package/dist/payments/methods.d.ts +37 -0
- package/dist/payments/methods.js +33 -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 +408 -0
- package/dist/pricing/index.js +353 -0
- package/dist/pricing/vouchers.d.ts +103 -0
- package/dist/pricing/vouchers.js +69 -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/returns/index.d.ts +225 -0
- package/dist/returns/index.js +160 -0
- package/dist/search/index.d.ts +99 -0
- package/dist/search/index.js +62 -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,323 @@
|
|
|
1
|
+
import { type Page, type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Job, JobHandle, JobsModule } from '../jobs/index.js';
|
|
3
|
+
import type { Call, ListOptions } from '../types.js';
|
|
4
|
+
import type { UploadsModule } from '../uploads/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* What each line of a bulk file is.
|
|
7
|
+
*
|
|
8
|
+
* `order` carries external order entry's semantics (spec §8.1): see
|
|
9
|
+
* {@link BulkRow} for its row, and {@link BulkModule.export} for what an
|
|
10
|
+
* export of it holds. Content items are absent — they live in the CMS, which
|
|
11
|
+
* has no bulk writer yet.
|
|
12
|
+
*/
|
|
13
|
+
export type BulkEntity = 'product' | 'variant' | 'price' | 'stock_level' | 'customer' | 'metafield' | 'order';
|
|
14
|
+
/**
|
|
15
|
+
* How an import applies each row.
|
|
16
|
+
*
|
|
17
|
+
* - `upsert` (the default) creates what is missing and updates what is there,
|
|
18
|
+
* so re-sending a file that was half applied CONVERGES. It is the only mode
|
|
19
|
+
* that is safe to repeat, which is why it is the default.
|
|
20
|
+
* - `create` skips a key that already exists rather than failing it.
|
|
21
|
+
* - `update` fails a row whose key does not exist.
|
|
22
|
+
*
|
|
23
|
+
* `price` and `stock_level` take no `create`: both belong to a variant that
|
|
24
|
+
* already exists, so there is nothing to create. `metafield` takes only
|
|
25
|
+
* `upsert`, because `setMetafield` is one by construction. `order` takes only
|
|
26
|
+
* `create`: an order is composed once and then moved by its own lifecycle
|
|
27
|
+
* (payments, park, settle), and is never RESTATED through bulk — so pass
|
|
28
|
+
* `mode: 'create'` explicitly, since the default is `upsert`. A mode an entity
|
|
29
|
+
* cannot apply is refused when you submit, not once per row.
|
|
30
|
+
*/
|
|
31
|
+
export type BulkMode = 'create' | 'upsert' | 'update';
|
|
32
|
+
/**
|
|
33
|
+
* A row of a bulk file: one entity, as a JSON object, on one line.
|
|
34
|
+
*
|
|
35
|
+
* **The shapes are the SDK's own write inputs.** A `customer` row is what
|
|
36
|
+
* `admin.customers.create()` takes; a `metafield` row is what
|
|
37
|
+
* `admin.metafields.set()` takes. That is the contract of the resource, and it
|
|
38
|
+
* is what lets you test one row interactively and then send a million identical
|
|
39
|
+
* ones.
|
|
40
|
+
*
|
|
41
|
+
* The accepted fields per entity, with their keys (what a row is matched on):
|
|
42
|
+
*
|
|
43
|
+
* | entity | key | fields |
|
|
44
|
+
* | --- | --- | --- |
|
|
45
|
+
* | `product` | `slug` | `slug`, `name`, `description`, `enabled`, `facetValueIds`, `languageCode`, `customFields` |
|
|
46
|
+
* | `variant` | `sku` | `sku`, `productSlug` (to create), `name`, `price`, `prices`, `enabled`, `optionIds`, `facetValueIds`, `taxCategoryId`, `trackInventory`, `outOfStockThreshold`, `useGlobalOutOfStockThreshold`, `languageCode`, `customFields` |
|
|
47
|
+
* | `price` | `sku` | `sku`, `price`, `prices` |
|
|
48
|
+
* | `stock_level` | `sku` (+ location) | `sku`, `stockOnHand`, `stockLocationId` |
|
|
49
|
+
* | `customer` | `emailAddress` | `emailAddress`, `firstName`, `lastName`, `title`, `phoneNumber`, `customFields` |
|
|
50
|
+
* | `metafield` | the four together | `ownerType`, `ownerId`, `namespace`, `key`, `value` |
|
|
51
|
+
* | `order` | `idempotency_key` (+ `externalRef`) | `idempotency_key`, then every field of `admin.orders.createOrRecover()`'s input: `externalRef`, `customerId`, `location`, `billingAddress`, `lines` (with `kind: 'catalog' \| 'external'`), `surcharges`, `fulfilment`, `transitionTo`, `attachments` |
|
|
52
|
+
*
|
|
53
|
+
* **A `stock_level` row** writes only a location of this store: another
|
|
54
|
+
* store's location (or an id that does not exist) fails the row with
|
|
55
|
+
* `LOCATION_NOT_IN_CHANNEL`. A token or app restricted with `locationIds`
|
|
56
|
+
* writes only its own locations (`LOCATION_NOT_ALLOWED` for any other, dry run
|
|
57
|
+
* included), and its `stock_level` export holds only rows at those locations.
|
|
58
|
+
* The restriction is the one the credential had when the operation was
|
|
59
|
+
* submitted. Such a credential can read (`get`, `results`) only the
|
|
60
|
+
* `stock_level` operations it submitted itself.
|
|
61
|
+
*
|
|
62
|
+
* **An `order` row** is `admin.orders.createOrRecover(input, { idempotencyKey })`
|
|
63
|
+
* written as one object: the input's fields under their SDK names, and the key
|
|
64
|
+
* as `idempotency_key` (snake_case, like the rest of the bulk envelope, because
|
|
65
|
+
* it is the call's option rather than a field of the input). The key is
|
|
66
|
+
* REQUIRED and bulk never makes one up — a row without it fails. Re-sending a
|
|
67
|
+
* row is the entry call's own recovery: the same key and body answer `ok` with
|
|
68
|
+
* the id of the order the first send created (never a second order), a changed
|
|
69
|
+
* body under the key is `IDEMPOTENCY_CONFLICT`, and the same `externalRef` with
|
|
70
|
+
* a different basket is `EXTERNAL_REF_CONFLICT`. Every refusal the interactive
|
|
71
|
+
* call documents (`LINE_MISPRICED`, `TAX_CLASS_UNMAPPED`, …) is that row's
|
|
72
|
+
* `problem`, with the line's position as `details[].field` (`lines[1]`), and the
|
|
73
|
+
* rest of the file carries on. A row that prices a line or a surcharge itself
|
|
74
|
+
* needs `ImportExternalLines`, exactly as the interactive call does. A dry run
|
|
75
|
+
* checks the row's shape and that every variant, the `location` and the
|
|
76
|
+
* `customerId` exist in this store — and never calls order entry, so pricing
|
|
77
|
+
* and tax-class refusals only a real run can report.
|
|
78
|
+
*
|
|
79
|
+
* Two things worth knowing before you build a file:
|
|
80
|
+
*
|
|
81
|
+
* - **An unknown field is REFUSED, not ignored.** A misspelled `stockOnhand` in
|
|
82
|
+
* a ten-thousand-row feed fails those rows with a message naming the field,
|
|
83
|
+
* rather than completing green having changed nothing.
|
|
84
|
+
* - **Money is integer minor units**, like everywhere else on this platform:
|
|
85
|
+
* `1999`, never `19.99`. A fractional value is refused with that sentence.
|
|
86
|
+
*/
|
|
87
|
+
export type BulkRow = Record<string, unknown>;
|
|
88
|
+
export type BulkRowStatus = 'ok' | 'skipped' | 'failed';
|
|
89
|
+
/** What happened to one row. */
|
|
90
|
+
export interface BulkRowResult {
|
|
91
|
+
/** 1-based, counting the file's NON-BLANK lines. */
|
|
92
|
+
row: number;
|
|
93
|
+
/**
|
|
94
|
+
* `ok` — applied (or, in a dry run, would have been). `skipped` — understood
|
|
95
|
+
* and deliberately not applied, which today means `create` mode meeting a key
|
|
96
|
+
* that already exists. `failed` — refused; `problem` says why.
|
|
97
|
+
*/
|
|
98
|
+
status: BulkRowStatus;
|
|
99
|
+
/** The id of the entity written, when one was. */
|
|
100
|
+
id?: string;
|
|
101
|
+
/**
|
|
102
|
+
* RFC 9457, and the SAME document the interactive call would have answered
|
|
103
|
+
* with for the same input — same `code`, same `detail`. A client that already
|
|
104
|
+
* handles `admin.customers.create()` being refused handles this.
|
|
105
|
+
*/
|
|
106
|
+
problem?: {
|
|
107
|
+
type: string;
|
|
108
|
+
title: string;
|
|
109
|
+
status: number;
|
|
110
|
+
code: string;
|
|
111
|
+
detail?: string;
|
|
112
|
+
};
|
|
113
|
+
[extra: string]: unknown;
|
|
114
|
+
}
|
|
115
|
+
export type BulkOperationStatus = 'queued' | 'running' | 'succeeded' | 'failed' | 'cancelled';
|
|
116
|
+
/** One bulk operation, and where its output is. */
|
|
117
|
+
export interface BulkOperation {
|
|
118
|
+
id: string;
|
|
119
|
+
operation: 'import' | 'export';
|
|
120
|
+
entity: BulkEntity;
|
|
121
|
+
mode: BulkMode | null;
|
|
122
|
+
dryRun: boolean;
|
|
123
|
+
containerId: string | null;
|
|
124
|
+
status: BulkOperationStatus;
|
|
125
|
+
/** Rows SEEN so far; the total once the operation is terminal. */
|
|
126
|
+
totalRows: number;
|
|
127
|
+
okRows: number;
|
|
128
|
+
skippedRows: number;
|
|
129
|
+
failedRows: number;
|
|
130
|
+
/**
|
|
131
|
+
* A signed link to the JSONL output — an export's rows, or an import's per-row
|
|
132
|
+
* results.
|
|
133
|
+
*
|
|
134
|
+
* **Minted per read and good for about fifteen minutes.** It is not stored, so
|
|
135
|
+
* do not persist it: read the operation again when you need a fresh one. The
|
|
136
|
+
* object itself lives in private storage and is not reachable any other way.
|
|
137
|
+
*
|
|
138
|
+
* For an IMPORT, check {@link resultTruncated} before treating this file as
|
|
139
|
+
* complete — `results(id)` is the authoritative set either way.
|
|
140
|
+
*/
|
|
141
|
+
resultUrl: string | null;
|
|
142
|
+
/**
|
|
143
|
+
* The file behind {@link resultUrl} stopped SHORT of the run.
|
|
144
|
+
*
|
|
145
|
+
* The operation still succeeded and every row is still there — but in the
|
|
146
|
+
* TABLE, not in the file: `admin.bulk.results(id)` pages the complete set.
|
|
147
|
+
* It happens when the outcomes exceed the size one object may hold, which a
|
|
148
|
+
* file with tens of thousands of REFUSED rows reaches long before the row
|
|
149
|
+
* limit, because each refusal carries a problem document.
|
|
150
|
+
*
|
|
151
|
+
* Check it before you treat the downloaded file as the whole story.
|
|
152
|
+
*/
|
|
153
|
+
resultTruncated: boolean;
|
|
154
|
+
error: {
|
|
155
|
+
code: string;
|
|
156
|
+
message: string;
|
|
157
|
+
} | null;
|
|
158
|
+
createdAt: string | null;
|
|
159
|
+
startedAt: string | null;
|
|
160
|
+
finishedAt: string | null;
|
|
161
|
+
[extra: string]: unknown;
|
|
162
|
+
}
|
|
163
|
+
export interface BulkImportOptions extends Call {
|
|
164
|
+
/** Default `upsert`. */
|
|
165
|
+
mode?: BulkMode;
|
|
166
|
+
/**
|
|
167
|
+
* Validate and look every row up, write NOTHING.
|
|
168
|
+
*
|
|
169
|
+
* The results say what each row WOULD have done, including "row 412's sku
|
|
170
|
+
* does not exist on this store" — a dry run makes the same lookups a real run
|
|
171
|
+
* makes. The staged file is still consumed, so a rehearsal and the real run
|
|
172
|
+
* mean staging the bytes twice.
|
|
173
|
+
*/
|
|
174
|
+
dryRun?: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Your own handle for "these files are one logical import".
|
|
177
|
+
*
|
|
178
|
+
* It GROUPS; it does not coordinate. The operations sharing one still succeed
|
|
179
|
+
* and fail independently, because a multi-file import whose parts had to agree
|
|
180
|
+
* would need a transaction across a million rows.
|
|
181
|
+
*/
|
|
182
|
+
containerId?: string;
|
|
183
|
+
/** Makes a retried submit return the SAME operation instead of a second one. */
|
|
184
|
+
idempotencyKey?: string;
|
|
185
|
+
/**
|
|
186
|
+
* Your own handle for the STAGING call, when this SDK has to stage the bytes.
|
|
187
|
+
*
|
|
188
|
+
* Staging is the call that hands out a signed URL, and a dropped response on
|
|
189
|
+
* it is the ordinary failure: without a token every retry would reserve
|
|
190
|
+
* another place and leave an object nobody ever claims. One is generated when
|
|
191
|
+
* you do not give one, which is right for a single attempt and wrong for a
|
|
192
|
+
* retry you drive yourself.
|
|
193
|
+
*/
|
|
194
|
+
clientToken?: string;
|
|
195
|
+
/** A label for a human reading the upload list. Default `bulk.jsonl`. */
|
|
196
|
+
filename?: string;
|
|
197
|
+
}
|
|
198
|
+
export interface BulkExportOptions extends Call {
|
|
199
|
+
containerId?: string;
|
|
200
|
+
idempotencyKey?: string;
|
|
201
|
+
}
|
|
202
|
+
export interface BulkResultsFilter extends ListOptions {
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* What you can hand `admin.bulk.import` as the file.
|
|
206
|
+
*
|
|
207
|
+
* - **bytes** (`Uint8Array`, `ArrayBuffer`, `Blob`) — staged and PUT for you;
|
|
208
|
+
* - a **`ReadableStream`** — collected, then staged. A presigned PUT signs one
|
|
209
|
+
* exact length, so the bytes have to be counted before they are sent; there
|
|
210
|
+
* is no way to stage a stream of unknown size;
|
|
211
|
+
* - a **staged upload id** you staged yourself with
|
|
212
|
+
* `admin.uploads.stage({ purpose: 'bulk', … })`, which is how to send a file
|
|
213
|
+
* this process never holds whole.
|
|
214
|
+
*
|
|
215
|
+
* **A filesystem PATH is deliberately not one of them.** This package is
|
|
216
|
+
* isomorphic and depends on `@sixtyninecommerce/core` and nothing else, so it
|
|
217
|
+
* cannot reach `node:fs` — a dynamic import of it would break every browser
|
|
218
|
+
* bundle and every external install. In Node it is one line at the call site,
|
|
219
|
+
* and it is YOUR `readFile`, not a hidden one:
|
|
220
|
+
*
|
|
221
|
+
* ```ts
|
|
222
|
+
* const bytes = await readFile('./prices.jsonl');
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
export type BulkFile = {
|
|
226
|
+
stagedUploadId: string;
|
|
227
|
+
} | Uint8Array | ArrayBuffer | Blob | ReadableStream<Uint8Array>;
|
|
228
|
+
/**
|
|
229
|
+
* JSONL bulk import and export (spec §6.11, §15.22).
|
|
230
|
+
*
|
|
231
|
+
* **The shape of it.** One line per entity, of the same shapes the SDK's own
|
|
232
|
+
* writes take. One operation becomes one job; a malformed row fails THAT row
|
|
233
|
+
* and never the job; the per-row outcomes are a page you can walk, and the
|
|
234
|
+
* whole thing is also a JSONL file behind a signed link.
|
|
235
|
+
*
|
|
236
|
+
* ```ts
|
|
237
|
+
* const entity = 'price' as const;
|
|
238
|
+
* const bytes = await readFile('./prices.jsonl');
|
|
239
|
+
* const handle = await admin.bulk.import(entity, bytes, {
|
|
240
|
+
* mode: 'update',
|
|
241
|
+
* idempotencyKey: crypto.randomUUID(),
|
|
242
|
+
* });
|
|
243
|
+
* const result = await handle.wait();
|
|
244
|
+
* if (result.failedRows > 0) {
|
|
245
|
+
* for await (const row of await admin.bulk.results(result.id)) {
|
|
246
|
+
* if (row.status === 'failed') console.error(row.row, row.problem?.detail);
|
|
247
|
+
* }
|
|
248
|
+
* }
|
|
249
|
+
* ```
|
|
250
|
+
*
|
|
251
|
+
* **Field groups.** While an app or API token owns a field group on the store, a row that would
|
|
252
|
+
* change that group's data fails with `problem.code` `FIELD_GROUP_LOCKED` (the detail names the
|
|
253
|
+
* group and its owner), on every entity, unless the owner itself submitted the import. An
|
|
254
|
+
* unchanged value passes. A row that creates a record is never refused for it.
|
|
255
|
+
*
|
|
256
|
+
* **Feed identifiers.** A `product` row whose `customFields.brand`, or a `variant` row whose
|
|
257
|
+
* `customFields.gtin`, is NEW or CHANGED and breaks the feed rule (a brand over 70 characters, a
|
|
258
|
+
* GTIN that is not 8, 12, 13 or 14 digits, both after trimming) fails with `problem.code`
|
|
259
|
+
* `FEED_IDENTIFIER_INVALID` (status 400), creates included; the other rows carry on. A value the
|
|
260
|
+
* record already holds passes, so an edited export sent back is never refused for a value it did
|
|
261
|
+
* not change. A `dryRun` does not reach this rule: it stops before the write.
|
|
262
|
+
*
|
|
263
|
+
* **It does not spend your rate limit.** Submitting costs one request like any
|
|
264
|
+
* other write; the rows themselves are applied by the platform's own worker, so
|
|
265
|
+
* a million of them spend nothing of your budget (§15.22). Nothing is bypassed
|
|
266
|
+
* either — the same hooks, provenance and validation run as for an interactive
|
|
267
|
+
* write.
|
|
268
|
+
*
|
|
269
|
+
* **Rehearse first.** `dryRun` runs every check and every lookup and writes
|
|
270
|
+
* nothing. It is the cheapest way to find out that a column in a supplier's
|
|
271
|
+
* spreadsheet is in the wrong units.
|
|
272
|
+
*
|
|
273
|
+
* **An app installation's `customerData` level applies.** An export an app
|
|
274
|
+
* submits comes back as that app reads the Admin API: at `none` a customer
|
|
275
|
+
* row's `emailAddress`, `firstName` and `lastName` are `""`, and any field its
|
|
276
|
+
* level withholds is blank. A `customer` import, and a `customer` export
|
|
277
|
+
* filtered by `emails`, need `identity` (each row is matched by its email, so
|
|
278
|
+
* the outcome says whether an address is a customer); below it they are
|
|
279
|
+
* refused with `PermissionDeniedError` code `CUSTOMER_DATA_NOT_GRANTED`. An
|
|
280
|
+
* operation is readable (`get`, `results`) only at or above the level it was
|
|
281
|
+
* submitted at. A human's and a personal token's operations are unaffected.
|
|
282
|
+
*/
|
|
283
|
+
export interface BulkModule {
|
|
284
|
+
/**
|
|
285
|
+
* Import a file of rows. Answers a handle whose `wait()` resolves with the
|
|
286
|
+
* finished operation, whatever the ending was.
|
|
287
|
+
*/
|
|
288
|
+
import(entity: BulkEntity, file: BulkFile, options?: BulkImportOptions): Promise<JobHandle<BulkOperation>>;
|
|
289
|
+
/**
|
|
290
|
+
* Export rows to JSONL. The output is exactly what `import` accepts, so an
|
|
291
|
+
* export can be edited and sent back — except for `order`, below.
|
|
292
|
+
*
|
|
293
|
+
* `filter` narrows it, and an UNRECOGNISED key is refused rather than ignored
|
|
294
|
+
* — a filter nothing honours would turn an intended narrowing into a
|
|
295
|
+
* whole-store export that completes green. Common keys: `updated_after` (an
|
|
296
|
+
* ISO-8601 instant WITH an offset), and a key list per entity (`slugs`,
|
|
297
|
+
* `skus`, `emails`, and `ids` for `order`). `metafield` requires `owner_type`
|
|
298
|
+
* and `owner_ids`.
|
|
299
|
+
*
|
|
300
|
+
* **An `order` export is a record of the entry, not an input to re-import**
|
|
301
|
+
* (orders are not restated). One row per order — a shopper's open cart is not
|
|
302
|
+
* an order and is left out — with `id`, `code`, `externalRef`, `state`,
|
|
303
|
+
* `placedAt`, `customerId` and `currencyCode`; `lines` in the order the entry
|
|
304
|
+
* request sent them, each with its `id` and `position`: an externally priced
|
|
305
|
+
* line as `kind: 'external'` with its `label`, `taxClass`, and the `unitPrice`
|
|
306
|
+
* and `priceBasis` it was STATED in (the pair the platform holds fixed), a
|
|
307
|
+
* catalog line as `kind: 'catalog'` with its `productVariantId` and `sku`, and
|
|
308
|
+
* on every line `charged` — what the order computed, in both bases: `unitPrice`/`linePrice` before discounts, `proratedLinePrice(WithTax)` after line and order-level promotions (the figure the lines' sum to `subTotal` on). Then the
|
|
309
|
+
* `surcharges`, the order's totals, `billableTotalWithTax` (what the invoice
|
|
310
|
+
* charges, goodwill rounding folded in) beside the raw `totalWithTax`, and
|
|
311
|
+
* `payment` — `covered`, `settled`, `authorized`, `refunded`, `outstanding` at
|
|
312
|
+
* the moment of export. Money is integer minor units of `currencyCode`.
|
|
313
|
+
* Customer identity is the id only: no name, email or address leaves through
|
|
314
|
+
* an export, the same rule the `order.*` events keep.
|
|
315
|
+
*/
|
|
316
|
+
export(entity: BulkEntity, filter?: Record<string, unknown>, options?: BulkExportOptions): Promise<JobHandle<BulkOperation>>;
|
|
317
|
+
/** One operation, with a freshly signed `resultUrl`. */
|
|
318
|
+
get(id: string, options?: Call): Promise<BulkOperation>;
|
|
319
|
+
/** The per-row outcomes, in ROW order. Iterate the page to walk them all. */
|
|
320
|
+
results(id: string, filter?: BulkResultsFilter): Promise<Page<BulkRowResult>>;
|
|
321
|
+
}
|
|
322
|
+
export declare function createBulkModule(transport: Transport, uploads: UploadsModule, jobs: JobsModule): BulkModule;
|
|
323
|
+
export type { Job, JobHandle };
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { createPage, readRestPage } from '@sixtyninecommerce/core';
|
|
2
|
+
/** The type a bulk file is staged as. */
|
|
3
|
+
const JSONL_CONTENT_TYPE = 'application/x-ndjson';
|
|
4
|
+
export function createBulkModule(transport, uploads, jobs) {
|
|
5
|
+
async function get(id, options) {
|
|
6
|
+
return transport.rest('plugins', { method: 'GET', path: `/bulk/${encodeURIComponent(id)}` }, options);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Wait for the JOB, then read the OPERATION.
|
|
10
|
+
*
|
|
11
|
+
* Two reads rather than one, because they answer different questions and the
|
|
12
|
+
* job resource is the one that knows when to stop polling. The operation is
|
|
13
|
+
* then read once, at the end, which is also when its `resultUrl` is worth
|
|
14
|
+
* having — a link minted while the run was going would have expired by the
|
|
15
|
+
* time the file existed.
|
|
16
|
+
*/
|
|
17
|
+
function handleFor(jobId, options) {
|
|
18
|
+
return {
|
|
19
|
+
runId: jobId,
|
|
20
|
+
async wait(waitOptions) {
|
|
21
|
+
await jobs.wait(jobId, { ...options, ...waitOptions });
|
|
22
|
+
return get(jobId, options);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
async function resultsPage(id, filter) {
|
|
27
|
+
const body = await transport.rest('plugins', {
|
|
28
|
+
method: 'GET',
|
|
29
|
+
path: `/bulk/${encodeURIComponent(id)}/results`,
|
|
30
|
+
query: { after: filter?.after, limit: filter?.limit },
|
|
31
|
+
}, filter);
|
|
32
|
+
const { items, meta } = readRestPage(body);
|
|
33
|
+
return createPage(items, meta, (cursor) => resultsPage(id, { ...filter, after: cursor }));
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
async import(entity, file, options) {
|
|
37
|
+
const stagedUploadId = await resolveStagedUpload(uploads, file, options);
|
|
38
|
+
// `jobId`, not `job_id`. The transport camelises every response key
|
|
39
|
+
// (`snakeToCamelKeys`, on by default), so the controller's `{ job_id }`
|
|
40
|
+
// arrives as `{ jobId }` — destructuring the wire spelling yields
|
|
41
|
+
// `undefined` and every handle then polls `/jobs/undefined`.
|
|
42
|
+
const { jobId } = await transport.rest('plugins', {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
path: '/bulk/imports',
|
|
45
|
+
body: {
|
|
46
|
+
entity,
|
|
47
|
+
...(options?.mode === undefined ? {} : { mode: options.mode }),
|
|
48
|
+
...(options?.dryRun === undefined ? {} : { dry_run: options.dryRun }),
|
|
49
|
+
staged_upload_id: stagedUploadId,
|
|
50
|
+
...(options?.containerId === undefined ? {} : { container_id: options.containerId }),
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
// `idempotencyKey` rides on the OPTIONS, which is where the transport
|
|
54
|
+
// reads it to compose the `Idempotency-Key` header. Putting it in the
|
|
55
|
+
// call would have been silently ignored — the header would never be
|
|
56
|
+
// sent and a retried submit would start a second operation.
|
|
57
|
+
options);
|
|
58
|
+
return handleFor(jobId, options);
|
|
59
|
+
},
|
|
60
|
+
async export(entity, filter, options) {
|
|
61
|
+
const { jobId } = await transport.rest('plugins', {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
path: '/bulk/exports',
|
|
64
|
+
body: {
|
|
65
|
+
entity,
|
|
66
|
+
...(filter === undefined ? {} : { filter }),
|
|
67
|
+
...(options?.containerId === undefined ? {} : { container_id: options.containerId }),
|
|
68
|
+
},
|
|
69
|
+
}, {
|
|
70
|
+
...options,
|
|
71
|
+
// The filter is the CALLER's own vocabulary — `updated_after`,
|
|
72
|
+
// `owner_type` — and the transport camelises every key unless told
|
|
73
|
+
// not to. Without this, `updated_after` would arrive as `updatedAfter`
|
|
74
|
+
// and be refused as an unknown filter key, which is the one mistake
|
|
75
|
+
// that is impossible to debug from the outside.
|
|
76
|
+
preserveKeys: FILTER_PASSTHROUGH,
|
|
77
|
+
});
|
|
78
|
+
return handleFor(jobId, options);
|
|
79
|
+
},
|
|
80
|
+
get,
|
|
81
|
+
results: resultsPage,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* `filter` keys travel EXACTLY as the caller spelled them.
|
|
86
|
+
*
|
|
87
|
+
* The service refuses an unrecognised filter key on purpose, so a transport
|
|
88
|
+
* that camelised `updated_after` into `updatedAfter` would turn every filtered
|
|
89
|
+
* export into a 400 naming a key the caller never typed.
|
|
90
|
+
*/
|
|
91
|
+
const FILTER_PASSTHROUGH = new Set(['filter']);
|
|
92
|
+
/**
|
|
93
|
+
* Turn whatever the caller gave us into a staged upload id.
|
|
94
|
+
*
|
|
95
|
+
* The bytes are COUNTED before they are staged, because a presigned PUT signs
|
|
96
|
+
* one exact `Content-Length` and there is no way to sign an upper bound. That
|
|
97
|
+
* is also why a `ReadableStream` is collected rather than piped: the size has
|
|
98
|
+
* to be known first. A caller whose file is too large to hold should stage it
|
|
99
|
+
* themselves and pass the id.
|
|
100
|
+
*/
|
|
101
|
+
async function resolveStagedUpload(uploads, file, options) {
|
|
102
|
+
if (typeof file === 'object' && file !== null && 'stagedUploadId' in file) {
|
|
103
|
+
return file.stagedUploadId;
|
|
104
|
+
}
|
|
105
|
+
const bytes = await readBytes(file);
|
|
106
|
+
const ticket = await uploads.stage({
|
|
107
|
+
purpose: 'bulk',
|
|
108
|
+
mimeType: JSONL_CONTENT_TYPE,
|
|
109
|
+
size: bytes.byteLength,
|
|
110
|
+
// A token of the caller's, when they gave one, so a dropped response on
|
|
111
|
+
// the staging call does not strand an object nobody will claim.
|
|
112
|
+
clientToken: options?.clientToken ?? randomToken(),
|
|
113
|
+
// A label for a human reading the upload list; it never reaches the
|
|
114
|
+
// object's location, which the platform composes from the store and an
|
|
115
|
+
// id it minted.
|
|
116
|
+
filename: options?.filename ?? 'bulk.jsonl',
|
|
117
|
+
},
|
|
118
|
+
// The CALLER's options, forwarded. Staging is a request like any other, and
|
|
119
|
+
// dropping them here sends it to the client's DEFAULT tenant while the
|
|
120
|
+
// submit that follows names the one the caller asked for — so the bytes
|
|
121
|
+
// land under the wrong store's prefix and the import then answers
|
|
122
|
+
// `UPLOAD_NOT_FOUND`, after they have already been uploaded. `signal` goes
|
|
123
|
+
// the same way: without it an abort cannot cancel the upload leg, which is
|
|
124
|
+
// the long one.
|
|
125
|
+
options);
|
|
126
|
+
await uploads.put(ticket, bytes);
|
|
127
|
+
return ticket.id;
|
|
128
|
+
}
|
|
129
|
+
async function readBytes(file) {
|
|
130
|
+
if (file instanceof Uint8Array)
|
|
131
|
+
return file;
|
|
132
|
+
if (file instanceof ArrayBuffer)
|
|
133
|
+
return new Uint8Array(file);
|
|
134
|
+
if (typeof Blob !== 'undefined' && file instanceof Blob) {
|
|
135
|
+
return new Uint8Array(await file.arrayBuffer());
|
|
136
|
+
}
|
|
137
|
+
return collectStream(file);
|
|
138
|
+
}
|
|
139
|
+
async function collectStream(stream) {
|
|
140
|
+
const chunks = [];
|
|
141
|
+
let total = 0;
|
|
142
|
+
const reader = stream.getReader();
|
|
143
|
+
for (;;) {
|
|
144
|
+
const { done, value } = await reader.read();
|
|
145
|
+
if (done)
|
|
146
|
+
break;
|
|
147
|
+
if (value) {
|
|
148
|
+
chunks.push(value);
|
|
149
|
+
total += value.byteLength;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const out = new Uint8Array(total);
|
|
153
|
+
let at = 0;
|
|
154
|
+
for (const chunk of chunks) {
|
|
155
|
+
out.set(chunk, at);
|
|
156
|
+
at += chunk.byteLength;
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
function randomToken() {
|
|
161
|
+
return globalThis.crypto.randomUUID();
|
|
162
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { type Page, type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Call, ListOptions } from '../types.js';
|
|
3
|
+
import { type CatalogueOwnership } from './types.js';
|
|
4
|
+
export interface Asset {
|
|
5
|
+
id: string;
|
|
6
|
+
createdAt: string;
|
|
7
|
+
updatedAt: string;
|
|
8
|
+
name: string;
|
|
9
|
+
type: 'IMAGE' | 'VIDEO' | 'BINARY';
|
|
10
|
+
mimeType: string;
|
|
11
|
+
fileSize: number;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
source: string;
|
|
15
|
+
preview: string;
|
|
16
|
+
/** Fractions of width and height (0–1); null when never set. */
|
|
17
|
+
focalPoint: {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
} | null;
|
|
21
|
+
tags: string[];
|
|
22
|
+
/** The store's own asset, or its organization's; see {@link CatalogueOwnership}. */
|
|
23
|
+
catalogueOwnership: CatalogueOwnership;
|
|
24
|
+
}
|
|
25
|
+
export interface CreateAssetInput {
|
|
26
|
+
file: Blob;
|
|
27
|
+
/**
|
|
28
|
+
* The name the asset is stored and listed under. Required unless `file` is a
|
|
29
|
+
* `File` (which carries its own): a bare Blob would otherwise be stored as
|
|
30
|
+
* "blob".
|
|
31
|
+
*/
|
|
32
|
+
fileName?: string;
|
|
33
|
+
tags?: string[];
|
|
34
|
+
}
|
|
35
|
+
export interface UpdateAssetInput {
|
|
36
|
+
id: string;
|
|
37
|
+
name?: string;
|
|
38
|
+
focalPoint?: {
|
|
39
|
+
x: number;
|
|
40
|
+
y: number;
|
|
41
|
+
} | null;
|
|
42
|
+
/** Replaces the tag list. */
|
|
43
|
+
tags?: string[];
|
|
44
|
+
}
|
|
45
|
+
/** One language's description of an image: its alt text in that language. */
|
|
46
|
+
export interface AssetDescription {
|
|
47
|
+
/** A language the store offers (`en`, `nl`, `pt_BR`). */
|
|
48
|
+
languageCode: string;
|
|
49
|
+
description: string;
|
|
50
|
+
}
|
|
51
|
+
/** What {@link AssetDescriptionsModule.set} saved. */
|
|
52
|
+
export interface AssetDescriptionsResult {
|
|
53
|
+
assetId: string;
|
|
54
|
+
/** The image's descriptions in the store, ordered by language. */
|
|
55
|
+
descriptions: AssetDescription[];
|
|
56
|
+
/** The image's alt text: the store's default-language description, or null when it has none. */
|
|
57
|
+
altText: string | null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* An image's descriptions in the client's store: what a storefront shows as its alt text, per
|
|
61
|
+
* language (headless W9-38). The content system keeps them per store; the engine keeps one alt
|
|
62
|
+
* text per image (`customFields.altText`), the store's default-language description.
|
|
63
|
+
*/
|
|
64
|
+
export interface AssetDescriptionsModule {
|
|
65
|
+
/**
|
|
66
|
+
* The image's descriptions in the client's store, ordered by language; `[]` when it has none.
|
|
67
|
+
* The content system's public read: it can also hold a language the store no longer offers,
|
|
68
|
+
* which `set` refuses, so leave such an entry out when sending the set back.
|
|
69
|
+
*/
|
|
70
|
+
get(assetId: string, options?: Call): Promise<AssetDescription[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Save the image's descriptions in the client's store AND its alt text, as one change.
|
|
73
|
+
* `descriptions` is the WHOLE set, one entry per language the store offers: a language left
|
|
74
|
+
* out is removed, and leaving out the store's default language clears the alt text. The alt
|
|
75
|
+
* text is one value wherever the image is used: another store holding it reads the new one.
|
|
76
|
+
*
|
|
77
|
+
* Both change or neither does. Repeating a call is safe: both are set to its input again,
|
|
78
|
+
* whatever an earlier attempt left, so a call that failed with `outcomeUnknown` is settled by
|
|
79
|
+
* sending it again. No idempotency key is needed (and none is acted on).
|
|
80
|
+
*
|
|
81
|
+
* Refused, nothing written: `CMS_PERMISSION_NOT_ALLOWED` (403, the caller holds no
|
|
82
|
+
* UpdateCmsAsset in the store), `ENTITY_NOT_FOUND` (404, an image this store does not hold),
|
|
83
|
+
* `MANAGED_BY_ORGANIZATION` (422, an image of the store's organization: change it in the
|
|
84
|
+
* workspace), `SHARED_ASSET_NOT_ALLOWED` (403, an image another store holds that the caller
|
|
85
|
+
* cannot change), `ASSET_DESCRIPTIONS_INVALID` (400, a language the store does not offer or
|
|
86
|
+
* named twice, a blank text, a text over 500 characters; `details[]` points at each),
|
|
87
|
+
* `FORBIDDEN` (403, neither UpdateCatalog nor UpdateAsset). `CMS_REQUEST_FAILED` (422): the
|
|
88
|
+
* content system did not save; nothing changed, or, with `outcomeUnknown`, the descriptions may
|
|
89
|
+
* have been saved while the alt text was not: send the same call again.
|
|
90
|
+
*
|
|
91
|
+
* Requires a platform release that serves `setAssetDescriptions`.
|
|
92
|
+
*/
|
|
93
|
+
set(assetId: string, descriptions: readonly AssetDescription[], options?: Call): Promise<AssetDescriptionsResult>;
|
|
94
|
+
}
|
|
95
|
+
export interface AssetListOptions extends ListOptions {
|
|
96
|
+
/** Case-insensitive substring of the name. */
|
|
97
|
+
name?: string;
|
|
98
|
+
/** Assets carrying ALL of these tags. */
|
|
99
|
+
tags?: string[];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The asset library. Assign an asset to a product, variant or collection with
|
|
103
|
+
* `assetIds` / `featuredAssetId` on that entity's own write.
|
|
104
|
+
*
|
|
105
|
+
* `create` uploads through the Admin API (GraphQL multipart), and is never
|
|
106
|
+
* retried by the SDK — a retry would upload the file twice. A file type the
|
|
107
|
+
* store does not permit is refused with `MIME_TYPE_ERROR`
|
|
108
|
+
* (`BusinessRuleError`): "The MIME type "…" is not permitted." For large files,
|
|
109
|
+
* `uploads` (spec §6.11) stages them directly to storage instead.
|
|
110
|
+
*
|
|
111
|
+
* A refused delete — "The selected Asset is featured by N Products" — is a
|
|
112
|
+
* `ConflictError` (`ASSET_NOT_DELETED`) unless `force` is set.
|
|
113
|
+
*/
|
|
114
|
+
export interface AssetsModule {
|
|
115
|
+
/** An image's descriptions (its alt text per language) in the store. */
|
|
116
|
+
descriptions: AssetDescriptionsModule;
|
|
117
|
+
list(options?: AssetListOptions): Promise<Page<Asset>>;
|
|
118
|
+
get(id: string, options?: Call): Promise<Asset | null>;
|
|
119
|
+
create(input: CreateAssetInput, options?: Call): Promise<Asset>;
|
|
120
|
+
update(input: UpdateAssetInput, options?: Call): Promise<Asset>;
|
|
121
|
+
delete(id: string, options?: Call & {
|
|
122
|
+
force?: boolean;
|
|
123
|
+
}): Promise<void>;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* An asset's own fields, without `catalogueOwnership`: what a read outside the catalogue (the
|
|
127
|
+
* settings images) selects, so it keeps working against an engine older than the field.
|
|
128
|
+
*/
|
|
129
|
+
export declare const ASSET_FILE_FIELDS = "\n id\n createdAt\n updatedAt\n name\n type\n mimeType\n fileSize\n width\n height\n source\n preview\n focalPoint {\n x\n y\n }\n tags {\n value\n }\n";
|
|
130
|
+
export declare const ASSET_FIELDS = "\n \n id\n createdAt\n updatedAt\n name\n type\n mimeType\n fileSize\n width\n height\n source\n preview\n focalPoint {\n x\n y\n }\n tags {\n value\n }\n\n \n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n\n";
|
|
131
|
+
export declare const ASSETS_QUERY = "\n query CatalogAssets($options: AssetListOptions) {\n assets(options: $options) {\n items { \n \n id\n createdAt\n updatedAt\n name\n type\n mimeType\n fileSize\n width\n height\n source\n preview\n focalPoint {\n x\n y\n }\n tags {\n value\n }\n\n \n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n\n }\n totalItems\n }\n }\n";
|
|
132
|
+
export declare const ASSET_QUERY = "\n query CatalogAsset($id: ID!) {\n asset(id: $id) { \n \n id\n createdAt\n updatedAt\n name\n type\n mimeType\n fileSize\n width\n height\n source\n preview\n focalPoint {\n x\n y\n }\n tags {\n value\n }\n\n \n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n\n }\n }\n";
|
|
133
|
+
export declare const CREATE_ASSETS_MUTATION = "\n mutation CatalogCreateAssets($input: [CreateAssetInput!]!) {\n createAssets(input: $input) {\n ... on Asset { \n \n id\n createdAt\n updatedAt\n name\n type\n mimeType\n fileSize\n width\n height\n source\n preview\n focalPoint {\n x\n y\n }\n tags {\n value\n }\n\n \n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n\n }\n ... on ErrorResult {\n errorCode\n message\n }\n }\n }\n";
|
|
134
|
+
export declare const UPDATE_ASSET_MUTATION = "\n mutation CatalogUpdateAsset($input: UpdateAssetInput!) {\n updateAsset(input: $input) { \n \n id\n createdAt\n updatedAt\n name\n type\n mimeType\n fileSize\n width\n height\n source\n preview\n focalPoint {\n x\n y\n }\n tags {\n value\n }\n\n \n catalogueOwnership {\n state\n organizationName\n editableHere\n }\n\n }\n }\n";
|
|
135
|
+
export declare const DELETE_ASSET_MUTATION = "\n mutation CatalogDeleteAsset($input: DeleteAssetInput!) {\n deleteAsset(input: $input) { \n result\n message\n }\n }\n";
|
|
136
|
+
export declare const SET_ASSET_DESCRIPTIONS_MUTATION = "\n mutation CatalogSetAssetDescriptions(\n $assetId: ID!\n $descriptions: [AssetDescriptionInput!]!\n ) {\n setAssetDescriptions(assetId: $assetId, descriptions: $descriptions) {\n assetId\n descriptions {\n languageCode\n description\n }\n altText\n }\n }\n";
|
|
137
|
+
/** An asset as {@link ASSET_FILE_FIELDS} reads it: no `catalogueOwnership`. */
|
|
138
|
+
export type AssetFile = Omit<Asset, 'catalogueOwnership'>;
|
|
139
|
+
/** An asset as the Admin API answers it: tags as objects. */
|
|
140
|
+
export type WireOf<T extends AssetFile> = Omit<T, 'tags'> & {
|
|
141
|
+
tags: Array<{
|
|
142
|
+
value: string;
|
|
143
|
+
}>;
|
|
144
|
+
};
|
|
145
|
+
export declare function toAsset(wire: WireOf<Asset>): Asset;
|
|
146
|
+
export declare function toAsset(wire: WireOf<AssetFile>): AssetFile;
|
|
147
|
+
export declare function createAssetsModule(transport: Transport): AssetsModule;
|