@rebasepro/server 0.11.1-canary.gfd39654 → 0.12.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/dist/api/contract-routes.d.ts +0 -1
- package/dist/auth/api-keys/api-key-types.d.ts +6 -70
- package/dist/auth/builtin-auth-adapter.d.ts +11 -0
- package/dist/auth/registration-policy.d.ts +57 -0
- package/dist/boot/bundle.d.ts +17 -5
- package/dist/boot/driver.d.ts +17 -3
- package/dist/boot/env.d.ts +16 -2
- package/dist/boot/sources.d.ts +31 -0
- package/dist/collections/loader.d.ts +11 -1
- package/dist/collections/validate-config.d.ts +70 -0
- package/dist/cron/cron-scheduler.d.ts +9 -0
- package/dist/cron/index.d.ts +1 -0
- package/dist/cron/scale-to-zero.d.ts +58 -0
- package/dist/env.d.ts +5 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.es.js +1024 -125
- package/dist/index.es.js.map +1 -1
- package/dist/init.d.ts +14 -17
- package/dist/{openapi-generator-CeOnlAJ3.js → openapi-generator-Bjzmb5cn.js} +5 -4
- package/dist/openapi-generator-Bjzmb5cn.js.map +1 -0
- package/dist/{schema-editor-routes-BFpXKkPD.js → schema-editor-routes-DDxfOIid.js} +2 -2
- package/dist/{schema-editor-routes-BFpXKkPD.js.map → schema-editor-routes-DDxfOIid.js.map} +1 -1
- package/dist/serve-spa.d.ts +31 -1
- package/dist/{src-q6_elgGZ.js → src-CoOAMnBh.js} +193 -14
- package/dist/src-CoOAMnBh.js.map +1 -0
- package/dist/{src-BYbxB4PR.js → src-Ivjud8jD.js} +272 -90
- package/dist/src-Ivjud8jD.js.map +1 -0
- package/package.json +5 -5
- package/dist/openapi-generator-CeOnlAJ3.js.map +0 -1
- package/dist/src-BYbxB4PR.js.map +0 -1
- package/dist/src-q6_elgGZ.js.map +0 -1
|
@@ -2,7 +2,7 @@ import { createRequire as __createRequire } from "module";
|
|
|
2
2
|
import "process";
|
|
3
3
|
__createRequire(import.meta.url);
|
|
4
4
|
import { r as __require, t as __commonJSMin } from "./chunk-DSJWtz9O.js";
|
|
5
|
-
import {
|
|
5
|
+
import { S as toCanonicalOp, b as NULL_OPS, f as getDeclaredSubcollections, g as getDataSourceCapabilities, l as policy, m as isRelationalCollectionConfig, w as EntityRelation, x as REST_TO_CANONICAL, y as CANONICAL_TO_REST } from "./src-Ivjud8jD.js";
|
|
6
6
|
(/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
7
7
|
(function(e) {
|
|
8
8
|
var t;
|
|
@@ -1270,7 +1270,7 @@ var _resolvedRelationsCache = /* @__PURE__ */ new WeakMap();
|
|
|
1270
1270
|
function resolveCollectionRelations(collection) {
|
|
1271
1271
|
const cached = _resolvedRelationsCache.get(collection);
|
|
1272
1272
|
if (cached) return cached;
|
|
1273
|
-
if (!
|
|
1273
|
+
if (!isRelationalCollectionConfig(collection)) return {};
|
|
1274
1274
|
const relations = {};
|
|
1275
1275
|
for (const relation of collection.relations ?? []) {
|
|
1276
1276
|
const resolved = resolveRelation(relation, collection);
|
|
@@ -1286,7 +1286,7 @@ function resolveCollectionRelations(collection) {
|
|
|
1286
1286
|
return relations;
|
|
1287
1287
|
}
|
|
1288
1288
|
function getTableName(collection) {
|
|
1289
|
-
if (
|
|
1289
|
+
if (isRelationalCollectionConfig(collection)) return collection.table ?? toSnakeCase(collection.slug) ?? toSnakeCase(collection.name);
|
|
1290
1290
|
return toSnakeCase(collection.slug) ?? toSnakeCase(collection.name);
|
|
1291
1291
|
}
|
|
1292
1292
|
/**
|
|
@@ -2451,6 +2451,136 @@ var QueryBuilder = class {
|
|
|
2451
2451
|
return this.collection.listen(this.params, onUpdate, onError);
|
|
2452
2452
|
}
|
|
2453
2453
|
};
|
|
2454
|
+
/** Rows `findAll()` will materialise before it refuses to continue. */
|
|
2455
|
+
var DEFAULT_FIND_ALL_MAX_ROWS = 1e4;
|
|
2456
|
+
/**
|
|
2457
|
+
* Requests one walk may make before it gives up on the server ever saying
|
|
2458
|
+
* `hasMore: false`. At the default page size that is two million rows — far
|
|
2459
|
+
* past any legitimate walk, and short of running forever.
|
|
2460
|
+
*/
|
|
2461
|
+
var DEFAULT_MAX_PAGES = 1e4;
|
|
2462
|
+
/**
|
|
2463
|
+
* Thrown when a walk stops for a reason the caller needs to know about.
|
|
2464
|
+
*
|
|
2465
|
+
* Every one of these is a case where the alternative would be silent: a
|
|
2466
|
+
* truncated array that looks complete, or a loop that never returns. Check
|
|
2467
|
+
* {@link code} to tell them apart.
|
|
2468
|
+
*/
|
|
2469
|
+
var RebasePaginationError = class RebasePaginationError extends Error {
|
|
2470
|
+
code;
|
|
2471
|
+
constructor(code, message) {
|
|
2472
|
+
super(message);
|
|
2473
|
+
this.name = "RebasePaginationError";
|
|
2474
|
+
this.code = code;
|
|
2475
|
+
Object.setPrototypeOf(this, RebasePaginationError.prototype);
|
|
2476
|
+
}
|
|
2477
|
+
};
|
|
2478
|
+
function normalizePageSize(raw) {
|
|
2479
|
+
if (raw === void 0 || !Number.isFinite(raw)) return 200;
|
|
2480
|
+
return Math.max(1, Math.floor(raw));
|
|
2481
|
+
}
|
|
2482
|
+
function normalizeMaxPages(raw) {
|
|
2483
|
+
if (raw === void 0) return DEFAULT_MAX_PAGES;
|
|
2484
|
+
if (raw === Number.POSITIVE_INFINITY) return raw;
|
|
2485
|
+
if (!Number.isFinite(raw)) return DEFAULT_MAX_PAGES;
|
|
2486
|
+
return Math.max(1, Math.floor(raw));
|
|
2487
|
+
}
|
|
2488
|
+
function normalizeMaxRows(raw) {
|
|
2489
|
+
if (raw === void 0) return DEFAULT_FIND_ALL_MAX_ROWS;
|
|
2490
|
+
if (raw === Number.POSITIVE_INFINITY) return raw;
|
|
2491
|
+
if (!Number.isFinite(raw)) return DEFAULT_FIND_ALL_MAX_ROWS;
|
|
2492
|
+
return Math.max(0, Math.floor(raw));
|
|
2493
|
+
}
|
|
2494
|
+
/**
|
|
2495
|
+
* Add one condition to a `where` map without disturbing what is already there.
|
|
2496
|
+
*
|
|
2497
|
+
* The caller's own filter on the cursor column has to survive — dropping it
|
|
2498
|
+
* would widen the query, which is the silent-filter-loss failure mode — so a
|
|
2499
|
+
* second condition on the same column becomes the array-of-tuples form that
|
|
2500
|
+
* `FindParams.where` already accepts, and both are AND-ed.
|
|
2501
|
+
*/
|
|
2502
|
+
function appendCondition(where, column, condition) {
|
|
2503
|
+
const next = { ...where ?? {} };
|
|
2504
|
+
const existing = next[column];
|
|
2505
|
+
if (existing === void 0) next[column] = condition;
|
|
2506
|
+
else if (Array.isArray(existing) && existing.length > 0 && Array.isArray(existing[0])) next[column] = [...existing, condition];
|
|
2507
|
+
else next[column] = [existing, condition];
|
|
2508
|
+
return next;
|
|
2509
|
+
}
|
|
2510
|
+
function cursorEquals(a, b) {
|
|
2511
|
+
if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
|
|
2512
|
+
return Object.is(a, b);
|
|
2513
|
+
}
|
|
2514
|
+
/**
|
|
2515
|
+
* Walk every row a query matches, yielding one row at a time and fetching the
|
|
2516
|
+
* next page only when the consumer asks for it.
|
|
2517
|
+
*
|
|
2518
|
+
* See {@link SDKCollectionClient.iterate} for the caller-facing contract,
|
|
2519
|
+
* including the offset-drift caveat and the `cursor` alternative.
|
|
2520
|
+
*
|
|
2521
|
+
* @param find the transport's single-page read
|
|
2522
|
+
* @param params `find()` parameters minus the window, plus the walk options
|
|
2523
|
+
* @param label the collection name, so an error says which walk failed
|
|
2524
|
+
*/
|
|
2525
|
+
async function* paginateFind(find, params, label = "collection") {
|
|
2526
|
+
const { pageSize, cursor, maxPages, ...rest } = params ?? {};
|
|
2527
|
+
const findParams = { ...rest };
|
|
2528
|
+
const size = normalizePageSize(pageSize);
|
|
2529
|
+
const pageCap = normalizeMaxPages(maxPages);
|
|
2530
|
+
const cursorField = typeof cursor === "string" ? cursor : cursor?.field;
|
|
2531
|
+
const requestedDirection = typeof cursor === "object" && cursor !== null ? cursor.direction : void 0;
|
|
2532
|
+
let direction = "asc";
|
|
2533
|
+
if (cursorField) {
|
|
2534
|
+
const orderBy = findParams.orderBy;
|
|
2535
|
+
if (orderBy && orderBy[0] !== cursorField) throw new RebasePaginationError("cursor-order-mismatch", `Cannot seek on "${cursorField}" while ordering "${label}" by "${orderBy[0]}": keyset pagination only advances along the column the query is sorted by. Order by "${cursorField}", or drop the cursor and page by offset.`);
|
|
2536
|
+
direction = requestedDirection ?? orderBy?.[1] ?? "asc";
|
|
2537
|
+
findParams.orderBy = [cursorField, direction];
|
|
2538
|
+
}
|
|
2539
|
+
const seekOp = direction === "desc" ? "<" : ">";
|
|
2540
|
+
const baseWhere = findParams.where;
|
|
2541
|
+
let offset = 0;
|
|
2542
|
+
let pages = 0;
|
|
2543
|
+
let cursorValue;
|
|
2544
|
+
let seeking = false;
|
|
2545
|
+
for (;;) {
|
|
2546
|
+
if (pages >= pageCap) throw new RebasePaginationError("max-pages", `Iterating "${label}" made ${pages} requests without the server reporting the end of the collection. Stopping rather than looping forever — raise \`maxPages\` if the walk is genuinely this long, or check that the backend sets \`meta.hasMore\`.`);
|
|
2547
|
+
const pageParams = {
|
|
2548
|
+
...findParams,
|
|
2549
|
+
limit: size
|
|
2550
|
+
};
|
|
2551
|
+
if (cursorField) {
|
|
2552
|
+
if (seeking) pageParams.where = appendCondition(baseWhere, cursorField, [seekOp, cursorValue]);
|
|
2553
|
+
} else pageParams.offset = offset;
|
|
2554
|
+
const page = await find(pageParams);
|
|
2555
|
+
pages += 1;
|
|
2556
|
+
const rows = page?.data ?? [];
|
|
2557
|
+
if (rows.length === 0) return;
|
|
2558
|
+
for (const row of rows) yield row;
|
|
2559
|
+
if (page?.meta?.hasMore !== true) return;
|
|
2560
|
+
if (cursorField) {
|
|
2561
|
+
const nextValue = rows[rows.length - 1]?.[cursorField];
|
|
2562
|
+
if (nextValue === void 0 || nextValue === null) throw new RebasePaginationError("cursor-missing", `Cannot seek past the last row of "${label}": it has no value for the cursor column "${cursorField}". Pick a column that is present and non-null on every row.`);
|
|
2563
|
+
if (seeking && cursorEquals(nextValue, cursorValue)) throw new RebasePaginationError("cursor-stalled", `Iterating "${label}" is stuck: two pages in a row ended at ${cursorField}=${String(nextValue)}. The cursor column has to be unique — a repeated value cannot be seeked past, and continuing would either loop forever or skip the duplicates. Use the primary key, or page by offset.`);
|
|
2564
|
+
cursorValue = nextValue;
|
|
2565
|
+
seeking = true;
|
|
2566
|
+
} else offset += rows.length;
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
/**
|
|
2570
|
+
* {@link paginateFind}, collected into an array under a ceiling.
|
|
2571
|
+
*
|
|
2572
|
+
* See {@link SDKCollectionClient.findAll}.
|
|
2573
|
+
*/
|
|
2574
|
+
async function collectAllPages(find, params, label = "collection") {
|
|
2575
|
+
const { maxRows, ...rest } = params ?? {};
|
|
2576
|
+
const cap = normalizeMaxRows(maxRows);
|
|
2577
|
+
const out = [];
|
|
2578
|
+
for await (const row of paginateFind(find, rest, label)) {
|
|
2579
|
+
out.push(row);
|
|
2580
|
+
if (out.length > cap) throw new RebasePaginationError("max-rows", `findAll("${label}") matched more than ${cap} rows. Returning the first ${cap} would look like the whole answer and quietly not be one, so this throws instead. Raise \`maxRows\` if you meant to load them all, or stream with \`iterate()\`.`);
|
|
2581
|
+
}
|
|
2582
|
+
return out;
|
|
2583
|
+
}
|
|
2454
2584
|
//#endregion
|
|
2455
2585
|
//#region ../common/src/data/filter-dialect.ts
|
|
2456
2586
|
/**
|
|
@@ -2754,6 +2884,42 @@ function rowToEntity(row, slug, primaryKeys = []) {
|
|
|
2754
2884
|
values: row
|
|
2755
2885
|
};
|
|
2756
2886
|
}
|
|
2887
|
+
/**
|
|
2888
|
+
* The relation envelope `toCmsRow` writes where a relation was:
|
|
2889
|
+
* `{ id, path, __type: "relation", data: { id, path, values } }`. It is the
|
|
2890
|
+
* admin's view-model, and the only pipeline that produces one is postgres'.
|
|
2891
|
+
*/
|
|
2892
|
+
function isRelationEnvelope(value) {
|
|
2893
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && value.__type === "relation";
|
|
2894
|
+
}
|
|
2895
|
+
/** The target's own columns, as `toRestRow` would have inlined them. */
|
|
2896
|
+
function inlineEnvelope(envelope) {
|
|
2897
|
+
return envelope.data?.values ?? {};
|
|
2898
|
+
}
|
|
2899
|
+
/**
|
|
2900
|
+
* Replace every relation envelope on a row with the target's flat columns.
|
|
2901
|
+
*
|
|
2902
|
+
* The SDK serves one relation shape — the inlined one (see
|
|
2903
|
+
* {@link RestFetchService}) — and reads that come back through a *driver*
|
|
2904
|
+
* method rather than the REST pipeline still carry envelopes. Realtime is the
|
|
2905
|
+
* one such read left: there is no `listenForRest`, so the rows arrive shaped
|
|
2906
|
+
* for the admin and are flattened here instead.
|
|
2907
|
+
*
|
|
2908
|
+
* Only applied where the REST pipeline is the contract (see `find`); a driver
|
|
2909
|
+
* without a `restFetchService` keeps whatever it returns, so the admin's own
|
|
2910
|
+
* path through {@link buildRebaseData} is untouched.
|
|
2911
|
+
*/
|
|
2912
|
+
function inlineRelationRefs(row) {
|
|
2913
|
+
let out;
|
|
2914
|
+
for (const [key, value] of Object.entries(row)) if (isRelationEnvelope(value)) {
|
|
2915
|
+
out = out ?? { ...row };
|
|
2916
|
+
out[key] = inlineEnvelope(value);
|
|
2917
|
+
} else if (Array.isArray(value) && value.some(isRelationEnvelope)) {
|
|
2918
|
+
out = out ?? { ...row };
|
|
2919
|
+
out[key] = value.map((item) => isRelationEnvelope(item) ? inlineEnvelope(item) : item);
|
|
2920
|
+
}
|
|
2921
|
+
return out ?? row;
|
|
2922
|
+
}
|
|
2757
2923
|
function createDriverAccessor(driver, slug, getPks = () => []) {
|
|
2758
2924
|
const accessor = {
|
|
2759
2925
|
async find(params) {
|
|
@@ -2761,14 +2927,14 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
|
|
|
2761
2927
|
const limit = params?.limit ?? 20;
|
|
2762
2928
|
const offset = params?.offset ?? 0;
|
|
2763
2929
|
const fetchService = driver.restFetchService;
|
|
2764
|
-
const rows = fetchService
|
|
2930
|
+
const rows = fetchService ? await fetchService.fetchCollectionForRest(slug, {
|
|
2765
2931
|
filter,
|
|
2766
2932
|
limit: params?.limit,
|
|
2767
2933
|
offset: params?.offset,
|
|
2768
2934
|
orderBy: params?.orderBy?.[0],
|
|
2769
2935
|
order: params?.orderBy?.[1],
|
|
2770
2936
|
searchString: params?.searchString
|
|
2771
|
-
}, params
|
|
2937
|
+
}, params?.include) : await driver.fetchCollection({
|
|
2772
2938
|
path: slug,
|
|
2773
2939
|
limit: params?.limit,
|
|
2774
2940
|
offset: params?.offset,
|
|
@@ -2797,7 +2963,8 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
|
|
|
2797
2963
|
};
|
|
2798
2964
|
},
|
|
2799
2965
|
async findById(id) {
|
|
2800
|
-
const
|
|
2966
|
+
const fetchService = driver.restFetchService;
|
|
2967
|
+
const row = fetchService ? await fetchService.fetchOneForRest(slug, id) : await driver.fetchOne({
|
|
2801
2968
|
path: slug,
|
|
2802
2969
|
id
|
|
2803
2970
|
});
|
|
@@ -2843,6 +3010,7 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
|
|
|
2843
3010
|
listen: driver.listenCollection ? (params, onUpdate, onError) => {
|
|
2844
3011
|
const limit = params?.limit ?? 20;
|
|
2845
3012
|
const offset = params?.offset ?? 0;
|
|
3013
|
+
const normalize = driver.restFetchService ? inlineRelationRefs : (row) => row;
|
|
2846
3014
|
return driver.listenCollection({
|
|
2847
3015
|
path: slug,
|
|
2848
3016
|
limit: params?.limit,
|
|
@@ -2853,7 +3021,7 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
|
|
|
2853
3021
|
searchString: params?.searchString,
|
|
2854
3022
|
onUpdate: (entities) => {
|
|
2855
3023
|
onUpdate({
|
|
2856
|
-
data: entities.map((row) => rowToEntity(row, slug, getPks())),
|
|
3024
|
+
data: entities.map((row) => rowToEntity(normalize(row), slug, getPks())),
|
|
2857
3025
|
meta: {
|
|
2858
3026
|
total: entities.length,
|
|
2859
3027
|
limit,
|
|
@@ -2866,10 +3034,11 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
|
|
|
2866
3034
|
});
|
|
2867
3035
|
} : void 0,
|
|
2868
3036
|
listenById: driver.listenOne ? (id, onUpdate, onError) => {
|
|
3037
|
+
const normalize = driver.restFetchService ? inlineRelationRefs : (row) => row;
|
|
2869
3038
|
return driver.listenOne({
|
|
2870
3039
|
path: slug,
|
|
2871
3040
|
id,
|
|
2872
|
-
onUpdate: (entity) => onUpdate(entity ? rowToEntity(entity, slug, getPks()) : void 0),
|
|
3041
|
+
onUpdate: (entity) => onUpdate(entity ? rowToEntity(normalize(entity), slug, getPks()) : void 0),
|
|
2873
3042
|
onError
|
|
2874
3043
|
});
|
|
2875
3044
|
} : void 0,
|
|
@@ -3000,7 +3169,7 @@ var SdkQueryBuilder = class {
|
|
|
3000
3169
|
* {@link SDKCollectionClient}. Every returned record is unwrapped to a flat row
|
|
3001
3170
|
* so the backend SDK is byte-for-byte the same shape as the frontend client.
|
|
3002
3171
|
*/
|
|
3003
|
-
function toSdkCollectionClient(snap) {
|
|
3172
|
+
function toSdkCollectionClient(snap, slug = "collection") {
|
|
3004
3173
|
const client = {
|
|
3005
3174
|
async find(params) {
|
|
3006
3175
|
const res = await snap.find(params);
|
|
@@ -3009,6 +3178,12 @@ function toSdkCollectionClient(snap) {
|
|
|
3009
3178
|
meta: res.meta
|
|
3010
3179
|
};
|
|
3011
3180
|
},
|
|
3181
|
+
iterate(params) {
|
|
3182
|
+
return paginateFind((p) => client.find(p), params, slug);
|
|
3183
|
+
},
|
|
3184
|
+
findAll(params) {
|
|
3185
|
+
return collectAllPages((p) => client.find(p), params, slug);
|
|
3186
|
+
},
|
|
3012
3187
|
async findById(id) {
|
|
3013
3188
|
const s = await snap.findById(id);
|
|
3014
3189
|
return s ? entityToRow(s) : void 0;
|
|
@@ -3060,7 +3235,7 @@ function wrapAsSdkData(entityData) {
|
|
|
3060
3235
|
function getAccessor(slug) {
|
|
3061
3236
|
let accessor = cache.get(slug);
|
|
3062
3237
|
if (!accessor) {
|
|
3063
|
-
accessor = toSdkCollectionClient(entityData.collection(slug));
|
|
3238
|
+
accessor = toSdkCollectionClient(entityData.collection(slug), slug);
|
|
3064
3239
|
cache.set(slug, accessor);
|
|
3065
3240
|
}
|
|
3066
3241
|
return accessor;
|
|
@@ -3077,8 +3252,12 @@ function wrapAsSdkData(entityData) {
|
|
|
3077
3252
|
*
|
|
3078
3253
|
* This is the developer-facing SDK data layer used by backend framework
|
|
3079
3254
|
* callbacks & scripts (`context.data` / `rebase.data`). It returns flat rows —
|
|
3080
|
-
* identical in shape to the frontend SDK client
|
|
3081
|
-
*
|
|
3255
|
+
* identical in shape to the frontend SDK client, down to how a relation is
|
|
3256
|
+
* served: a foreign key stays a foreign key, and a relation named in `include`
|
|
3257
|
+
* arrives as the target's own columns. The `{ __type: "relation" }` envelope is
|
|
3258
|
+
* the admin's view-model and never reaches here.
|
|
3259
|
+
*
|
|
3260
|
+
* The admin uses {@link buildRebaseData} (Entity) over its own driver.
|
|
3082
3261
|
*/
|
|
3083
3262
|
function buildSdkData(driver) {
|
|
3084
3263
|
return wrapAsSdkData(buildRebaseData(driver));
|
|
@@ -3178,6 +3357,6 @@ function deserializeOrderBy(raw) {
|
|
|
3178
3357
|
return [raw.slice(0, idx), raw.slice(idx + 1) === "desc" ? "desc" : "asc"];
|
|
3179
3358
|
}
|
|
3180
3359
|
//#endregion
|
|
3181
|
-
export { deserializeFilter as a, serializeLogicalCondition as c,
|
|
3360
|
+
export { toSnakeCase as _, deserializeFilter as a, serializeLogicalCondition as c, CollectionRegistry as d, createDataSourceRegistry as f, buildCompositeId as g, resolveCollectionRelations as h, buildSdkData as i, collectAllPages as l, findRelation as m, serializeOrderBy as n, deserializeLogicalCondition as o, resolveDataSource as p, buildRoutedRebaseData as r, serializeFilter as s, deserializeOrderBy as t, paginateFind as u };
|
|
3182
3361
|
|
|
3183
|
-
//# sourceMappingURL=src-
|
|
3362
|
+
//# sourceMappingURL=src-CoOAMnBh.js.map
|