itd-api 0.9.1 → 0.9.3
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/dist/events/index.cjs +3 -4
- package/dist/events/index.d.cts +3 -3
- package/dist/events/index.d.ts +3 -3
- package/dist/events/index.js +4 -4
- package/dist/index.cjs +283 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -72
- package/dist/index.d.ts +16 -72
- package/dist/index.js +284 -90
- package/dist/index.js.map +1 -1
- package/dist/node/index.cjs +3 -3
- package/dist/node/index.js +3 -3
- package/dist/rest/index.cjs +4 -5
- package/dist/rest/index.d.cts +3 -3
- package/dist/rest/index.d.ts +3 -3
- package/dist/rest/index.js +5 -5
- package/dist/shared/{events-BDdJyH2p.d.ts → events-BPxBF0gQ.d.cts} +3 -5
- package/dist/shared/{events-D6y0Hxyz.js → events-BzjI6pn5.js} +4 -4
- package/dist/shared/{events-D6y0Hxyz.js.map → events-BzjI6pn5.js.map} +1 -1
- package/dist/shared/{events-BqFkwwTw.cjs → events-C1FudmSe.cjs} +3 -9
- package/dist/shared/{events-BqFkwwTw.cjs.map → events-C1FudmSe.cjs.map} +1 -1
- package/dist/shared/{events-BQyH5-S0.d.cts → events-DnwfcLxS.d.ts} +3 -5
- package/dist/shared/{multi-storage-SoW05uzO.js → multi-storage-C3Ngtop1.js} +13 -8
- package/dist/shared/multi-storage-C3Ngtop1.js.map +1 -0
- package/dist/shared/{multi-storage-CDKLa956.cjs → multi-storage-s-fPtjoy.cjs} +13 -8
- package/dist/shared/multi-storage-s-fPtjoy.cjs.map +1 -0
- package/dist/shared/{options-DOJYtoti.cjs → options-DjEtbVaf.cjs} +2 -2
- package/dist/shared/{options-DOJYtoti.cjs.map → options-DjEtbVaf.cjs.map} +1 -1
- package/dist/shared/{options-DhgGg7Ms.js → options-i4LrKfqx.js} +2 -2
- package/dist/shared/{options-DhgGg7Ms.js.map → options-i4LrKfqx.js.map} +1 -1
- package/dist/shared/{redact-Ba5iSVYZ.js → redact-DJV0XM3n.js} +40 -15
- package/dist/shared/redact-DJV0XM3n.js.map +1 -0
- package/dist/shared/{redact-BP00URmQ.cjs → redact-lAmck1Z6.cjs} +45 -14
- package/dist/shared/redact-lAmck1Z6.cjs.map +1 -0
- package/dist/shared/{render-BU1_wex8.d.cts → render-C1F_QWYD.d.cts} +82 -19
- package/dist/shared/{render-sb1VJhUA.js → render-CtOpp9Pm.js} +127 -124
- package/dist/shared/render-CtOpp9Pm.js.map +1 -0
- package/dist/shared/{render-DAEeCMk9.cjs → render-Omy1drH1.cjs} +125 -128
- package/dist/shared/render-Omy1drH1.cjs.map +1 -0
- package/dist/shared/{render-CZ_-F2Tl.d.ts → render-uFW2kDxp.d.ts} +82 -19
- package/dist/shared/{storage-QNVxzpDB.cjs → storage-CZJZoaz9.cjs} +4 -2
- package/dist/shared/storage-CZJZoaz9.cjs.map +1 -0
- package/dist/shared/{storage-CfHKzVHf.js → storage-DiDe0PZM.js} +4 -2
- package/dist/shared/storage-DiDe0PZM.js.map +1 -0
- package/dist/shared/{url-Dsr4c5r5.js → url-3Ts6EEHQ.js} +301 -96
- package/dist/shared/url-3Ts6EEHQ.js.map +1 -0
- package/dist/shared/{url-CzHqE-Fg.cjs → url-D6wsXm1T.cjs} +301 -96
- package/dist/shared/url-D6wsXm1T.cjs.map +1 -0
- package/dist/shared/{url-CZZcyPI0.d.cts → url-DubjkRR9.d.cts} +10 -16
- package/dist/shared/{url-CZZcyPI0.d.ts → url-DubjkRR9.d.ts} +10 -16
- package/dist/web/index.cjs +1 -1
- package/dist/web/index.js +1 -1
- package/package.json +5 -5
- package/dist/shared/multi-storage-CDKLa956.cjs.map +0 -1
- package/dist/shared/multi-storage-SoW05uzO.js.map +0 -1
- package/dist/shared/redact-BP00URmQ.cjs.map +0 -1
- package/dist/shared/redact-Ba5iSVYZ.js.map +0 -1
- package/dist/shared/render-DAEeCMk9.cjs.map +0 -1
- package/dist/shared/render-sb1VJhUA.js.map +0 -1
- package/dist/shared/storage-CfHKzVHf.js.map +0 -1
- package/dist/shared/storage-QNVxzpDB.cjs.map +0 -1
- package/dist/shared/url-CzHqE-Fg.cjs.map +0 -1
- package/dist/shared/url-Dsr4c5r5.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { B as isRecord, C as ReportReason, E as SpanType, G as pickString, H as pickBoolean, J as identityResult, K as RetrySafety, M as defineBuiltInOperation, U as pickNumber, V as pickArray, W as pickObject, X as mergeService, Y as voidResult, c as normalizeNotification, ct as createDeadline, nt as STATUS_SERVICE, o as passthroughOperation, q as defineOperation, s as voidOperation, tt as DEFAULT_STATUS_BASE_URL, w as ReportTargetType, y as InteractionType } from "./url-
|
|
1
|
+
import { B as isRecord, C as ReportReason, E as SpanType, G as pickString, H as pickBoolean, J as identityResult, K as RetrySafety, M as defineBuiltInOperation, U as pickNumber, V as pickArray, W as pickObject, X as mergeService, Y as voidResult, c as normalizeNotification, ct as createDeadline, nt as STATUS_SERVICE, o as passthroughOperation, q as defineOperation, s as voidOperation, tt as DEFAULT_STATUS_BASE_URL, w as ReportTargetType, y as InteractionType } from "./url-3Ts6EEHQ.js";
|
|
2
2
|
import { _ as ItdStateError, a as ItdConfigError, b as isItdApiError, l as ItdFileError, s as ItdError, t as ItdAbortError, u as ItdFileErrorReason } from "./errors-GI10kZxk.js";
|
|
3
|
-
import { a as redactUrl, b as
|
|
4
|
-
import { a as fileTooLarge, c as FileTransferMode, i as isReadableByteStream, n as boundedFileStream, o as optionalBytes, r as isBoundedFileStream, s as DEFAULT_URL_FILE_MAX_BYTES, t as resolveFileStreamOptions } from "./options-
|
|
5
|
-
import { r as createKeyValueStore
|
|
3
|
+
import { a as redactUrl, b as isBlob, f as encodePathSegment, r as redactErrorCause, x as isFile, y as createDeviceId } from "./redact-DJV0XM3n.js";
|
|
4
|
+
import { a as fileTooLarge, c as FileTransferMode, i as isReadableByteStream, n as boundedFileStream, o as optionalBytes, r as isBoundedFileStream, s as DEFAULT_URL_FILE_MAX_BYTES, t as resolveFileStreamOptions } from "./options-i4LrKfqx.js";
|
|
5
|
+
import { r as createKeyValueStore } from "./key-value-store-Bt2PSMxY.js";
|
|
6
6
|
//#region src/core/feature-catalog.ts
|
|
7
7
|
/**
|
|
8
8
|
* Изменяемый слой над каталогом конкретного API.
|
|
@@ -370,6 +370,22 @@ function createFileResolver(fetchImplementation) {
|
|
|
370
370
|
}
|
|
371
371
|
//#endregion
|
|
372
372
|
//#region src/core/features.ts
|
|
373
|
+
var FeatureInstallationTransaction = class {
|
|
374
|
+
#cleanup = [];
|
|
375
|
+
add(cleanup) {
|
|
376
|
+
this.#cleanup.push(cleanup);
|
|
377
|
+
}
|
|
378
|
+
snapshot() {
|
|
379
|
+
return [...this.#cleanup];
|
|
380
|
+
}
|
|
381
|
+
rollback(reportError) {
|
|
382
|
+
for (let index = this.#cleanup.length - 1; index >= 0; index -= 1) try {
|
|
383
|
+
this.#cleanup[index]?.();
|
|
384
|
+
} catch (error) {
|
|
385
|
+
reportError(error);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
};
|
|
373
389
|
function requireName(value, kind) {
|
|
374
390
|
if (typeof value !== "string" || value.trim() === "") throw new ItdConfigError(`${kind} должен иметь непустое имя`);
|
|
375
391
|
return value.trim();
|
|
@@ -385,6 +401,21 @@ function validateBucket(owner, localName, bucket) {
|
|
|
385
401
|
if (bucket.concurrency !== void 0 && (!Number.isInteger(bucket.concurrency) || bucket.concurrency < 1)) throw new ItdConfigError(`feature «${owner}»: concurrency бакета «${localName}» должен быть целым числом от 1`);
|
|
386
402
|
if (bucket.rps !== void 0 && (!Number.isFinite(bucket.rps) || bucket.rps <= 0)) throw new ItdConfigError(`feature «${owner}»: rps бакета «${localName}» должен быть положительным числом`);
|
|
387
403
|
}
|
|
404
|
+
function validateFeatureDefinition(feature, isInstalled) {
|
|
405
|
+
if (typeof feature !== "object" || feature === null) throw new ItdConfigError("feature должен быть объектом");
|
|
406
|
+
const name = requireFeatureName(feature.name);
|
|
407
|
+
if (isInstalled(name)) throw new ItdConfigError(`feature «${name}» уже установлен`);
|
|
408
|
+
if (typeof feature.setup !== "function") throw new ItdConfigError(`feature «${name}» должен предоставлять setup()`);
|
|
409
|
+
if (typeof feature.operations !== "object" || feature.operations === null || Array.isArray(feature.operations)) throw new ItdConfigError(`feature «${name}» должен объявлять operations`);
|
|
410
|
+
if (feature.services !== void 0 && !Array.isArray(feature.services)) throw new ItdConfigError(`feature «${name}»: services должен быть массивом`);
|
|
411
|
+
if (feature.buckets !== void 0 && (typeof feature.buckets !== "object" || feature.buckets === null || Array.isArray(feature.buckets))) throw new ItdConfigError(`feature «${name}»: buckets должен быть объектом`);
|
|
412
|
+
return name;
|
|
413
|
+
}
|
|
414
|
+
function validateFeatureInstallation(name, installation) {
|
|
415
|
+
if (typeof installation !== "object" || installation === null || !("api" in installation)) throw new ItdConfigError(`setup() feature «${name}» должен вернуть объект с полем api`);
|
|
416
|
+
if (installation.close !== void 0 && typeof installation.close !== "function") throw new ItdConfigError(`feature «${name}»: close должен быть функцией`);
|
|
417
|
+
if (installation.dispose !== void 0 && typeof installation.dispose !== "function") throw new ItdConfigError(`feature «${name}»: dispose должен быть функцией`);
|
|
418
|
+
}
|
|
388
419
|
/** Реестр подключаемых модулей клиента. @internal */
|
|
389
420
|
var FeatureRegistry = class {
|
|
390
421
|
#deps;
|
|
@@ -394,20 +425,89 @@ var FeatureRegistry = class {
|
|
|
394
425
|
constructor(deps) {
|
|
395
426
|
this.#deps = deps;
|
|
396
427
|
}
|
|
397
|
-
|
|
398
|
-
this.#deps.assertActive("установить feature");
|
|
399
|
-
if (this.#disposed) throw new ItdStateError("Реестр feature уже освобождён");
|
|
400
|
-
if (typeof feature !== "object" || feature === null) throw new ItdConfigError("feature должен быть объектом");
|
|
401
|
-
const name = requireFeatureName(feature.name);
|
|
402
|
-
if (this.#features.has(name)) throw new ItdConfigError(`feature «${name}» уже установлен`);
|
|
403
|
-
if (typeof feature.setup !== "function") throw new ItdConfigError(`feature «${name}» должен предоставлять setup()`);
|
|
404
|
-
if (typeof feature.operations !== "object" || feature.operations === null || Array.isArray(feature.operations)) throw new ItdConfigError(`feature «${name}» должен объявлять operations`);
|
|
405
|
-
if (feature.services !== void 0 && !Array.isArray(feature.services)) throw new ItdConfigError(`feature «${name}»: services должен быть массивом`);
|
|
406
|
-
if (feature.buckets !== void 0 && (typeof feature.buckets !== "object" || feature.buckets === null || Array.isArray(feature.buckets))) throw new ItdConfigError(`feature «${name}»: buckets должен быть объектом`);
|
|
407
|
-
const rollback = [];
|
|
428
|
+
#registerServices(featureName, definitions, transaction) {
|
|
408
429
|
const services = /* @__PURE__ */ new Set();
|
|
430
|
+
for (const service of definitions) {
|
|
431
|
+
const serviceName = requireName(service?.name, `Сервис feature «${featureName}»`);
|
|
432
|
+
const owner = this.#serviceOwners.get(serviceName);
|
|
433
|
+
if (owner !== void 0) throw new ItdConfigError(`feature «${featureName}»: сервис «${serviceName}» уже принадлежит feature «${owner}»`);
|
|
434
|
+
if (services.has(serviceName)) throw new ItdConfigError(`feature «${featureName}»: сервис «${serviceName}» объявлен повторно`);
|
|
435
|
+
if (!this.#deps.services.has(serviceName)) {
|
|
436
|
+
this.#deps.services.define(service);
|
|
437
|
+
transaction.add(() => void this.#deps.services.delete(serviceName));
|
|
438
|
+
} else {
|
|
439
|
+
const override = this.#deps.serviceOverrides.find((candidate) => candidate.name.trim() === serviceName);
|
|
440
|
+
if (override) {
|
|
441
|
+
const previous = this.#deps.services.replace(mergeService(service, override));
|
|
442
|
+
transaction.add(() => void this.#deps.services.replace(previous));
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
this.#serviceOwners.set(serviceName, featureName);
|
|
446
|
+
transaction.add(() => {
|
|
447
|
+
if (this.#serviceOwners.get(serviceName) === featureName) this.#serviceOwners.delete(serviceName);
|
|
448
|
+
});
|
|
449
|
+
services.add(serviceName);
|
|
450
|
+
}
|
|
451
|
+
return services;
|
|
452
|
+
}
|
|
453
|
+
#registerBuckets(featureName, definitions, transaction) {
|
|
409
454
|
const bucketNames = /* @__PURE__ */ new Map();
|
|
455
|
+
for (const [rawLocalName, bucket] of Object.entries(definitions)) {
|
|
456
|
+
const localName = requireName(rawLocalName, `Бакет feature «${featureName}»`);
|
|
457
|
+
validateBucket(featureName, localName, bucket);
|
|
458
|
+
const globalName = `feature:${featureName}/${localName}`;
|
|
459
|
+
transaction.add(this.#deps.catalog.registerBucket(featureName, globalName, bucket));
|
|
460
|
+
const unregisterQueue = this.#deps.registerBucket(globalName, bucket);
|
|
461
|
+
if (unregisterQueue) transaction.add(unregisterQueue);
|
|
462
|
+
bucketNames.set(localName, globalName);
|
|
463
|
+
}
|
|
464
|
+
return bucketNames;
|
|
465
|
+
}
|
|
466
|
+
#registerOperations(featureName, definitions, services, bucketNames, transaction) {
|
|
410
467
|
const operations = /* @__PURE__ */ new Map();
|
|
468
|
+
for (const [rawLocalName, definition] of Object.entries(definitions)) {
|
|
469
|
+
const localName = requireName(rawLocalName, `Операция feature «${featureName}»`);
|
|
470
|
+
if (typeof definition !== "object" || definition === null) throw new ItdConfigError(`feature «${featureName}»: операция «${localName}» должна быть объектом`);
|
|
471
|
+
if (![
|
|
472
|
+
"GET",
|
|
473
|
+
"POST",
|
|
474
|
+
"PUT",
|
|
475
|
+
"PATCH",
|
|
476
|
+
"DELETE"
|
|
477
|
+
].includes(definition.method)) throw new ItdConfigError(`feature «${featureName}»: операция «${localName}» содержит неизвестный HTTP-метод`);
|
|
478
|
+
if (!Object.values(RetrySafety).includes(definition.retrySafety)) throw new ItdConfigError(`feature «${featureName}»: операция «${localName}» содержит неизвестную retrySafety`);
|
|
479
|
+
if (definition.service !== void 0 && typeof definition.service !== "string") throw new ItdConfigError(`feature «${featureName}»: service операции «${localName}» должен быть строкой`);
|
|
480
|
+
if (definition.bucket !== void 0 && typeof definition.bucket !== "string") throw new ItdConfigError(`feature «${featureName}»: bucket операции «${localName}» должен быть строкой`);
|
|
481
|
+
if (definition.read !== void 0 && typeof definition.read !== "function") throw new ItdConfigError(`feature «${featureName}»: read операции «${localName}» должна быть функцией`);
|
|
482
|
+
if (definition.annotations !== void 0 && (typeof definition.annotations !== "object" || definition.annotations === null || Array.isArray(definition.annotations))) throw new ItdConfigError(`feature «${featureName}»: annotations операции «${localName}» должны быть объектом`);
|
|
483
|
+
if (definition.service !== void 0 && !services.has(definition.service)) throw new ItdConfigError(`feature «${featureName}»: операция «${localName}» ссылается на необъявленный сервис «${definition.service}»`);
|
|
484
|
+
const bucket = definition.bucket === void 0 ? this.#deps.catalog.defaultBucket : bucketNames.get(definition.bucket);
|
|
485
|
+
if (bucket === void 0) throw new ItdConfigError(`feature «${featureName}»: операция «${localName}» ссылается на необъявленный бакет «${definition.bucket}»`);
|
|
486
|
+
const operationId = `${featureName}.${localName}`;
|
|
487
|
+
const contract = defineOperation(operationId, {
|
|
488
|
+
method: definition.method,
|
|
489
|
+
retrySafety: definition.retrySafety,
|
|
490
|
+
bucket,
|
|
491
|
+
...definition.annotations === void 0 ? {} : { annotations: definition.annotations }
|
|
492
|
+
}, definition.read ?? identityResult);
|
|
493
|
+
transaction.add(this.#deps.catalog.registerOperation(featureName, operationId, {
|
|
494
|
+
method: contract.method,
|
|
495
|
+
retrySafety: contract.retrySafety,
|
|
496
|
+
bucket,
|
|
497
|
+
...contract.annotations === void 0 ? {} : { annotations: contract.annotations }
|
|
498
|
+
}));
|
|
499
|
+
operations.set(localName, {
|
|
500
|
+
contract,
|
|
501
|
+
service: definition.service
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
return operations;
|
|
505
|
+
}
|
|
506
|
+
install(feature) {
|
|
507
|
+
this.#deps.assertActive("установить feature");
|
|
508
|
+
if (this.#disposed) throw new ItdStateError("Реестр feature уже освобождён");
|
|
509
|
+
const name = validateFeatureDefinition(feature, (candidate) => this.#features.has(candidate));
|
|
510
|
+
const transaction = new FeatureInstallationTransaction();
|
|
411
511
|
const controller = new AbortController();
|
|
412
512
|
let committed = false;
|
|
413
513
|
const reportRollbackError = (message, error) => {
|
|
@@ -416,74 +516,9 @@ var FeatureRegistry = class {
|
|
|
416
516
|
} catch {}
|
|
417
517
|
};
|
|
418
518
|
try {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if (owner !== void 0) throw new ItdConfigError(`feature «${name}»: сервис «${serviceName}» уже принадлежит feature «${owner}»`);
|
|
423
|
-
if (services.has(serviceName)) throw new ItdConfigError(`feature «${name}»: сервис «${serviceName}» объявлен повторно`);
|
|
424
|
-
if (!this.#deps.services.has(serviceName)) {
|
|
425
|
-
this.#deps.services.define(service);
|
|
426
|
-
rollback.push(() => void this.#deps.services.delete(serviceName));
|
|
427
|
-
} else {
|
|
428
|
-
const override = this.#deps.serviceOverrides.find((candidate) => candidate.name.trim() === serviceName);
|
|
429
|
-
if (override) {
|
|
430
|
-
const previous = this.#deps.services.replace(mergeService(service, override));
|
|
431
|
-
rollback.push(() => void this.#deps.services.replace(previous));
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
this.#serviceOwners.set(serviceName, name);
|
|
435
|
-
rollback.push(() => {
|
|
436
|
-
if (this.#serviceOwners.get(serviceName) === name) this.#serviceOwners.delete(serviceName);
|
|
437
|
-
});
|
|
438
|
-
services.add(serviceName);
|
|
439
|
-
}
|
|
440
|
-
for (const [rawLocalName, bucket] of Object.entries(feature.buckets ?? {})) {
|
|
441
|
-
const localName = requireName(rawLocalName, `Бакет feature «${name}»`);
|
|
442
|
-
validateBucket(name, localName, bucket);
|
|
443
|
-
const globalName = `feature:${name}/${localName}`;
|
|
444
|
-
const unregisterCatalog = this.#deps.catalog.registerBucket(name, globalName, bucket);
|
|
445
|
-
rollback.push(unregisterCatalog);
|
|
446
|
-
const unregisterQueue = this.#deps.registerBucket(globalName, bucket);
|
|
447
|
-
if (unregisterQueue) rollback.push(unregisterQueue);
|
|
448
|
-
bucketNames.set(localName, globalName);
|
|
449
|
-
}
|
|
450
|
-
for (const [rawLocalName, definition] of Object.entries(feature.operations)) {
|
|
451
|
-
const localName = requireName(rawLocalName, `Операция feature «${name}»`);
|
|
452
|
-
if (typeof definition !== "object" || definition === null) throw new ItdConfigError(`feature «${name}»: операция «${localName}» должна быть объектом`);
|
|
453
|
-
if (![
|
|
454
|
-
"GET",
|
|
455
|
-
"POST",
|
|
456
|
-
"PUT",
|
|
457
|
-
"PATCH",
|
|
458
|
-
"DELETE"
|
|
459
|
-
].includes(definition.method)) throw new ItdConfigError(`feature «${name}»: операция «${localName}» содержит неизвестный HTTP-метод`);
|
|
460
|
-
if (!Object.values(RetrySafety).includes(definition.retrySafety)) throw new ItdConfigError(`feature «${name}»: операция «${localName}» содержит неизвестную retrySafety`);
|
|
461
|
-
if (definition.service !== void 0 && typeof definition.service !== "string") throw new ItdConfigError(`feature «${name}»: service операции «${localName}» должен быть строкой`);
|
|
462
|
-
if (definition.bucket !== void 0 && typeof definition.bucket !== "string") throw new ItdConfigError(`feature «${name}»: bucket операции «${localName}» должен быть строкой`);
|
|
463
|
-
if (definition.read !== void 0 && typeof definition.read !== "function") throw new ItdConfigError(`feature «${name}»: read операции «${localName}» должна быть функцией`);
|
|
464
|
-
if (definition.annotations !== void 0 && (typeof definition.annotations !== "object" || definition.annotations === null || Array.isArray(definition.annotations))) throw new ItdConfigError(`feature «${name}»: annotations операции «${localName}» должны быть объектом`);
|
|
465
|
-
if (definition.service !== void 0 && !services.has(definition.service)) throw new ItdConfigError(`feature «${name}»: операция «${localName}» ссылается на необъявленный сервис «${definition.service}»`);
|
|
466
|
-
const bucket = definition.bucket === void 0 ? this.#deps.catalog.defaultBucket : bucketNames.get(definition.bucket);
|
|
467
|
-
if (bucket === void 0) throw new ItdConfigError(`feature «${name}»: операция «${localName}» ссылается на необъявленный бакет «${definition.bucket}»`);
|
|
468
|
-
const operationId = `${name}.${localName}`;
|
|
469
|
-
const contract = defineOperation(operationId, {
|
|
470
|
-
method: definition.method,
|
|
471
|
-
retrySafety: definition.retrySafety,
|
|
472
|
-
bucket,
|
|
473
|
-
...definition.annotations === void 0 ? {} : { annotations: definition.annotations }
|
|
474
|
-
}, definition.read ?? identityResult);
|
|
475
|
-
const unregister = this.#deps.catalog.registerOperation(name, operationId, {
|
|
476
|
-
method: contract.method,
|
|
477
|
-
retrySafety: contract.retrySafety,
|
|
478
|
-
bucket,
|
|
479
|
-
...contract.annotations === void 0 ? {} : { annotations: contract.annotations }
|
|
480
|
-
});
|
|
481
|
-
rollback.push(unregister);
|
|
482
|
-
operations.set(localName, {
|
|
483
|
-
contract,
|
|
484
|
-
service: definition.service
|
|
485
|
-
});
|
|
486
|
-
}
|
|
519
|
+
const services = this.#registerServices(name, feature.services ?? [], transaction);
|
|
520
|
+
const bucketNames = this.#registerBuckets(name, feature.buckets ?? {}, transaction);
|
|
521
|
+
const operations = this.#registerOperations(name, feature.operations, services, bucketNames, transaction);
|
|
487
522
|
const context = Object.freeze({
|
|
488
523
|
featureName: name,
|
|
489
524
|
baseUrl: this.#deps.baseUrl,
|
|
@@ -538,7 +573,7 @@ var FeatureRegistry = class {
|
|
|
538
573
|
registered = false;
|
|
539
574
|
unregister();
|
|
540
575
|
};
|
|
541
|
-
if (!committed)
|
|
576
|
+
if (!committed) transaction.add(() => {
|
|
542
577
|
if (!registered) return;
|
|
543
578
|
if (committed) {
|
|
544
579
|
release();
|
|
@@ -563,21 +598,21 @@ var FeatureRegistry = class {
|
|
|
563
598
|
}
|
|
564
599
|
});
|
|
565
600
|
const installation = feature.setup(context);
|
|
566
|
-
|
|
567
|
-
if (installation.close !== void 0 && typeof installation.close !== "function") throw new ItdConfigError(`feature «${name}»: close должен быть функцией`);
|
|
568
|
-
if (installation.dispose !== void 0 && typeof installation.dispose !== "function") throw new ItdConfigError(`feature «${name}»: dispose должен быть функцией`);
|
|
601
|
+
validateFeatureInstallation(name, installation);
|
|
569
602
|
this.#features.set(name, {
|
|
570
603
|
name,
|
|
571
604
|
controller,
|
|
572
605
|
close: installation.close,
|
|
573
606
|
dispose: installation.dispose,
|
|
574
|
-
cleanup:
|
|
607
|
+
cleanup: transaction.snapshot()
|
|
575
608
|
});
|
|
576
609
|
committed = true;
|
|
577
610
|
return installation.api;
|
|
578
611
|
} catch (error) {
|
|
579
612
|
controller.abort(new ItdAbortError(`Установка feature «${name}» отменена`));
|
|
580
|
-
|
|
613
|
+
transaction.rollback((rollbackError) => {
|
|
614
|
+
reportRollbackError(`Не удалось полностью откатить feature «${name}»`, rollbackError);
|
|
615
|
+
});
|
|
581
616
|
throw error;
|
|
582
617
|
}
|
|
583
618
|
}
|
|
@@ -1819,7 +1854,6 @@ var FilesResource = class extends BaseResource {
|
|
|
1819
1854
|
//#endregion
|
|
1820
1855
|
//#region src/resources/hashtags.ts
|
|
1821
1856
|
const HASHTAG_POSTS = pageOperation("hashtags.posts", (body) => readCursorPage(body, "posts"));
|
|
1822
|
-
const HASHTAGS_SEARCH = defineBuiltInOperation("hashtags.search", (body) => pickArray(body, "hashtags"));
|
|
1823
1857
|
const HASHTAGS_TRENDING = defineBuiltInOperation("hashtags.trending", (body) => pickArray(body, "hashtags"));
|
|
1824
1858
|
/**
|
|
1825
1859
|
* Хэштеги.
|
|
@@ -1835,21 +1869,6 @@ var HashtagsResource = class extends BaseResource {
|
|
|
1835
1869
|
start: (p) => p.cursor ? { cursor: p.cursor } : {},
|
|
1836
1870
|
mode: PaginationMode.Cursor
|
|
1837
1871
|
});
|
|
1838
|
-
/**
|
|
1839
|
-
* Ищет хэштеги.
|
|
1840
|
-
*
|
|
1841
|
-
* Без строки запроса возвращает общий список.
|
|
1842
|
-
*/
|
|
1843
|
-
search(query, params = {}, options = {}) {
|
|
1844
|
-
return this.http.execute(HASHTAGS_SEARCH, {
|
|
1845
|
-
path: "/api/hashtags",
|
|
1846
|
-
query: {
|
|
1847
|
-
q: query,
|
|
1848
|
-
limit: params.limit
|
|
1849
|
-
},
|
|
1850
|
-
...options
|
|
1851
|
-
});
|
|
1852
|
-
}
|
|
1853
1872
|
/** Загружает трендовые хэштеги. */
|
|
1854
1873
|
trending(params = {}, options = {}) {
|
|
1855
1874
|
return this.http.execute(HASHTAGS_TRENDING, {
|
|
@@ -4121,7 +4140,6 @@ const USER_LIST_OPERATIONS = {
|
|
|
4121
4140
|
"users.blocked": userListOperation("users.blocked")
|
|
4122
4141
|
};
|
|
4123
4142
|
const USERS_CHECK_USERNAME = defineBuiltInOperation("users.checkUsername", (body) => pickBoolean(body, "available"));
|
|
4124
|
-
const USERS_SEARCH = defineBuiltInOperation("users.search", (body) => pickArray(body, "users"));
|
|
4125
4143
|
const USERS_WHO_TO_FOLLOW = defineBuiltInOperation("users.whoToFollow", (body) => pickArray(body, "users"));
|
|
4126
4144
|
const USERS_TOP_CLANS = defineBuiltInOperation("users.topClans", (body) => pickArray(body, "clans"));
|
|
4127
4145
|
const USERS_PINS = defineBuiltInOperation("users.pins", (body) => ({
|
|
@@ -4250,17 +4268,6 @@ var UsersResource = class extends BaseResource {
|
|
|
4250
4268
|
...options
|
|
4251
4269
|
});
|
|
4252
4270
|
}
|
|
4253
|
-
/** Ищет пользователей по строке запроса. */
|
|
4254
|
-
search(query, params = {}, options = {}) {
|
|
4255
|
-
return this.http.execute(USERS_SEARCH, {
|
|
4256
|
-
path: "/api/users/search",
|
|
4257
|
-
query: {
|
|
4258
|
-
q: query,
|
|
4259
|
-
limit: params.limit
|
|
4260
|
-
},
|
|
4261
|
-
...options
|
|
4262
|
-
});
|
|
4263
|
-
}
|
|
4264
4271
|
/** Загружает рекомендации, на кого подписаться. */
|
|
4265
4272
|
whoToFollow(options = {}) {
|
|
4266
4273
|
return this.http.execute(USERS_WHO_TO_FOLLOW, {
|
|
@@ -4684,10 +4691,6 @@ function createShopOrderAccessStorage(store, options = {}) {
|
|
|
4684
4691
|
clear: () => backend.delete(key)
|
|
4685
4692
|
};
|
|
4686
4693
|
}
|
|
4687
|
-
/** Создаёт независимое хранилище доступа к заказам в памяти. */
|
|
4688
|
-
function createMemoryShopOrderAccessStorage() {
|
|
4689
|
-
return createShopOrderAccessStorage(new MemoryKeyValueStore());
|
|
4690
|
-
}
|
|
4691
4694
|
//#endregion
|
|
4692
4695
|
//#region src/shop/feature.ts
|
|
4693
4696
|
const Operation = Object.freeze({
|
|
@@ -4742,7 +4745,7 @@ function createShopFeature(options = {}) {
|
|
|
4742
4745
|
}
|
|
4743
4746
|
},
|
|
4744
4747
|
setup(context) {
|
|
4745
|
-
const storage = options.storage ??
|
|
4748
|
+
const storage = options.storage ?? new MemoryShopOrderAccessStorage();
|
|
4746
4749
|
let pendingEmail = null;
|
|
4747
4750
|
const readSession = async () => {
|
|
4748
4751
|
const session = await storage.get();
|
|
@@ -5032,6 +5035,6 @@ function renderSpans(content, spans = [], options = {}) {
|
|
|
5032
5035
|
return result;
|
|
5033
5036
|
}
|
|
5034
5037
|
//#endregion
|
|
5035
|
-
export {
|
|
5038
|
+
export { utcStampToIso as A, AUDIO_MIME_TYPES as C, isBuilder as D, comment as E, mapPage as F, createFeatureHost as I, ExtensibleOperationCatalog as L, BaseResource as M, PaginationMode as N, createStatusFeature as O, Paginator as P, ALLOWED_MIME_TYPES as S, VIDEO_MIME_TYPES as T, poll as _, createShopOrderAccessStorage as a, parseHtml as b, ShopOrderStatus as c, isMyProfile as d, fromStream as f, post as g, report as h, MemoryShopOrderAccessStorage as i, NotificationsResource as j, toDate as k, ShopProductCategory as l, createResources as m, renderSpans as n, statusDays as o, fromUrl as p, createShopFeature as r, ShopConsentKind as s, SpanRenderFormat as t, ShopProductStatus as u, autoSpans as v, IMAGE_MIME_TYPES as w, parseMarkdown as x, markup as y };
|
|
5036
5039
|
|
|
5037
|
-
//# sourceMappingURL=render-
|
|
5040
|
+
//# sourceMappingURL=render-CtOpp9Pm.js.map
|