@salesforce/b2c-tooling-sdk 1.21.2 → 1.22.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/data/guides/enrichment.json +294 -0
- package/data/guides/index.json +376 -16
- package/data/help/index.json +6 -1
- package/data/job-steps/index.json +1 -1
- package/data/job-steps/job-steps.json +1 -1
- package/data/script-api/index.json +49 -5
- package/data/tooling/index.json +2 -2
- package/data/xsd/commercefeaturestate.xsd +1 -0
- package/data/xsd/index.json +2 -1
- package/data/xsd/redirecturl.xsd +2 -0
- package/dist/esm/auth/index.d.ts +6 -3
- package/dist/esm/auth/index.js +4 -2
- package/dist/esm/auth/index.js.map +1 -1
- package/dist/esm/auth/oauth-implicit.d.ts +19 -0
- package/dist/esm/auth/oauth-implicit.js +103 -10
- package/dist/esm/auth/oauth-implicit.js.map +1 -1
- package/dist/esm/auth/oauth-pkce-fallback.d.ts +68 -0
- package/dist/esm/auth/oauth-pkce-fallback.js +128 -0
- package/dist/esm/auth/oauth-pkce-fallback.js.map +1 -0
- package/dist/esm/auth/oauth-pkce.d.ts +94 -0
- package/dist/esm/auth/oauth-pkce.js +579 -0
- package/dist/esm/auth/oauth-pkce.js.map +1 -0
- package/dist/esm/auth/resolve.d.ts +4 -3
- package/dist/esm/auth/resolve.js +17 -2
- package/dist/esm/auth/resolve.js.map +1 -1
- package/dist/esm/auth/session-store.d.ts +99 -0
- package/dist/esm/auth/session-store.js +242 -0
- package/dist/esm/auth/session-store.js.map +1 -0
- package/dist/esm/auth/stateful-oauth-strategy.d.ts +20 -24
- package/dist/esm/auth/stateful-oauth-strategy.js +16 -114
- package/dist/esm/auth/stateful-oauth-strategy.js.map +1 -1
- package/dist/esm/auth/types.d.ts +20 -4
- package/dist/esm/auth/types.js +1 -1
- package/dist/esm/auth/types.js.map +1 -1
- package/dist/esm/cli/am-command.d.ts +2 -2
- package/dist/esm/cli/am-command.js +13 -4
- package/dist/esm/cli/am-command.js.map +1 -1
- package/dist/esm/cli/base-command.js +3 -3
- package/dist/esm/cli/base-command.js.map +1 -1
- package/dist/esm/cli/config.js +3 -1
- package/dist/esm/cli/config.js.map +1 -1
- package/dist/esm/cli/lifecycle.d.ts +1 -1
- package/dist/esm/cli/lifecycle.js.map +1 -1
- package/dist/esm/cli/oauth-command.d.ts +12 -11
- package/dist/esm/cli/oauth-command.js +73 -41
- package/dist/esm/cli/oauth-command.js.map +1 -1
- package/dist/esm/cli/ods-command.d.ts +1 -1
- package/dist/esm/cli/ods-command.js +5 -3
- package/dist/esm/cli/ods-command.js.map +1 -1
- package/dist/esm/clients/ods.generated.d.ts +16 -0
- package/dist/esm/config/dw-json.d.ts +10 -0
- package/dist/esm/config/dw-json.js.map +1 -1
- package/dist/esm/config/index.d.ts +1 -0
- package/dist/esm/config/index.js +2 -0
- package/dist/esm/config/index.js.map +1 -1
- package/dist/esm/config/mapping.d.ts +13 -0
- package/dist/esm/config/mapping.js +66 -3
- package/dist/esm/config/mapping.js.map +1 -1
- package/dist/esm/config/redaction.d.ts +39 -0
- package/dist/esm/config/redaction.js +51 -0
- package/dist/esm/config/redaction.js.map +1 -0
- package/dist/esm/config/resolver.js +1 -0
- package/dist/esm/config/resolver.js.map +1 -1
- package/dist/esm/config/sources/env-source.js +2 -0
- package/dist/esm/config/sources/env-source.js.map +1 -1
- package/dist/esm/config/sources/package-json-source.js +1 -0
- package/dist/esm/config/sources/package-json-source.js.map +1 -1
- package/dist/esm/config/types.d.ts +14 -4
- package/dist/esm/defaults.d.ts +23 -4
- package/dist/esm/defaults.js +36 -4
- package/dist/esm/defaults.js.map +1 -1
- package/dist/esm/docs/content-cache.d.ts +1 -1
- package/dist/esm/docs/content-cache.js +1 -1
- package/dist/esm/docs/index.d.ts +1 -1
- package/dist/esm/docs/index.js.map +1 -1
- package/dist/esm/docs/types.d.ts +29 -0
- package/dist/esm/index.d.ts +6 -4
- package/dist/esm/index.js +3 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/instance/index.js +3 -3
- package/dist/esm/instance/index.js.map +1 -1
- package/dist/esm/operations/cap/index.d.ts +2 -2
- package/dist/esm/operations/cap/index.js +1 -1
- package/dist/esm/operations/cap/index.js.map +1 -1
- package/dist/esm/operations/cap/install.d.ts +17 -0
- package/dist/esm/operations/cap/install.js +29 -0
- package/dist/esm/operations/cap/install.js.map +1 -1
- package/dist/esm/operations/cap/package.js +36 -0
- package/dist/esm/operations/cap/package.js.map +1 -1
- package/dist/esm/operations/cap/validate.d.ts +9 -0
- package/dist/esm/operations/cap/validate.js +29 -0
- package/dist/esm/operations/cap/validate.js.map +1 -1
- package/dist/esm/operations/content/export.js +7 -3
- package/dist/esm/operations/content/export.js.map +1 -1
- package/dist/esm/operations/content/library.d.ts +26 -0
- package/dist/esm/operations/content/library.js +83 -2
- package/dist/esm/operations/content/library.js.map +1 -1
- package/dist/esm/operations/content/types.d.ts +10 -1
- package/dist/esm/operations/jobs/import-set.d.ts +170 -0
- package/dist/esm/operations/jobs/import-set.js +538 -0
- package/dist/esm/operations/jobs/import-set.js.map +1 -0
- package/dist/esm/operations/jobs/index.d.ts +3 -0
- package/dist/esm/operations/jobs/index.js +3 -0
- package/dist/esm/operations/jobs/index.js.map +1 -1
- package/dist/esm/operations/jobs/run.js +0 -11
- package/dist/esm/operations/jobs/run.js.map +1 -1
- package/dist/esm/operations/jobs/site-archive.js +13 -75
- package/dist/esm/operations/jobs/site-archive.js.map +1 -1
- package/dist/esm/operations/ods/index.d.ts +4 -0
- package/dist/esm/operations/ods/index.js +2 -0
- package/dist/esm/operations/ods/index.js.map +1 -1
- package/dist/esm/operations/ods/sandbox-settings.d.ts +51 -0
- package/dist/esm/operations/ods/sandbox-settings.js +63 -0
- package/dist/esm/operations/ods/sandbox-settings.js.map +1 -0
- package/dist/esm/operations/ods/wait-for-clones.d.ts +97 -0
- package/dist/esm/operations/ods/wait-for-clones.js +145 -0
- package/dist/esm/operations/ods/wait-for-clones.js.map +1 -0
- package/dist/esm/skills/parser.js +2 -2
- package/dist/esm/skills/parser.js.map +1 -1
- package/package.json +1 -1
- package/specs/ods-api-v1.json +43 -0
- package/dist/esm/auth/stateful-store.d.ts +0 -49
- package/dist/esm/auth/stateful-store.js +0 -166
- package/dist/esm/auth/stateful-store.js.map +0 -1
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2
|
|
4
|
+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import { HTTPError } from '../../errors/http-error.js';
|
|
10
|
+
import { findCartridges } from '../code/cartridges.js';
|
|
11
|
+
import { siteArchiveImport } from './site-archive.js';
|
|
12
|
+
const DEFAULT_STATE_ROOT = 'Impex/b2c-cli/import-sets';
|
|
13
|
+
const DEFAULT_SET_ID = 'migrations';
|
|
14
|
+
const DEFAULT_STALE_LOCK_SECONDS = 30 * 60;
|
|
15
|
+
const DEFAULT_LOCK_POLL_INTERVAL_SECONDS = 3;
|
|
16
|
+
const DEFAULT_HEARTBEAT_INTERVAL_SECONDS = 30;
|
|
17
|
+
const SITE_ARCHIVE_DIRECTORY_NAMES = new Set([
|
|
18
|
+
'ab-tests',
|
|
19
|
+
'cache-settings',
|
|
20
|
+
'catalogs',
|
|
21
|
+
'coupons',
|
|
22
|
+
'csrf-allowlists',
|
|
23
|
+
'csrf-whitelists',
|
|
24
|
+
'customer-lists',
|
|
25
|
+
'custom-objects',
|
|
26
|
+
'dcext',
|
|
27
|
+
'geolocations',
|
|
28
|
+
'global-data',
|
|
29
|
+
'inventory',
|
|
30
|
+
'inventory-lists',
|
|
31
|
+
'jobs',
|
|
32
|
+
'libraries',
|
|
33
|
+
'locales',
|
|
34
|
+
'meta',
|
|
35
|
+
'oauth-providers',
|
|
36
|
+
'ocapi-settings',
|
|
37
|
+
'payment-methods',
|
|
38
|
+
'payment-processors',
|
|
39
|
+
'preferences',
|
|
40
|
+
'price-books',
|
|
41
|
+
'pricebooks',
|
|
42
|
+
'promotions',
|
|
43
|
+
'redirect-urls',
|
|
44
|
+
'search',
|
|
45
|
+
'services',
|
|
46
|
+
'shipping',
|
|
47
|
+
'sites',
|
|
48
|
+
'slots',
|
|
49
|
+
'sorting-rules',
|
|
50
|
+
'source-codes',
|
|
51
|
+
'sourcecodes',
|
|
52
|
+
'static',
|
|
53
|
+
'static-resources',
|
|
54
|
+
'stores',
|
|
55
|
+
'system-type-definitions',
|
|
56
|
+
'tax',
|
|
57
|
+
'users',
|
|
58
|
+
]);
|
|
59
|
+
/** Thrown when WebDAV lock or receipt state cannot be safely read or written. */
|
|
60
|
+
export class ImportSetStateError extends Error {
|
|
61
|
+
constructor(message) {
|
|
62
|
+
super(message);
|
|
63
|
+
this.name = 'ImportSetStateError';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Discovers import items from cartridge `metadata/` directories followed by
|
|
68
|
+
* the explicit import-set directory. A cartridge metadata directory that
|
|
69
|
+
* resembles a site archive is one item; otherwise its immediate child
|
|
70
|
+
* directories and zip archives are items. Cartridge sources are ordered by
|
|
71
|
+
* cartridge name, and child items within each source are sorted by name.
|
|
72
|
+
*/
|
|
73
|
+
export async function discoverImportSet(directory, options = {}) {
|
|
74
|
+
const resolvedDirectory = path.resolve(directory);
|
|
75
|
+
const excludedDirectories = resolveExcludedDirectories(options);
|
|
76
|
+
const cartridgeItems = options.includeCartridgeMetadata === false ? [] : await discoverCartridgeMetadata(options, excludedDirectories);
|
|
77
|
+
const directoryItems = await discoverImportDirectory(resolvedDirectory, '', excludedDirectories);
|
|
78
|
+
const items = [...cartridgeItems, ...directoryItems];
|
|
79
|
+
if (items.length === 0) {
|
|
80
|
+
const importDirectoryExists = await isDirectory(resolvedDirectory);
|
|
81
|
+
if (!importDirectoryExists && options.includeCartridgeMetadata === false) {
|
|
82
|
+
throw new Error(`Import-set directory does not exist: ${resolvedDirectory}`);
|
|
83
|
+
}
|
|
84
|
+
throw new Error(options.includeCartridgeMetadata === false
|
|
85
|
+
? `No import directories or zip archives found in ${resolvedDirectory}`
|
|
86
|
+
: `No import directories or zip archives found in ${resolvedDirectory} or discovered cartridge metadata`);
|
|
87
|
+
}
|
|
88
|
+
const itemIds = new Set();
|
|
89
|
+
for (const item of items) {
|
|
90
|
+
if (itemIds.has(item.id))
|
|
91
|
+
throw new Error(`Duplicate import-set item ID: ${item.id}`);
|
|
92
|
+
itemIds.add(item.id);
|
|
93
|
+
}
|
|
94
|
+
return items;
|
|
95
|
+
}
|
|
96
|
+
async function discoverCartridgeMetadata(options, excludedDirectories) {
|
|
97
|
+
const cartridges = findCartridges(options.cartridgeRoot)
|
|
98
|
+
.filter((cartridge) => !isExcludedPath(cartridge.src, excludedDirectories))
|
|
99
|
+
.sort((a, b) => a.name.localeCompare(b.name, 'en', { numeric: false }));
|
|
100
|
+
const items = [];
|
|
101
|
+
for (const cartridge of cartridges) {
|
|
102
|
+
const metadataDirectory = path.join(cartridge.src, 'metadata');
|
|
103
|
+
// eslint-disable-next-line no-await-in-loop
|
|
104
|
+
const metadataEntries = await readDirectory(metadataDirectory);
|
|
105
|
+
if (!metadataEntries)
|
|
106
|
+
continue;
|
|
107
|
+
if (looksLikeSiteArchive(metadataEntries)) {
|
|
108
|
+
items.push({
|
|
109
|
+
id: `cartridge-metadata/${cartridge.name}`,
|
|
110
|
+
target: metadataDirectory,
|
|
111
|
+
kind: 'directory',
|
|
112
|
+
// eslint-disable-next-line no-await-in-loop
|
|
113
|
+
note: await readItemNote(metadataDirectory),
|
|
114
|
+
});
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// Keep source discovery sequential so ordering is explicit and stable.
|
|
118
|
+
// eslint-disable-next-line no-await-in-loop
|
|
119
|
+
const cartridgeItems = await discoverImportDirectory(metadataDirectory, `cartridge-metadata/${cartridge.name}/`, excludedDirectories);
|
|
120
|
+
items.push(...cartridgeItems);
|
|
121
|
+
}
|
|
122
|
+
return items;
|
|
123
|
+
}
|
|
124
|
+
function looksLikeSiteArchive(entries) {
|
|
125
|
+
return entries.some((entry) => {
|
|
126
|
+
if (entry.name.startsWith('.'))
|
|
127
|
+
return false;
|
|
128
|
+
if (entry.isFile())
|
|
129
|
+
return path.extname(entry.name).toLowerCase() === '.xml';
|
|
130
|
+
if (!entry.isDirectory())
|
|
131
|
+
return false;
|
|
132
|
+
return SITE_ARCHIVE_DIRECTORY_NAMES.has(entry.name.toLowerCase().replaceAll('_', '-'));
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async function readDirectory(directory) {
|
|
136
|
+
const stat = await fs.promises.stat(directory).catch(() => undefined);
|
|
137
|
+
if (!stat)
|
|
138
|
+
return undefined;
|
|
139
|
+
if (!stat.isDirectory())
|
|
140
|
+
throw new Error(`Import-set source is not a directory: ${directory}`);
|
|
141
|
+
return fs.promises.readdir(directory, { withFileTypes: true });
|
|
142
|
+
}
|
|
143
|
+
async function discoverImportDirectory(directory, idPrefix = '', excludedDirectories = []) {
|
|
144
|
+
const entries = await readDirectory(directory);
|
|
145
|
+
if (!entries)
|
|
146
|
+
return [];
|
|
147
|
+
const candidates = entries
|
|
148
|
+
.filter((entry) => !entry.name.startsWith('.'))
|
|
149
|
+
.filter((entry) => entry.isDirectory() || (entry.isFile() && path.extname(entry.name).toLowerCase() === '.zip'))
|
|
150
|
+
.filter((entry) => !isExcludedPath(path.join(directory, entry.name), excludedDirectories))
|
|
151
|
+
.sort((a, b) => a.name.localeCompare(b.name, 'en', { numeric: false }));
|
|
152
|
+
return Promise.all(candidates.map(async (entry) => {
|
|
153
|
+
const target = path.join(directory, entry.name);
|
|
154
|
+
const kind = entry.isDirectory() ? 'directory' : 'zip';
|
|
155
|
+
return {
|
|
156
|
+
id: `${idPrefix}${entry.name}`,
|
|
157
|
+
target,
|
|
158
|
+
kind,
|
|
159
|
+
note: kind === 'directory' ? await readItemNote(target) : undefined,
|
|
160
|
+
};
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
function resolveExcludedDirectories(options) {
|
|
164
|
+
const root = path.resolve(options.cartridgeRoot ?? process.cwd());
|
|
165
|
+
const configuredDirectories = options.excludeDirectories ?? [];
|
|
166
|
+
return [
|
|
167
|
+
...new Set(configuredDirectories
|
|
168
|
+
.filter((directory) => typeof directory === 'string' && directory.trim().length > 0)
|
|
169
|
+
.map((directory) => path.resolve(root, directory.trim()))),
|
|
170
|
+
];
|
|
171
|
+
}
|
|
172
|
+
/** README filenames checked, in priority order, at the top of a directory item. */
|
|
173
|
+
const README_FILENAMES = ['README.md', 'README'];
|
|
174
|
+
/**
|
|
175
|
+
* Reads the first README file at the top of a directory item, if present.
|
|
176
|
+
* Returns the trimmed contents, or undefined when no README exists or it is empty.
|
|
177
|
+
*/
|
|
178
|
+
async function readItemNote(directory) {
|
|
179
|
+
for (const filename of README_FILENAMES) {
|
|
180
|
+
// eslint-disable-next-line no-await-in-loop
|
|
181
|
+
const contents = await fs.promises.readFile(path.join(directory, filename), 'utf8').catch(() => undefined);
|
|
182
|
+
if (contents === undefined)
|
|
183
|
+
continue;
|
|
184
|
+
const trimmed = contents.trim();
|
|
185
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
186
|
+
}
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
function isExcludedPath(candidate, excludedDirectories) {
|
|
190
|
+
return excludedDirectories.some((excludedDirectory) => {
|
|
191
|
+
const relativePath = path.relative(excludedDirectory, candidate);
|
|
192
|
+
return relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
async function isDirectory(directory) {
|
|
196
|
+
const stat = await fs.promises.stat(directory).catch(() => undefined);
|
|
197
|
+
return stat?.isDirectory() === true;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Applies an ordered set of site archives exactly until a verified receipt
|
|
201
|
+
* directory is created for each item name. A missing or invalid receipt always
|
|
202
|
+
* leaves the item pending, even if a previous process may have completed the
|
|
203
|
+
* platform import.
|
|
204
|
+
*
|
|
205
|
+
* The operation uses an exclusive WebDAV directory (`MKCOL`) as a best-effort
|
|
206
|
+
* set-wide lock. B2C Commerce does not provide conditional WebDAV deletes, so
|
|
207
|
+
* stale lock takeover is intentionally observable through progress events.
|
|
208
|
+
* The operation never logs or writes output; callers can consume structured
|
|
209
|
+
* progress through {@link SiteArchiveImportSetOptions.onEvent}.
|
|
210
|
+
*/
|
|
211
|
+
export async function siteArchiveImportSet(instance, directory, options = {}) {
|
|
212
|
+
const resolvedDirectory = path.resolve(directory);
|
|
213
|
+
const setId = options.setId ?? DEFAULT_SET_ID;
|
|
214
|
+
validateSetId(setId);
|
|
215
|
+
validateStateRoot(options.stateRoot ?? DEFAULT_STATE_ROOT);
|
|
216
|
+
const runId = randomUUID();
|
|
217
|
+
const items = await discoverImportSet(resolvedDirectory, {
|
|
218
|
+
includeCartridgeMetadata: options.includeCartridgeMetadata,
|
|
219
|
+
cartridgeRoot: options.cartridgeRoot,
|
|
220
|
+
excludeDirectories: options.excludeDirectories,
|
|
221
|
+
});
|
|
222
|
+
const stateRoot = (options.stateRoot ?? DEFAULT_STATE_ROOT).replace(/\/+$/, '');
|
|
223
|
+
const setRoot = `${stateRoot}/${setId}`;
|
|
224
|
+
const receiptsRoot = `${setRoot}/receipts`;
|
|
225
|
+
const lockPath = `${setRoot}/lock`;
|
|
226
|
+
const sleep = options.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
|
|
227
|
+
const importArchive = options.importArchive ?? siteArchiveImport;
|
|
228
|
+
let itemResults = await evaluateReceipts(instance, setId, receiptsRoot, items, options.onEvent);
|
|
229
|
+
emitPlan(options, setId, itemResults);
|
|
230
|
+
if (options.dryRun || itemResults.every((item) => item.status === 'skipped')) {
|
|
231
|
+
return buildResult(setId, resolvedDirectory, Boolean(options.dryRun), runId, itemResults);
|
|
232
|
+
}
|
|
233
|
+
await ensureCollection(instance, stateRoot, sleep);
|
|
234
|
+
await ensureCollection(instance, setRoot, sleep);
|
|
235
|
+
await ensureCollection(instance, receiptsRoot, sleep);
|
|
236
|
+
const lockOwner = await acquireLock(instance, lockPath, setId, runId, options, sleep);
|
|
237
|
+
let heartbeatError;
|
|
238
|
+
let heartbeatChain = Promise.resolve();
|
|
239
|
+
const heartbeatInterval = Math.max(1, options.heartbeatIntervalSeconds ?? DEFAULT_HEARTBEAT_INTERVAL_SECONDS);
|
|
240
|
+
const heartbeatTimer = setInterval(() => {
|
|
241
|
+
heartbeatChain = heartbeatChain
|
|
242
|
+
.then(() => heartbeatLock(instance, lockPath, lockOwner))
|
|
243
|
+
.catch((error) => {
|
|
244
|
+
heartbeatError = error instanceof Error ? error : new Error(String(error));
|
|
245
|
+
});
|
|
246
|
+
}, heartbeatInterval * 1000);
|
|
247
|
+
heartbeatTimer.unref();
|
|
248
|
+
let operationError;
|
|
249
|
+
try {
|
|
250
|
+
// Another runner may have completed work while this process waited.
|
|
251
|
+
itemResults = await evaluateReceipts(instance, setId, receiptsRoot, items, options.onEvent);
|
|
252
|
+
const total = itemResults.length;
|
|
253
|
+
for (const [index, itemResult] of itemResults.entries()) {
|
|
254
|
+
if (itemResult.status === 'skipped') {
|
|
255
|
+
options.onEvent?.({
|
|
256
|
+
type: 'item-skipped',
|
|
257
|
+
item: itemResult,
|
|
258
|
+
receipt: itemResult.receipt,
|
|
259
|
+
index: index + 1,
|
|
260
|
+
total,
|
|
261
|
+
});
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (heartbeatError)
|
|
265
|
+
throw heartbeatError;
|
|
266
|
+
await heartbeatLock(instance, lockPath, lockOwner);
|
|
267
|
+
options.onEvent?.({ type: 'item-importing', item: itemResult, index: index + 1, total });
|
|
268
|
+
const importResult = await importArchive(instance, itemResult.target, {
|
|
269
|
+
keepArchive: options.keepArchive,
|
|
270
|
+
wait: true,
|
|
271
|
+
waitOptions: options.waitOptions,
|
|
272
|
+
});
|
|
273
|
+
if (heartbeatError)
|
|
274
|
+
throw heartbeatError;
|
|
275
|
+
const receipt = createReceipt(setId, receiptsRoot, itemResult.id);
|
|
276
|
+
await writeAndVerifyReceipt(instance, receipt.receiptPath);
|
|
277
|
+
itemResult.status = 'imported';
|
|
278
|
+
itemResult.receipt = receipt;
|
|
279
|
+
itemResult.importResult = importResult;
|
|
280
|
+
options.onEvent?.({ type: 'item-imported', item: itemResult, receipt, index: index + 1, total });
|
|
281
|
+
}
|
|
282
|
+
return buildResult(setId, resolvedDirectory, false, runId, itemResults);
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
operationError = error;
|
|
286
|
+
throw error;
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
clearInterval(heartbeatTimer);
|
|
290
|
+
await heartbeatChain;
|
|
291
|
+
try {
|
|
292
|
+
await releaseLock(instance, lockPath, runId);
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
// Preserve an import or receipt error so callers can report the real
|
|
296
|
+
// failure. An unreleased lock will become eligible for stale takeover.
|
|
297
|
+
if (operationError === undefined)
|
|
298
|
+
throw error;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async function evaluateReceipts(instance, setId, receiptsRoot, items, onEvent) {
|
|
303
|
+
const results = [];
|
|
304
|
+
for (const item of items) {
|
|
305
|
+
const remotePath = receiptPath(receiptsRoot, item.id);
|
|
306
|
+
// Receipt reads are intentionally sequential to avoid bursting WebDAV on large sets.
|
|
307
|
+
// eslint-disable-next-line no-await-in-loop
|
|
308
|
+
const read = await readReceiptDirectory(instance, remotePath);
|
|
309
|
+
if (!read.found) {
|
|
310
|
+
results.push({ ...item, status: 'pending' });
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (!read.valid) {
|
|
314
|
+
onEvent?.({ type: 'receipt-invalid', item, receiptPath: remotePath });
|
|
315
|
+
results.push({ ...item, status: 'pending' });
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
results.push({ ...item, status: 'skipped', receipt: createReceipt(setId, receiptsRoot, item.id) });
|
|
319
|
+
}
|
|
320
|
+
return results;
|
|
321
|
+
}
|
|
322
|
+
async function acquireLock(instance, lockPath, setId, runId, options, sleep) {
|
|
323
|
+
const staleSeconds = Math.max(1, options.staleLockSeconds ?? DEFAULT_STALE_LOCK_SECONDS);
|
|
324
|
+
const pollMilliseconds = Math.max(1, options.lockPollIntervalSeconds ?? DEFAULT_LOCK_POLL_INTERVAL_SECONDS) * 1000;
|
|
325
|
+
let forceBreak = Boolean(options.breakLock);
|
|
326
|
+
let waitNotified = false;
|
|
327
|
+
while (true) {
|
|
328
|
+
// MKCOL is the only conditional creation primitive B2C WebDAV enforces.
|
|
329
|
+
// eslint-disable-next-line no-await-in-loop
|
|
330
|
+
const response = await instance.webdav.request(lockPath, { method: 'MKCOL' });
|
|
331
|
+
if (response.status === 201) {
|
|
332
|
+
const now = new Date().toISOString();
|
|
333
|
+
const owner = {
|
|
334
|
+
version: 1,
|
|
335
|
+
setId,
|
|
336
|
+
runId,
|
|
337
|
+
createdAt: now,
|
|
338
|
+
heartbeatAt: now,
|
|
339
|
+
owner: options.owner,
|
|
340
|
+
};
|
|
341
|
+
try {
|
|
342
|
+
// eslint-disable-next-line no-await-in-loop
|
|
343
|
+
await putJson(instance, `${lockPath}/owner.json`, owner);
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
await deletePath(instance, lockPath);
|
|
347
|
+
throw error;
|
|
348
|
+
}
|
|
349
|
+
options.onEvent?.({ type: 'lock-acquired', setId, runId });
|
|
350
|
+
return owner;
|
|
351
|
+
}
|
|
352
|
+
if (response.status !== 405 && response.status !== 409) {
|
|
353
|
+
throw new ImportSetStateError(`Unable to acquire import-set lock ${lockPath}: ${response.status} ${response.statusText}`);
|
|
354
|
+
}
|
|
355
|
+
// eslint-disable-next-line no-await-in-loop
|
|
356
|
+
const info = await readLockInfo(instance, lockPath);
|
|
357
|
+
const stale = info.ageSeconds !== undefined && info.ageSeconds >= staleSeconds;
|
|
358
|
+
if (forceBreak || stale) {
|
|
359
|
+
options.onEvent?.({
|
|
360
|
+
type: 'lock-takeover',
|
|
361
|
+
setId,
|
|
362
|
+
owner: info.owner,
|
|
363
|
+
ageSeconds: info.ageSeconds,
|
|
364
|
+
forced: forceBreak,
|
|
365
|
+
});
|
|
366
|
+
// B2C WebDAV ignores conditional DELETE, so stale takeover is best effort.
|
|
367
|
+
// eslint-disable-next-line no-await-in-loop
|
|
368
|
+
await deletePath(instance, lockPath);
|
|
369
|
+
forceBreak = false;
|
|
370
|
+
waitNotified = false;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
if (!waitNotified) {
|
|
374
|
+
options.onEvent?.({ type: 'lock-wait', setId, owner: info.owner, ageSeconds: info.ageSeconds });
|
|
375
|
+
waitNotified = true;
|
|
376
|
+
}
|
|
377
|
+
// eslint-disable-next-line no-await-in-loop
|
|
378
|
+
await sleep(pollMilliseconds);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
async function heartbeatLock(instance, lockPath, owner) {
|
|
382
|
+
const ownerPath = `${lockPath}/owner.json`;
|
|
383
|
+
const current = await readJson(instance, ownerPath);
|
|
384
|
+
if (!current.found || !current.valid || current.value?.runId !== owner.runId) {
|
|
385
|
+
throw new ImportSetStateError(`Import-set lock ${lockPath} is no longer owned by run ${owner.runId}`);
|
|
386
|
+
}
|
|
387
|
+
owner.heartbeatAt = new Date().toISOString();
|
|
388
|
+
await putJson(instance, ownerPath, owner);
|
|
389
|
+
}
|
|
390
|
+
async function releaseLock(instance, lockPath, runId) {
|
|
391
|
+
const current = await readJson(instance, `${lockPath}/owner.json`);
|
|
392
|
+
if (current.found && current.valid && current.value?.runId === runId) {
|
|
393
|
+
await deletePath(instance, lockPath);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
async function readLockInfo(instance, lockPath) {
|
|
397
|
+
const ownerRead = await readJson(instance, `${lockPath}/owner.json`);
|
|
398
|
+
const owner = ownerRead.valid ? ownerRead.value : undefined;
|
|
399
|
+
const timestamp = owner?.heartbeatAt ?? owner?.createdAt;
|
|
400
|
+
if (timestamp) {
|
|
401
|
+
const milliseconds = Date.parse(timestamp);
|
|
402
|
+
if (Number.isFinite(milliseconds)) {
|
|
403
|
+
return { owner, ageSeconds: Math.max(0, (Date.now() - milliseconds) / 1000) };
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
try {
|
|
407
|
+
const entries = await instance.webdav.propfind(lockPath, '0');
|
|
408
|
+
const modified = entries[0]?.lastModified;
|
|
409
|
+
return {
|
|
410
|
+
owner,
|
|
411
|
+
ageSeconds: modified ? Math.max(0, (Date.now() - modified.getTime()) / 1000) : undefined,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
return { owner };
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
async function ensureCollection(instance, remotePath, sleep) {
|
|
419
|
+
const segments = remotePath.split('/').filter(Boolean);
|
|
420
|
+
if (segments.length < 2)
|
|
421
|
+
throw new ImportSetStateError(`Invalid WebDAV state path: ${remotePath}`);
|
|
422
|
+
let current = segments[0];
|
|
423
|
+
for (const segment of segments.slice(1)) {
|
|
424
|
+
current = `${current}/${segment}`;
|
|
425
|
+
// eslint-disable-next-line no-await-in-loop
|
|
426
|
+
const response = await instance.webdav.request(current, { method: 'MKCOL' });
|
|
427
|
+
if (response.status === 201 || response.status === 405)
|
|
428
|
+
continue;
|
|
429
|
+
if (response.status === 409) {
|
|
430
|
+
// Concurrent creators can receive 409 while the winning collection becomes visible.
|
|
431
|
+
// eslint-disable-next-line no-await-in-loop
|
|
432
|
+
await sleep(25);
|
|
433
|
+
// eslint-disable-next-line no-await-in-loop
|
|
434
|
+
const head = await instance.webdav.request(current, { method: 'HEAD' });
|
|
435
|
+
if (head.ok)
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
throw new ImportSetStateError(`Unable to create WebDAV collection ${current}: ${response.status} ${response.statusText}`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
async function readJson(instance, remotePath) {
|
|
442
|
+
const response = await instance.webdav.request(remotePath, { method: 'GET' });
|
|
443
|
+
if (response.status === 404)
|
|
444
|
+
return { found: false, valid: false };
|
|
445
|
+
if (!response.ok) {
|
|
446
|
+
throw new ImportSetStateError(`Unable to read WebDAV state ${remotePath}: ${response.status} ${response.statusText}`);
|
|
447
|
+
}
|
|
448
|
+
try {
|
|
449
|
+
return { found: true, valid: true, value: JSON.parse(await response.text()) };
|
|
450
|
+
}
|
|
451
|
+
catch {
|
|
452
|
+
return { found: true, valid: false };
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
async function putJson(instance, remotePath, value) {
|
|
456
|
+
const response = await instance.webdav.request(remotePath, {
|
|
457
|
+
method: 'PUT',
|
|
458
|
+
headers: { 'Content-Type': 'application/json' },
|
|
459
|
+
body: `${JSON.stringify(value, null, 2)}\n`,
|
|
460
|
+
});
|
|
461
|
+
if (!response.ok) {
|
|
462
|
+
throw new ImportSetStateError(`Unable to write WebDAV state ${remotePath}: ${response.status} ${response.statusText}`);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
async function readReceiptDirectory(instance, remotePath) {
|
|
466
|
+
try {
|
|
467
|
+
const entries = await instance.webdav.propfind(remotePath, '0');
|
|
468
|
+
return { found: true, valid: entries[0]?.isCollection === true };
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
if (error instanceof HTTPError && error.response.status === 404)
|
|
472
|
+
return { found: false, valid: false };
|
|
473
|
+
throw new ImportSetStateError(`Unable to read WebDAV receipt directory ${remotePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
async function writeAndVerifyReceipt(instance, remotePath) {
|
|
477
|
+
let response = await instance.webdav.request(remotePath, { method: 'MKCOL' });
|
|
478
|
+
if (response.status === 405) {
|
|
479
|
+
const existing = await readReceiptDirectory(instance, remotePath);
|
|
480
|
+
if (!existing.valid) {
|
|
481
|
+
await deletePath(instance, remotePath);
|
|
482
|
+
response = await instance.webdav.request(remotePath, { method: 'MKCOL' });
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (response.status !== 201 && response.status !== 405) {
|
|
486
|
+
throw new ImportSetStateError(`Unable to create WebDAV receipt directory ${remotePath}: ${response.status} ${response.statusText}`);
|
|
487
|
+
}
|
|
488
|
+
const verification = await readReceiptDirectory(instance, remotePath);
|
|
489
|
+
if (!verification.found || !verification.valid) {
|
|
490
|
+
throw new ImportSetStateError(`Receipt directory verification failed for ${remotePath}; the import will be retried.`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
async function deletePath(instance, remotePath) {
|
|
494
|
+
const response = await instance.webdav.request(remotePath, { method: 'DELETE' });
|
|
495
|
+
if (!response.ok && response.status !== 404) {
|
|
496
|
+
throw new ImportSetStateError(`Unable to delete WebDAV state ${remotePath}: ${response.status} ${response.statusText}`);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
function createReceipt(setId, receiptsRoot, itemId) {
|
|
500
|
+
return { version: 1, setId, itemId, receiptPath: receiptPath(receiptsRoot, itemId) };
|
|
501
|
+
}
|
|
502
|
+
function receiptPath(receiptsRoot, itemId) {
|
|
503
|
+
return `${receiptsRoot}/${createHash('sha256').update(itemId).digest('hex')}`;
|
|
504
|
+
}
|
|
505
|
+
function emitPlan(options, setId, items) {
|
|
506
|
+
options.onEvent?.({
|
|
507
|
+
type: 'plan',
|
|
508
|
+
setId,
|
|
509
|
+
total: items.length,
|
|
510
|
+
pending: items.filter((item) => item.status === 'pending').length,
|
|
511
|
+
skipped: items.filter((item) => item.status === 'skipped').length,
|
|
512
|
+
dryRun: Boolean(options.dryRun),
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
function buildResult(setId, directory, dryRun, runId, items) {
|
|
516
|
+
return {
|
|
517
|
+
setId,
|
|
518
|
+
directory,
|
|
519
|
+
dryRun,
|
|
520
|
+
runId,
|
|
521
|
+
items,
|
|
522
|
+
imported: items.filter((item) => item.status === 'imported').length,
|
|
523
|
+
skipped: items.filter((item) => item.status === 'skipped').length,
|
|
524
|
+
pending: items.filter((item) => item.status === 'pending').length,
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
function validateSetId(setId) {
|
|
528
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(setId)) {
|
|
529
|
+
throw new Error(`Invalid import-set ID "${setId}". Use 1-128 letters, numbers, dots, underscores, or hyphens.`);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
function validateStateRoot(stateRoot) {
|
|
533
|
+
const segments = stateRoot.split('/').filter(Boolean);
|
|
534
|
+
if (segments[0]?.toLowerCase() !== 'impex' || segments.some((segment) => segment === '.' || segment === '..')) {
|
|
535
|
+
throw new Error(`Import-set state root must be a path under Impex: ${stateRoot}`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
//# sourceMappingURL=import-set.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-set.js","sourceRoot":"","sources":["../../../../src/operations/jobs/import-set.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* ## System Jobs
|
|
17
17
|
*
|
|
18
18
|
* - {@link siteArchiveImport} - Import a site archive
|
|
19
|
+
* - {@link siteArchiveImportSet} - Apply an ordered, receipted set of site archives
|
|
19
20
|
* - {@link siteArchiveImportSplit} - Import a large site archive in multiple parts
|
|
20
21
|
* - {@link siteArchiveExport} - Export a site archive
|
|
21
22
|
* - {@link siteArchiveExportToPath} - Export and save to local path
|
|
@@ -64,6 +65,8 @@
|
|
|
64
65
|
export { executeJob, getJobExecution, waitForJob, searchJobExecutions, findRunningJobExecution, getJobLog, getJobErrorMessage, JobExecutionError, } from './run.js';
|
|
65
66
|
export type { JobExecution, JobStepExecution, JobExecutionStatus, JobExecutionParameter, ExecuteJobOptions, WaitForJobOptions, WaitForJobPollInfo, SearchJobExecutionsOptions, JobExecutionSearchResult, } from './run.js';
|
|
66
67
|
export { siteArchiveImport, siteArchiveImportSplit, siteArchiveExport, siteArchiveExportToBuffer, siteArchiveExportToPath, } from './site-archive.js';
|
|
68
|
+
export { discoverImportSet, siteArchiveImportSet, ImportSetStateError } from './import-set.js';
|
|
69
|
+
export type { DiscoverImportSetOptions, ImportSetItem, ImportSetReceipt, ImportSetItemResult, ImportSetResult, ImportSetEvent, ImportSetLockOwner, SiteArchiveImportSetOptions, } from './import-set.js';
|
|
67
70
|
export type { SiteArchiveImportOptions, SiteArchiveImportResult, SiteArchiveImportSplitOptions, SplitImportPlanInfo, SplitImportPartInfo, SiteArchiveExportOptions, SiteArchiveExportResult, ExportDataUnitsConfiguration, ExportSitesConfiguration, ExportGlobalDataConfiguration, } from './site-archive.js';
|
|
68
71
|
export { discoverExportableUnits } from './discover.js';
|
|
69
72
|
export type { ExportableUnits } from './discover.js';
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* ## System Jobs
|
|
22
22
|
*
|
|
23
23
|
* - {@link siteArchiveImport} - Import a site archive
|
|
24
|
+
* - {@link siteArchiveImportSet} - Apply an ordered, receipted set of site archives
|
|
24
25
|
* - {@link siteArchiveImportSplit} - Import a large site archive in multiple parts
|
|
25
26
|
* - {@link siteArchiveExport} - Export a site archive
|
|
26
27
|
* - {@link siteArchiveExportToPath} - Export and save to local path
|
|
@@ -70,6 +71,8 @@
|
|
|
70
71
|
export { executeJob, getJobExecution, waitForJob, searchJobExecutions, findRunningJobExecution, getJobLog, getJobErrorMessage, JobExecutionError, } from './run.js';
|
|
71
72
|
// Site archive import/export
|
|
72
73
|
export { siteArchiveImport, siteArchiveImportSplit, siteArchiveExport, siteArchiveExportToBuffer, siteArchiveExportToPath, } from './site-archive.js';
|
|
74
|
+
// Ordered, idempotent import sets
|
|
75
|
+
export { discoverImportSet, siteArchiveImportSet, ImportSetStateError } from './import-set.js';
|
|
73
76
|
// Exportable data unit discovery
|
|
74
77
|
export { discoverExportableUnits } from './discover.js';
|
|
75
78
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/operations/jobs/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/operations/jobs/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AAEH,qBAAqB;AACrB,OAAO,EACL,UAAU,EACV,eAAe,EACf,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,SAAS,EACT,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAclB,6BAA6B;AAC7B,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAE3B,kCAAkC;AAClC,OAAO,EAAC,iBAAiB,EAAE,oBAAoB,EAAE,mBAAmB,EAAC,MAAM,iBAAiB,CAAC;AA0B7F,iCAAiC;AACjC,OAAO,EAAC,uBAAuB,EAAC,MAAM,eAAe,CAAC"}
|
|
@@ -137,13 +137,11 @@ export async function getJobExecution(instance, jobId, executionId) {
|
|
|
137
137
|
* ```
|
|
138
138
|
*/
|
|
139
139
|
export async function waitForJob(instance, jobId, executionId, options = {}) {
|
|
140
|
-
const logger = getLogger();
|
|
141
140
|
const { pollIntervalSeconds = 3, timeoutSeconds = 0, onPoll } = options;
|
|
142
141
|
const sleepFn = options.sleep ?? defaultSleep;
|
|
143
142
|
const startTime = Date.now();
|
|
144
143
|
const pollIntervalMs = pollIntervalSeconds * 1000;
|
|
145
144
|
const timeoutMs = timeoutSeconds * 1000;
|
|
146
|
-
let ticks = 0;
|
|
147
145
|
await sleepFn(pollIntervalMs);
|
|
148
146
|
while (true) {
|
|
149
147
|
const elapsedSeconds = Math.round((Date.now() - startTime) / 1000);
|
|
@@ -152,23 +150,14 @@ export async function waitForJob(instance, jobId, executionId, options = {}) {
|
|
|
152
150
|
}
|
|
153
151
|
const execution = await getJobExecution(instance, jobId, executionId);
|
|
154
152
|
const currentStatus = execution.execution_status ?? 'unknown';
|
|
155
|
-
logger.trace({ jobId, executionId, elapsedSeconds, status: currentStatus }, '[Jobs] Job poll');
|
|
156
153
|
onPoll?.({ jobId, executionId, elapsedSeconds, status: currentStatus });
|
|
157
154
|
// Check for terminal states
|
|
158
155
|
if (execution.execution_status === 'aborted' || execution.exit_status?.code === 'ERROR') {
|
|
159
|
-
logger.debug({ jobId, executionId, execution }, `Job ${jobId} failed`);
|
|
160
156
|
throw new JobExecutionError(`Job ${jobId} failed`, execution);
|
|
161
157
|
}
|
|
162
158
|
if (execution.execution_status === 'finished') {
|
|
163
|
-
const durationSec = (execution.duration ?? 0) / 1000;
|
|
164
|
-
logger.debug({ jobId, executionId, status: execution.exit_status?.code, duration: durationSec }, `Job ${jobId} finished. Status: ${execution.exit_status?.code} (duration: ${durationSec}s)`);
|
|
165
159
|
return execution;
|
|
166
160
|
}
|
|
167
|
-
// Log periodic updates
|
|
168
|
-
if (ticks % 5 === 0) {
|
|
169
|
-
logger.debug({ jobId, executionId, status: currentStatus, elapsed: elapsedSeconds }, `Waiting for job ${jobId} to finish (${elapsedSeconds}s elapsed)...`);
|
|
170
|
-
}
|
|
171
|
-
ticks++;
|
|
172
161
|
await sleepFn(pollIntervalMs);
|
|
173
162
|
}
|
|
174
163
|
}
|