@adobe-commerce/aio-toolkit 1.1.1 → 1.2.1
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/CHANGELOG.md +94 -0
- package/README.md +280 -4
- package/dist/index.d.mts +90 -1
- package/dist/index.d.ts +90 -1
- package/dist/index.js +676 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +672 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -31,6 +31,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
// src/index.ts
|
|
32
32
|
var index_exports = {};
|
|
33
33
|
__export(index_exports, {
|
|
34
|
+
AbdbCollection: () => collection_default,
|
|
35
|
+
AbdbColumn: () => column_default,
|
|
36
|
+
AbdbColumnType: () => AbdbColumnType,
|
|
37
|
+
AbdbRepository: () => abdb_repository_default,
|
|
34
38
|
AdminUiSdk: () => AdminUiSdk,
|
|
35
39
|
AdobeAuth: () => adobe_auth_default,
|
|
36
40
|
AdobeCommerceClient: () => adobe_commerce_client_default,
|
|
@@ -2391,6 +2395,674 @@ __name(_FileRepository, "FileRepository");
|
|
|
2391
2395
|
var FileRepository = _FileRepository;
|
|
2392
2396
|
var file_repository_default = FileRepository;
|
|
2393
2397
|
|
|
2398
|
+
// src/framework/abdb/collection/index.ts
|
|
2399
|
+
var import_aio_lib_db = require("@adobe/aio-lib-db");
|
|
2400
|
+
|
|
2401
|
+
// src/framework/abdb/column/types.ts
|
|
2402
|
+
var AbdbColumnType = /* @__PURE__ */ ((AbdbColumnType2) => {
|
|
2403
|
+
AbdbColumnType2["STRING"] = "STRING";
|
|
2404
|
+
AbdbColumnType2["NUMBER"] = "NUMBER";
|
|
2405
|
+
AbdbColumnType2["BOOLEAN"] = "BOOLEAN";
|
|
2406
|
+
AbdbColumnType2["DATETIME"] = "DATETIME";
|
|
2407
|
+
return AbdbColumnType2;
|
|
2408
|
+
})(AbdbColumnType || {});
|
|
2409
|
+
|
|
2410
|
+
// src/framework/abdb/column/index.ts
|
|
2411
|
+
var ISO_8601_DATETIME = /^\d{4}-\d{2}-\d{2}([Tt ]\d{2}:\d{2}(:\d{2}(\.\d{1,9})?)?(Z|[+-]\d{2}(:?\d{2})?)?)?$/;
|
|
2412
|
+
var _AbdbColumn = class _AbdbColumn {
|
|
2413
|
+
/**
|
|
2414
|
+
* @param options - Field definition
|
|
2415
|
+
* @throws {Error} When `name` is missing or blank, or `type` is missing / not a member of {@link AbdbColumnType}
|
|
2416
|
+
*/
|
|
2417
|
+
constructor(options) {
|
|
2418
|
+
if (!options?.name?.trim()) {
|
|
2419
|
+
throw new Error('AbdbColumn: "name" is required and cannot be empty');
|
|
2420
|
+
}
|
|
2421
|
+
if (!options.type || !Object.values(AbdbColumnType).includes(options.type)) {
|
|
2422
|
+
throw new Error('AbdbColumn: "type" is required');
|
|
2423
|
+
}
|
|
2424
|
+
this._name = options.name.trim();
|
|
2425
|
+
this._type = options.type;
|
|
2426
|
+
this._description = void 0;
|
|
2427
|
+
this._isRequired = options.isRequired ?? false;
|
|
2428
|
+
if (options.description !== void 0) {
|
|
2429
|
+
const trimmed = options.description.trim();
|
|
2430
|
+
if (trimmed.length > 0) {
|
|
2431
|
+
this._description = trimmed;
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
Object.freeze(this);
|
|
2435
|
+
}
|
|
2436
|
+
/**
|
|
2437
|
+
* Returns the trimmed field name.
|
|
2438
|
+
*/
|
|
2439
|
+
getName() {
|
|
2440
|
+
return this._name;
|
|
2441
|
+
}
|
|
2442
|
+
/**
|
|
2443
|
+
* Returns the expected value type for this column.
|
|
2444
|
+
*/
|
|
2445
|
+
getType() {
|
|
2446
|
+
return this._type;
|
|
2447
|
+
}
|
|
2448
|
+
/**
|
|
2449
|
+
* Returns the optional description, if one was provided and non-whitespace.
|
|
2450
|
+
*
|
|
2451
|
+
* @returns Description string, or `undefined` when not set
|
|
2452
|
+
*/
|
|
2453
|
+
getDescription() {
|
|
2454
|
+
return this._description;
|
|
2455
|
+
}
|
|
2456
|
+
/**
|
|
2457
|
+
* Returns whether a value is mandatory for {@link AbdbColumn#validate}.
|
|
2458
|
+
*
|
|
2459
|
+
* @returns `true` if constructed with `isRequired: true`; otherwise `false`
|
|
2460
|
+
*/
|
|
2461
|
+
getIsRequired() {
|
|
2462
|
+
return this._isRequired;
|
|
2463
|
+
}
|
|
2464
|
+
/**
|
|
2465
|
+
* Serializes this column to a plain object for JSON (config files, APIs, persistence).
|
|
2466
|
+
*/
|
|
2467
|
+
toJSON() {
|
|
2468
|
+
const json = {
|
|
2469
|
+
name: this._name,
|
|
2470
|
+
type: this._type
|
|
2471
|
+
};
|
|
2472
|
+
if (this._description !== void 0) {
|
|
2473
|
+
json.description = this._description;
|
|
2474
|
+
}
|
|
2475
|
+
if (this._isRequired) {
|
|
2476
|
+
json.isRequired = true;
|
|
2477
|
+
}
|
|
2478
|
+
return json;
|
|
2479
|
+
}
|
|
2480
|
+
/**
|
|
2481
|
+
* Creates a new column with the same or overridden options. Does not mutate this instance.
|
|
2482
|
+
*
|
|
2483
|
+
* Passing `description: ' '` (blank / whitespace) clears the description on the new column.
|
|
2484
|
+
*
|
|
2485
|
+
* @param overrides - Partial options; omitted keys keep current values
|
|
2486
|
+
* @returns A new {@link AbdbColumn} instance
|
|
2487
|
+
*/
|
|
2488
|
+
clone(overrides = {}) {
|
|
2489
|
+
const name = overrides.name ?? this._name;
|
|
2490
|
+
const type = overrides.type ?? this._type;
|
|
2491
|
+
const isRequired = overrides.isRequired ?? this._isRequired;
|
|
2492
|
+
if (overrides.description !== void 0) {
|
|
2493
|
+
return new _AbdbColumn({ name, type, description: overrides.description, isRequired });
|
|
2494
|
+
}
|
|
2495
|
+
if (this._description !== void 0) {
|
|
2496
|
+
return new _AbdbColumn({ name, type, description: this._description, isRequired });
|
|
2497
|
+
}
|
|
2498
|
+
return new _AbdbColumn({ name, type, isRequired });
|
|
2499
|
+
}
|
|
2500
|
+
/**
|
|
2501
|
+
* Validates a payload value against this column's requiredness and {@link AbdbColumnType}.
|
|
2502
|
+
*
|
|
2503
|
+
* **Missing values** (`undefined`, `null`, or empty / whitespace-only strings) are handled first:
|
|
2504
|
+
* if `isRequired` is `false`, validation succeeds; if `true`, throws.
|
|
2505
|
+
*
|
|
2506
|
+
* **Type rules** (when a non-missing value is present):
|
|
2507
|
+
* - `STRING`: primitive string
|
|
2508
|
+
* - `NUMBER`: finite number, or a non-empty string whose trim parses to a finite number via `Number`
|
|
2509
|
+
* - `BOOLEAN`: primitive boolean, or non-empty trimmed string `"true"` / `"false"` (case-insensitive)
|
|
2510
|
+
* - `DATETIME`: valid `Date`, finite numeric timestamp (ms), or non-empty trimmed ISO 8601 date/datetime string
|
|
2511
|
+
*
|
|
2512
|
+
* @param value - Document field or API payload value
|
|
2513
|
+
* @throws {Error} When required and missing, or when the value does not match the column type
|
|
2514
|
+
*/
|
|
2515
|
+
validate(value) {
|
|
2516
|
+
if (this._isMissingValue(value)) {
|
|
2517
|
+
if (this._isRequired) {
|
|
2518
|
+
throw new Error(`AbdbColumn: "${this._name}" is required`);
|
|
2519
|
+
}
|
|
2520
|
+
return;
|
|
2521
|
+
}
|
|
2522
|
+
switch (this._type) {
|
|
2523
|
+
case "STRING" /* STRING */:
|
|
2524
|
+
this._validateStringValue(value);
|
|
2525
|
+
return;
|
|
2526
|
+
case "NUMBER" /* NUMBER */:
|
|
2527
|
+
this._validateNumberValue(value);
|
|
2528
|
+
return;
|
|
2529
|
+
case "BOOLEAN" /* BOOLEAN */:
|
|
2530
|
+
this._validateBooleanValue(value);
|
|
2531
|
+
return;
|
|
2532
|
+
case "DATETIME" /* DATETIME */:
|
|
2533
|
+
this._validateDateTimeValue(value);
|
|
2534
|
+
return;
|
|
2535
|
+
default: {
|
|
2536
|
+
const _unreachable = this._type;
|
|
2537
|
+
throw new Error(`AbdbColumn: unhandled type "${_unreachable}"`);
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
/**
|
|
2542
|
+
* Whether `value` counts as absent for requiredness checks (before type validation).
|
|
2543
|
+
*
|
|
2544
|
+
* @returns `true` for `undefined`, `null`, or a string that is empty after trim
|
|
2545
|
+
*/
|
|
2546
|
+
_isMissingValue(value) {
|
|
2547
|
+
if (value === void 0 || value === null) {
|
|
2548
|
+
return true;
|
|
2549
|
+
}
|
|
2550
|
+
return typeof value === "string" && value.trim() === "";
|
|
2551
|
+
}
|
|
2552
|
+
/**
|
|
2553
|
+
* @throws {Error} When `value` is not a primitive string
|
|
2554
|
+
*/
|
|
2555
|
+
_validateStringValue(value) {
|
|
2556
|
+
if (typeof value !== "string") {
|
|
2557
|
+
throw new Error(`AbdbColumn: "${this._name}" expects string, got ${typeof value}`);
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
/**
|
|
2561
|
+
* @throws {Error} When not a finite number or numeric string
|
|
2562
|
+
*/
|
|
2563
|
+
_validateNumberValue(value) {
|
|
2564
|
+
if (typeof value === "number") {
|
|
2565
|
+
if (Number.isFinite(value)) {
|
|
2566
|
+
return;
|
|
2567
|
+
}
|
|
2568
|
+
throw new Error(`AbdbColumn: "${this._name}" expects a finite number, got ${String(value)}`);
|
|
2569
|
+
}
|
|
2570
|
+
if (typeof value === "string") {
|
|
2571
|
+
const trimmed = value.trim();
|
|
2572
|
+
const n = Number(trimmed);
|
|
2573
|
+
if (Number.isFinite(n)) {
|
|
2574
|
+
return;
|
|
2575
|
+
}
|
|
2576
|
+
throw new Error(
|
|
2577
|
+
`AbdbColumn: "${this._name}" expects a finite number or numeric string, got ${JSON.stringify(value)}`
|
|
2578
|
+
);
|
|
2579
|
+
}
|
|
2580
|
+
throw new Error(
|
|
2581
|
+
`AbdbColumn: "${this._name}" expects a finite number or numeric string, got ${typeof value}`
|
|
2582
|
+
);
|
|
2583
|
+
}
|
|
2584
|
+
/**
|
|
2585
|
+
* @throws {Error} When not a boolean or `"true"` / `"false"` string
|
|
2586
|
+
*/
|
|
2587
|
+
_validateBooleanValue(value) {
|
|
2588
|
+
if (typeof value === "boolean") {
|
|
2589
|
+
return;
|
|
2590
|
+
}
|
|
2591
|
+
if (typeof value === "string") {
|
|
2592
|
+
const t = value.trim().toLowerCase();
|
|
2593
|
+
if (t === "true" || t === "false") {
|
|
2594
|
+
return;
|
|
2595
|
+
}
|
|
2596
|
+
throw new Error(
|
|
2597
|
+
`AbdbColumn: "${this._name}" expects boolean or "true"/"false" string, got ${JSON.stringify(value)}`
|
|
2598
|
+
);
|
|
2599
|
+
}
|
|
2600
|
+
throw new Error(
|
|
2601
|
+
`AbdbColumn: "${this._name}" expects boolean or "true"/"false" string, got ${typeof value}`
|
|
2602
|
+
);
|
|
2603
|
+
}
|
|
2604
|
+
/**
|
|
2605
|
+
* @throws {Error} When not a valid `Date`, finite timestamp, or ISO 8601 string
|
|
2606
|
+
*/
|
|
2607
|
+
_validateDateTimeValue(value) {
|
|
2608
|
+
if (value instanceof Date) {
|
|
2609
|
+
if (!Number.isNaN(value.getTime())) {
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
throw new Error(`AbdbColumn: "${this._name}" expects a valid Date`);
|
|
2613
|
+
}
|
|
2614
|
+
if (typeof value === "number") {
|
|
2615
|
+
if (Number.isFinite(value)) {
|
|
2616
|
+
return;
|
|
2617
|
+
}
|
|
2618
|
+
throw new Error(
|
|
2619
|
+
`AbdbColumn: "${this._name}" expects a finite numeric timestamp, got ${value}`
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2622
|
+
if (typeof value === "string") {
|
|
2623
|
+
const s = value.trim();
|
|
2624
|
+
if (!ISO_8601_DATETIME.test(s)) {
|
|
2625
|
+
throw new Error(
|
|
2626
|
+
`AbdbColumn: "${this._name}" expects ISO 8601 datetime string, got ${JSON.stringify(value)}`
|
|
2627
|
+
);
|
|
2628
|
+
}
|
|
2629
|
+
const t = Date.parse(s);
|
|
2630
|
+
if (Number.isNaN(t)) {
|
|
2631
|
+
throw new Error(
|
|
2632
|
+
`AbdbColumn: "${this._name}" expects ISO 8601 datetime string, got ${JSON.stringify(value)}`
|
|
2633
|
+
);
|
|
2634
|
+
}
|
|
2635
|
+
return;
|
|
2636
|
+
}
|
|
2637
|
+
throw new Error(
|
|
2638
|
+
`AbdbColumn: "${this._name}" expects Date, finite numeric timestamp, or ISO 8601 datetime string, got ${typeof value}`
|
|
2639
|
+
);
|
|
2640
|
+
}
|
|
2641
|
+
};
|
|
2642
|
+
__name(_AbdbColumn, "AbdbColumn");
|
|
2643
|
+
var AbdbColumn = _AbdbColumn;
|
|
2644
|
+
var column_default = AbdbColumn;
|
|
2645
|
+
|
|
2646
|
+
// src/framework/abdb/collection/index.ts
|
|
2647
|
+
var _AbdbCollection = class _AbdbCollection {
|
|
2648
|
+
/**
|
|
2649
|
+
* Creates a collection and optionally configures it in a callback (e.g. chained {@link addColumn} calls).
|
|
2650
|
+
*
|
|
2651
|
+
* @param name - Raw collection name; trimmed and validated
|
|
2652
|
+
* @param callback - Optional function invoked with `this` for fluent setup
|
|
2653
|
+
* @throws {Error} When `name` is empty, whitespace-only, or contains invalid characters
|
|
2654
|
+
*/
|
|
2655
|
+
constructor(name, callback) {
|
|
2656
|
+
this._name = this._validateCollectionName(name);
|
|
2657
|
+
this._columns = /* @__PURE__ */ new Map();
|
|
2658
|
+
if (callback) {
|
|
2659
|
+
callback(this);
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
/**
|
|
2663
|
+
* Returns this collection's name.
|
|
2664
|
+
*/
|
|
2665
|
+
getName() {
|
|
2666
|
+
return this._name;
|
|
2667
|
+
}
|
|
2668
|
+
addColumn(name, type, descriptionOrOptions, isRequired) {
|
|
2669
|
+
const trimmed = this._validateColumnName(name);
|
|
2670
|
+
if (this._columns.has(trimmed)) {
|
|
2671
|
+
throw new Error(`AbdbCollection: duplicate column name "${trimmed}"`);
|
|
2672
|
+
}
|
|
2673
|
+
const columnOptions = { name: trimmed, type };
|
|
2674
|
+
if (typeof descriptionOrOptions === "string") {
|
|
2675
|
+
columnOptions.description = descriptionOrOptions;
|
|
2676
|
+
if (isRequired !== void 0) {
|
|
2677
|
+
columnOptions.isRequired = isRequired;
|
|
2678
|
+
}
|
|
2679
|
+
} else if (descriptionOrOptions !== void 0) {
|
|
2680
|
+
if (descriptionOrOptions.description !== void 0) {
|
|
2681
|
+
columnOptions.description = descriptionOrOptions.description;
|
|
2682
|
+
}
|
|
2683
|
+
if (descriptionOrOptions.isRequired !== void 0) {
|
|
2684
|
+
columnOptions.isRequired = descriptionOrOptions.isRequired;
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
this._columns.set(trimmed, new column_default(columnOptions));
|
|
2688
|
+
return this;
|
|
2689
|
+
}
|
|
2690
|
+
/**
|
|
2691
|
+
* Returns a defensive copy of columns in insertion order.
|
|
2692
|
+
*/
|
|
2693
|
+
getColumns() {
|
|
2694
|
+
return Array.from(this._columns.values());
|
|
2695
|
+
}
|
|
2696
|
+
/**
|
|
2697
|
+
* Returns the column registered under `name`, or `undefined` if no such column exists.
|
|
2698
|
+
*
|
|
2699
|
+
* @param name - Column name to look up (exact match after trimming)
|
|
2700
|
+
* @returns The {@link AbdbColumn} instance, or `undefined`
|
|
2701
|
+
*/
|
|
2702
|
+
getColumn(name) {
|
|
2703
|
+
return this._columns.get(name.trim());
|
|
2704
|
+
}
|
|
2705
|
+
/**
|
|
2706
|
+
* Returns `true` when a column with the given name has been registered.
|
|
2707
|
+
*
|
|
2708
|
+
* @param name - Column name to check (exact match after trimming)
|
|
2709
|
+
*/
|
|
2710
|
+
hasColumn(name) {
|
|
2711
|
+
return this._columns.has(name.trim());
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* Validates a document-style object against this collection's columns. Throws on the **first** failing
|
|
2715
|
+
* column. Use {@link validateAll} when you need all errors reported at once.
|
|
2716
|
+
*
|
|
2717
|
+
* Missing keys are read as `undefined`, so a **required** column whose key is absent fails validation.
|
|
2718
|
+
* Extra keys not matching any column name are ignored.
|
|
2719
|
+
*
|
|
2720
|
+
* @param record - Key/value payload whose keys are column names
|
|
2721
|
+
* @throws {Error} When any column validation fails (requiredness or type)
|
|
2722
|
+
*/
|
|
2723
|
+
validate(record) {
|
|
2724
|
+
for (const col of this._columns.values()) {
|
|
2725
|
+
col.validate(record[col.getName()]);
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
/**
|
|
2729
|
+
* Validates a document-style object against **all** columns and collects every error instead of
|
|
2730
|
+
* stopping at the first failure. Useful at API boundaries where reporting all problems at once
|
|
2731
|
+
* gives a better developer or end-user experience.
|
|
2732
|
+
*
|
|
2733
|
+
* Returns an empty array when the record is fully valid.
|
|
2734
|
+
*
|
|
2735
|
+
* @param record - Key/value payload whose keys are column names
|
|
2736
|
+
* @returns Array of validation error messages, one per failing column (insertion order)
|
|
2737
|
+
*
|
|
2738
|
+
* @example
|
|
2739
|
+
* ```typescript
|
|
2740
|
+
* const errors = orders.validateAll(payload);
|
|
2741
|
+
* if (errors.length > 0) {
|
|
2742
|
+
* return { status: 400, body: { errors } };
|
|
2743
|
+
* }
|
|
2744
|
+
* ```
|
|
2745
|
+
*/
|
|
2746
|
+
validateAll(record) {
|
|
2747
|
+
const errors = [];
|
|
2748
|
+
for (const col of this._columns.values()) {
|
|
2749
|
+
try {
|
|
2750
|
+
col.validate(record[col.getName()]);
|
|
2751
|
+
} catch (e) {
|
|
2752
|
+
errors.push(e instanceof Error ? e.message : String(e));
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
return errors;
|
|
2756
|
+
}
|
|
2757
|
+
/**
|
|
2758
|
+
* Connects to the database (via `@adobe/aio-lib-db`), runs `callback` with the selected DB **collection**
|
|
2759
|
+
* handle and the **client**, then closes the client in a `finally` block.
|
|
2760
|
+
*
|
|
2761
|
+
* **Errors:** `DbError` instances are rethrown as `AbdbCollection: database error: …`;
|
|
2762
|
+
* any other value is wrapped as `AbdbCollection: unexpected error: …`.
|
|
2763
|
+
*
|
|
2764
|
+
* @param callback - Receives `(collection, client)` after connect
|
|
2765
|
+
* @param token - IMS access token for `initDb`
|
|
2766
|
+
* @param region - Data region (default: `'amer'`)
|
|
2767
|
+
* @returns Promise resolving to the callback's return value
|
|
2768
|
+
* @throws {Error} On init, connect, `DbError`, or callback failure
|
|
2769
|
+
*/
|
|
2770
|
+
async run(callback, token, region = "amer") {
|
|
2771
|
+
let client;
|
|
2772
|
+
try {
|
|
2773
|
+
const db = await (0, import_aio_lib_db.init)({ token, region });
|
|
2774
|
+
client = await db.connect();
|
|
2775
|
+
const collection = await client.collection(this._name);
|
|
2776
|
+
return await callback(collection, client);
|
|
2777
|
+
} catch (error) {
|
|
2778
|
+
if (error instanceof import_aio_lib_db.DbError) {
|
|
2779
|
+
throw new Error(`AbdbCollection: database error: ${error.message}`);
|
|
2780
|
+
}
|
|
2781
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
2782
|
+
throw new Error(`AbdbCollection: unexpected error: ${detail}`);
|
|
2783
|
+
} finally {
|
|
2784
|
+
await client?.close();
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
/**
|
|
2788
|
+
* Validates and normalizes the collection identifier used at construction.
|
|
2789
|
+
*
|
|
2790
|
+
* @throws {Error} If the name is empty or not `[a-zA-Z0-9_]`
|
|
2791
|
+
*/
|
|
2792
|
+
_validateCollectionName(name) {
|
|
2793
|
+
return this._validateIdentifier(
|
|
2794
|
+
name,
|
|
2795
|
+
'AbdbCollection: "name" is required and cannot be empty',
|
|
2796
|
+
"AbdbCollection: name must contain only alphanumeric characters and underscores"
|
|
2797
|
+
);
|
|
2798
|
+
}
|
|
2799
|
+
/**
|
|
2800
|
+
* Validates and normalizes a column name before {@link addColumn} stores it.
|
|
2801
|
+
*
|
|
2802
|
+
* @throws {Error} If the name is empty or not `[a-zA-Z0-9_]`
|
|
2803
|
+
*/
|
|
2804
|
+
_validateColumnName(name) {
|
|
2805
|
+
return this._validateIdentifier(
|
|
2806
|
+
name,
|
|
2807
|
+
'AbdbCollection: column "name" is required and cannot be empty',
|
|
2808
|
+
"AbdbCollection: column name must contain only alphanumeric characters and underscores"
|
|
2809
|
+
);
|
|
2810
|
+
}
|
|
2811
|
+
/**
|
|
2812
|
+
* Shared validation for collection and column identifiers.
|
|
2813
|
+
*
|
|
2814
|
+
* @param raw - Unvalidated string
|
|
2815
|
+
* @param emptyMessage - Thrown when `raw` is missing or whitespace-only
|
|
2816
|
+
* @param invalidMessage - Thrown when the trimmed value is not alphanumeric with underscores
|
|
2817
|
+
* @returns The trimmed identifier
|
|
2818
|
+
*/
|
|
2819
|
+
_validateIdentifier(raw, emptyMessage, invalidMessage) {
|
|
2820
|
+
if (!raw || raw.trim() === "") {
|
|
2821
|
+
throw new Error(emptyMessage);
|
|
2822
|
+
}
|
|
2823
|
+
const trimmed = raw.trim();
|
|
2824
|
+
if (!/^[a-zA-Z0-9_]+$/.test(trimmed)) {
|
|
2825
|
+
throw new Error(invalidMessage);
|
|
2826
|
+
}
|
|
2827
|
+
return trimmed;
|
|
2828
|
+
}
|
|
2829
|
+
};
|
|
2830
|
+
__name(_AbdbCollection, "AbdbCollection");
|
|
2831
|
+
var AbdbCollection = _AbdbCollection;
|
|
2832
|
+
var collection_default = AbdbCollection;
|
|
2833
|
+
|
|
2834
|
+
// src/framework/repository/abdb-repository/index.ts
|
|
2835
|
+
var _AbdbRepository = class _AbdbRepository {
|
|
2836
|
+
/**
|
|
2837
|
+
* @param collection - Schema and DB-connection wrapper for the target collection
|
|
2838
|
+
* @param token - IMS access token forwarded to every `collection.run()` call
|
|
2839
|
+
* @param region - Data region forwarded to every `collection.run()` call (default: `'amer'`)
|
|
2840
|
+
* @throws {Error} When `collection` is not an {@link AbdbCollection} instance, or `token` is missing
|
|
2841
|
+
*/
|
|
2842
|
+
constructor(collection, token, region = "amer") {
|
|
2843
|
+
if (!(collection instanceof collection_default)) {
|
|
2844
|
+
throw new Error('AbdbRepository: "collection" must be an AbdbCollection instance');
|
|
2845
|
+
}
|
|
2846
|
+
if (!token || typeof token !== "string" || !token.trim()) {
|
|
2847
|
+
throw new Error('AbdbRepository: "token" is required');
|
|
2848
|
+
}
|
|
2849
|
+
if (!collection.hasColumn("_created_at")) {
|
|
2850
|
+
collection.addColumn("_created_at", "DATETIME" /* DATETIME */, "Record creation timestamp");
|
|
2851
|
+
}
|
|
2852
|
+
if (!collection.hasColumn("_updated_at")) {
|
|
2853
|
+
collection.addColumn("_updated_at", "DATETIME" /* DATETIME */, "Record last-updated timestamp");
|
|
2854
|
+
}
|
|
2855
|
+
this._collection = collection;
|
|
2856
|
+
this._token = token;
|
|
2857
|
+
this._region = region;
|
|
2858
|
+
}
|
|
2859
|
+
/**
|
|
2860
|
+
* Returns the name of the underlying collection.
|
|
2861
|
+
*/
|
|
2862
|
+
getName() {
|
|
2863
|
+
return this._collection.getName();
|
|
2864
|
+
}
|
|
2865
|
+
/**
|
|
2866
|
+
* Returns the underlying {@link AbdbCollection} instance.
|
|
2867
|
+
*/
|
|
2868
|
+
getCollection() {
|
|
2869
|
+
return this._collection;
|
|
2870
|
+
}
|
|
2871
|
+
/**
|
|
2872
|
+
* Returns all documents matching `filter` as an array.
|
|
2873
|
+
* Passing no filter (or an empty object) returns every document in the collection.
|
|
2874
|
+
*
|
|
2875
|
+
* @param filter - Optional query filter (default: `{}`)
|
|
2876
|
+
* @returns Array of matched documents (may be empty)
|
|
2877
|
+
*/
|
|
2878
|
+
async find(filter = {}) {
|
|
2879
|
+
return this._collection.run(
|
|
2880
|
+
async (collection) => {
|
|
2881
|
+
return collection.find(filter).toArray();
|
|
2882
|
+
},
|
|
2883
|
+
this._token,
|
|
2884
|
+
this._region
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
/**
|
|
2888
|
+
* Returns the first document matching `filter`, or `null` if none found.
|
|
2889
|
+
*
|
|
2890
|
+
* @param filter - Query filter (e.g. `{ _id: 'abc' }` or `{ email: 'a@b.com' }`)
|
|
2891
|
+
* @returns The matched document, or `null`
|
|
2892
|
+
*/
|
|
2893
|
+
async findOne(filter) {
|
|
2894
|
+
return this._collection.run(
|
|
2895
|
+
async (collection) => {
|
|
2896
|
+
return collection.findOne(filter);
|
|
2897
|
+
},
|
|
2898
|
+
this._token,
|
|
2899
|
+
this._region
|
|
2900
|
+
);
|
|
2901
|
+
}
|
|
2902
|
+
/**
|
|
2903
|
+
* Returns `true` when a document with the given `_id` exists in the collection.
|
|
2904
|
+
* Uses `countDocuments` rather than fetching the full document for efficiency.
|
|
2905
|
+
*
|
|
2906
|
+
* @param id - The `_id` to check
|
|
2907
|
+
* @returns `true` if the document exists, `false` otherwise
|
|
2908
|
+
*/
|
|
2909
|
+
async exists(id) {
|
|
2910
|
+
if (!id) return false;
|
|
2911
|
+
const n = await this._collection.run(
|
|
2912
|
+
(collection) => {
|
|
2913
|
+
return collection.countDocuments({ _id: id });
|
|
2914
|
+
},
|
|
2915
|
+
this._token,
|
|
2916
|
+
this._region
|
|
2917
|
+
);
|
|
2918
|
+
return n > 0;
|
|
2919
|
+
}
|
|
2920
|
+
/**
|
|
2921
|
+
* Returns the number of documents in the collection matching `filter`.
|
|
2922
|
+
* Passing no filter (or an empty object) counts every document.
|
|
2923
|
+
*
|
|
2924
|
+
* @param filter - Optional query filter (default: `{}`)
|
|
2925
|
+
* @returns Total number of matching documents
|
|
2926
|
+
*/
|
|
2927
|
+
async count(filter = {}) {
|
|
2928
|
+
return this._collection.run(
|
|
2929
|
+
(collection) => {
|
|
2930
|
+
return collection.countDocuments(filter);
|
|
2931
|
+
},
|
|
2932
|
+
this._token,
|
|
2933
|
+
this._region
|
|
2934
|
+
);
|
|
2935
|
+
}
|
|
2936
|
+
/**
|
|
2937
|
+
* Inserts or updates a document.
|
|
2938
|
+
*
|
|
2939
|
+
* - **Insert** (no `id`): stamps both `_created_at` and `_updated_at`, runs full schema
|
|
2940
|
+
* validation, then calls `insertOne`. Returns the new document's `_id`.
|
|
2941
|
+
* - **Update** (with `id`): stamps `_updated_at`, runs **partial** validation (only columns
|
|
2942
|
+
* present in the payload are checked — required fields that are absent are not enforced
|
|
2943
|
+
* because they already exist in the stored document), then calls `updateOne` with
|
|
2944
|
+
* `upsert: true`. Returns the same `id` that was passed in.
|
|
2945
|
+
*
|
|
2946
|
+
* @param payload - Document fields to write
|
|
2947
|
+
* @param id - When provided, updates the document with this `_id`; otherwise inserts
|
|
2948
|
+
* @returns The `_id` of the inserted or updated document
|
|
2949
|
+
*/
|
|
2950
|
+
async save(payload = {}, id = "") {
|
|
2951
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2952
|
+
if (id) {
|
|
2953
|
+
const updatePayload = { ...payload, _updated_at: now };
|
|
2954
|
+
this._validatePartial(updatePayload);
|
|
2955
|
+
await this._collection.run(
|
|
2956
|
+
async (collection) => {
|
|
2957
|
+
await collection.updateOne({ _id: id }, updatePayload, { upsert: true });
|
|
2958
|
+
},
|
|
2959
|
+
this._token,
|
|
2960
|
+
this._region
|
|
2961
|
+
);
|
|
2962
|
+
return id;
|
|
2963
|
+
}
|
|
2964
|
+
const insertPayload = { ...payload, _created_at: now, _updated_at: now };
|
|
2965
|
+
this._collection.validate(insertPayload);
|
|
2966
|
+
return this._collection.run(
|
|
2967
|
+
async (collection) => {
|
|
2968
|
+
return collection.insertOne(insertPayload);
|
|
2969
|
+
},
|
|
2970
|
+
this._token,
|
|
2971
|
+
this._region
|
|
2972
|
+
);
|
|
2973
|
+
}
|
|
2974
|
+
/**
|
|
2975
|
+
* Deletes the document with the given `_id`. No-ops silently when `id` is empty.
|
|
2976
|
+
*
|
|
2977
|
+
* @param id - The `_id` of the document to delete
|
|
2978
|
+
*/
|
|
2979
|
+
async delete(id = "") {
|
|
2980
|
+
if (!id) return;
|
|
2981
|
+
await this._collection.run(
|
|
2982
|
+
async (collection) => {
|
|
2983
|
+
await collection.deleteOne({ _id: id });
|
|
2984
|
+
},
|
|
2985
|
+
this._token,
|
|
2986
|
+
this._region
|
|
2987
|
+
);
|
|
2988
|
+
}
|
|
2989
|
+
/**
|
|
2990
|
+
* Inserts multiple documents in a single `insertMany` call.
|
|
2991
|
+
* Each payload is stamped with `_created_at` / `_updated_at` and validated
|
|
2992
|
+
* against the full collection schema before the bulk write is sent to the DB.
|
|
2993
|
+
*
|
|
2994
|
+
* @param payloads - Array of document payloads to insert
|
|
2995
|
+
* @returns Array of inserted `_id` values in insertion order
|
|
2996
|
+
*/
|
|
2997
|
+
async insertAll(payloads) {
|
|
2998
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2999
|
+
const insertPayloads = payloads.map((payload) => {
|
|
3000
|
+
const doc = { ...payload, _created_at: now, _updated_at: now };
|
|
3001
|
+
this._collection.validate(doc);
|
|
3002
|
+
return doc;
|
|
3003
|
+
});
|
|
3004
|
+
return this._collection.run(
|
|
3005
|
+
async (collection) => {
|
|
3006
|
+
return collection.insertMany(insertPayloads);
|
|
3007
|
+
},
|
|
3008
|
+
this._token,
|
|
3009
|
+
this._region
|
|
3010
|
+
);
|
|
3011
|
+
}
|
|
3012
|
+
/**
|
|
3013
|
+
* Applies a partial update to all documents matching `filter` using a single `updateMany` call.
|
|
3014
|
+
* Stamps `_updated_at` on every matched document and runs partial validation on the payload
|
|
3015
|
+
* (only the columns present in the payload are checked).
|
|
3016
|
+
*
|
|
3017
|
+
* @param payload - Fields to update on every matched document
|
|
3018
|
+
* @param filter - Query condition selecting which documents to update (default: `{}` — all documents)
|
|
3019
|
+
*/
|
|
3020
|
+
async updateAll(payload, filter = {}) {
|
|
3021
|
+
const updatePayload = { ...payload, _updated_at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
3022
|
+
this._validatePartial(updatePayload);
|
|
3023
|
+
await this._collection.run(
|
|
3024
|
+
async (collection) => {
|
|
3025
|
+
await collection.updateMany(filter, updatePayload);
|
|
3026
|
+
},
|
|
3027
|
+
this._token,
|
|
3028
|
+
this._region
|
|
3029
|
+
);
|
|
3030
|
+
}
|
|
3031
|
+
/**
|
|
3032
|
+
* Deletes all documents matching `filter` using a single `deleteMany` call.
|
|
3033
|
+
* Passing no filter (or an empty object) deletes every document in the collection.
|
|
3034
|
+
*
|
|
3035
|
+
* @param filter - Optional query filter (default: `{}`)
|
|
3036
|
+
*/
|
|
3037
|
+
async deleteAll(filter = {}) {
|
|
3038
|
+
await this._collection.run(
|
|
3039
|
+
async (collection) => {
|
|
3040
|
+
await collection.deleteMany(filter);
|
|
3041
|
+
},
|
|
3042
|
+
this._token,
|
|
3043
|
+
this._region
|
|
3044
|
+
);
|
|
3045
|
+
}
|
|
3046
|
+
/**
|
|
3047
|
+
* Validates only the columns whose keys are present in `record`.
|
|
3048
|
+
* Required columns that are absent from the payload are intentionally skipped —
|
|
3049
|
+
* they already exist in the stored document and are not being changed.
|
|
3050
|
+
*
|
|
3051
|
+
* Used by the update path of {@link save} and {@link updateAll}.
|
|
3052
|
+
*/
|
|
3053
|
+
_validatePartial(record) {
|
|
3054
|
+
for (const col of this._collection.getColumns()) {
|
|
3055
|
+
const key = col.getName();
|
|
3056
|
+
if (key in record) {
|
|
3057
|
+
col.validate(record[key]);
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
};
|
|
3062
|
+
__name(_AbdbRepository, "AbdbRepository");
|
|
3063
|
+
var AbdbRepository = _AbdbRepository;
|
|
3064
|
+
var abdb_repository_default = AbdbRepository;
|
|
3065
|
+
|
|
2394
3066
|
// src/framework/publish-event/index.ts
|
|
2395
3067
|
var import_aio_sdk3 = require("@adobe/aio-sdk");
|
|
2396
3068
|
var import_cloudevents = require("cloudevents");
|
|
@@ -8852,6 +9524,10 @@ __name(_AdminUiSdk, "AdminUiSdk");
|
|
|
8852
9524
|
var AdminUiSdk = _AdminUiSdk;
|
|
8853
9525
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8854
9526
|
0 && (module.exports = {
|
|
9527
|
+
AbdbCollection,
|
|
9528
|
+
AbdbColumn,
|
|
9529
|
+
AbdbColumnType,
|
|
9530
|
+
AbdbRepository,
|
|
8855
9531
|
AdminUiSdk,
|
|
8856
9532
|
AdobeAuth,
|
|
8857
9533
|
AdobeCommerceClient,
|