@rebasepro/server 0.13.0 → 0.13.1-canary.g3660bd5
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/{admin_block-CcSGdH7M.js → admin_block-EmIHae6X.js} +2 -1
- package/dist/admin_block-EmIHae6X.js.map +1 -0
- package/dist/api/errors.d.ts +0 -6
- package/dist/api/openapi-generator.d.ts +14 -0
- package/dist/api/rest/idempotency.d.ts +41 -4
- package/dist/api/rest/write-validation.d.ts +12 -5
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/jwt.d.ts +12 -0
- package/dist/{auth-CuC9M2x6.js → auth-BE_FSK1l.js} +17 -37
- package/dist/auth-BE_FSK1l.js.map +1 -0
- package/dist/{backup-CVggVhR2.js → backup-BJiY_mM-.js} +2 -2
- package/dist/{backup-CVggVhR2.js.map → backup-BJiY_mM-.js.map} +1 -1
- package/dist/{cron-routes-CrQ0tK-_.js → cron-routes-D5a9v1HY.js} +2 -2
- package/dist/{cron-routes-CrQ0tK-_.js.map → cron-routes-D5a9v1HY.js.map} +1 -1
- package/dist/{cron-scheduler-B3RFt0HS.js → cron-scheduler-BhFZWR0T.js} +21 -2
- package/dist/cron-scheduler-BhFZWR0T.js.map +1 -0
- package/dist/{cron-store-BywZsyfZ.js → cron-store-Cu4sOseb.js} +11 -1
- package/dist/cron-store-Cu4sOseb.js.map +1 -0
- package/dist/{errors-CgkCzoj7.js → errors-BpudWAVU.js} +2 -10
- package/dist/errors-BpudWAVU.js.map +1 -0
- package/dist/index.es.js +220 -164
- package/dist/index.es.js.map +1 -1
- package/dist/{jwt-DD6EtpGj.js → jwt-CzeviDcB.js} +17 -2
- package/dist/{jwt-DD6EtpGj.js.map → jwt-CzeviDcB.js.map} +1 -1
- package/dist/{openapi-generator-BEwyiaAr.js → openapi-generator-C-Rqz9sp.js} +99 -102
- package/dist/openapi-generator-C-Rqz9sp.js.map +1 -0
- package/dist/{schema-editor-routes-CbF20Mf1.js → schema-editor-routes-C1DxDnDR.js} +3 -3
- package/dist/{schema-editor-routes-CbF20Mf1.js.map → schema-editor-routes-C1DxDnDR.js.map} +1 -1
- package/dist/{src-Cum9kox5.js → src-7U0xuQo3.js} +65 -15
- package/dist/src-7U0xuQo3.js.map +1 -0
- package/dist/utils/logging.d.ts +0 -4
- package/package.json +5 -5
- package/dist/admin_block-CcSGdH7M.js.map +0 -1
- package/dist/auth-CuC9M2x6.js.map +0 -1
- package/dist/cron-scheduler-B3RFt0HS.js.map +0 -1
- package/dist/cron-store-BywZsyfZ.js.map +0 -1
- package/dist/errors-CgkCzoj7.js.map +0 -1
- package/dist/openapi-generator-BEwyiaAr.js.map +0 -1
- package/dist/src-Cum9kox5.js.map +0 -1
package/dist/index.es.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "module";
|
|
2
2
|
import process from "process";
|
|
3
3
|
__createRequire(import.meta.url);
|
|
4
|
-
import {
|
|
4
|
+
import { C as EntityReference, E as Vector, T as GeoPoint, _ as resolvePrimaryKeys, a as serializeFilter, b as resolveClientListLimit, c as paginateFind, d as createDataSourceRegistry, f as resolveDataSource, g as buildCompositeId, h as resolveCollectionRelations, i as deserializeLogicalCondition, l as resolveFindWindow, m as findRelation, n as buildSdkData, o as serializeLogicalCondition, p as getEffectiveSecurityRules, r as deserializeFilter, s as collectAllPages, t as buildRoutedRebaseData, u as CollectionRegistry, v as toSnakeCase, w as EntityRelation } from "./src-7U0xuQo3.js";
|
|
5
5
|
import { a as DEFAULT_DATA_SOURCE_KEY, r as isPostgresCollectionConfig, t as getCollectionDataPath, u as toCanonicalOp } from "./src-_qQ3RNCK.js";
|
|
6
|
-
import { n as ADMIN_PROPERTY_KEYS, t as ADMIN_COLLECTION_KEYS } from "./admin_block-
|
|
6
|
+
import { n as ADMIN_PROPERTY_KEYS, t as ADMIN_COLLECTION_KEYS } from "./admin_block-EmIHae6X.js";
|
|
7
7
|
import { t as isSQLAdmin } from "./backend-CIxN4FVm.js";
|
|
8
8
|
import { n as createContractRoutes } from "./contract-routes-Dj8i5AiM.js";
|
|
9
|
-
import { $ as httpMethodToOperation, A as getEmailVerificationTemplate, B as optionalAuth, C as createDataRateLimiter, D as validatePasswordStrength, E as hashPassword, F as createAdapterAuthMiddleware, G as createApiKeyPreAuth, H as queryTokenAuth, I as createAuthMiddleware, J as isApiKeyToken, K as createFunctionApiKeyGuard, L as createRequireAuth, M as getPasswordResetTemplate, N as getUserInvitationTemplate, O as verifyPassword, P as getWelcomeEmailTemplate, Q as scopeDataDriver, R as extractUserFromToken, S as _coercedNumber, T as resolveAuthHooks, U as requireAdmin, V as publicObjectAuth, W as requireAuth, X as extractBearerToken, Y as validateApiKey, Z as safeCompare, _ as createBuiltinAuthAdapter, a as createSpotifyProvider, b as object, c as createGitLabProvider, d as createFacebookProvider, et as isOperationAllowed, f as createAppleProvider, g as createGoogleProvider, h as createLinkedinProvider, i as createApiKeyStore,
|
|
9
|
+
import { $ as httpMethodToOperation, A as getEmailVerificationTemplate, B as optionalAuth, C as createDataRateLimiter, D as validatePasswordStrength, E as hashPassword, F as createAdapterAuthMiddleware, G as createApiKeyPreAuth, H as queryTokenAuth, I as createAuthMiddleware, J as isApiKeyToken, K as createFunctionApiKeyGuard, L as createRequireAuth, M as getPasswordResetTemplate, N as getUserInvitationTemplate, O as verifyPassword, P as getWelcomeEmailTemplate, Q as scopeDataDriver, R as extractUserFromToken, S as _coercedNumber, T as resolveAuthHooks, U as requireAdmin, V as publicObjectAuth, W as requireAuth, X as extractBearerToken, Y as validateApiKey, Z as safeCompare, _ as createBuiltinAuthAdapter, a as createSpotifyProvider, b as object, c as createGitLabProvider, d as createFacebookProvider, et as isOperationAllowed, f as createAppleProvider, g as createGoogleProvider, h as createLinkedinProvider, i as createApiKeyStore, j as getMagicLinkTemplate, k as generateSecurePassword, l as createDiscordProvider, m as createGitHubProvider, n as createCustomAuthAdapter, nt as isPublicStoragePath, o as createSlackProvider, p as createMicrosoftProvider, q as createStorageApiKeyGuard, r as createApiKeyRoutes, s as createBitbucketProvider, tt as PUBLIC_STORAGE_PREFIX, u as createTwitterProvider, v as ZodNumber, w as MemoryRateLimitStore, x as string, y as _enum, z as fileTokenAuth } from "./auth-BE_FSK1l.js";
|
|
10
10
|
import { t as logger } from "./logger-BYU66ENZ.js";
|
|
11
|
-
import { n as errorHandler,
|
|
12
|
-
import { i as generateDownloadToken, n as configureJwt } from "./jwt-
|
|
11
|
+
import { n as errorHandler, t as ApiError } from "./errors-BpudWAVU.js";
|
|
12
|
+
import { i as generateDownloadToken, n as configureJwt } from "./jwt-CzeviDcB.js";
|
|
13
13
|
import { t as logMiddleware } from "./logs-routes-BYA72C_C.js";
|
|
14
14
|
import { n as DOCUMENT_MIME_TYPES, r as IMAGE_MIME_TYPES, t as DEFAULT_MAX_FILE_SIZE } from "./types-DSnOC4mF.js";
|
|
15
15
|
import { t as S3StorageController } from "./S3StorageController-B2EDXXMH.js";
|
|
@@ -17,10 +17,10 @@ import { t as GCSStorageController } from "./GCSStorageController-BEmDYFKc.js";
|
|
|
17
17
|
import { n as loadFunctionsFromDirectory } from "./function-loader-B_1fYfUY.js";
|
|
18
18
|
import { t as createFunctionRoutes } from "./function-routes-C0cLIy3N.js";
|
|
19
19
|
import { n as loadCronJobsFromDirectory } from "./cron-loader-B1S2MCSl.js";
|
|
20
|
-
import { r as validateCronExpression, t as CronScheduler } from "./cron-scheduler-
|
|
21
|
-
import { t as createCronRoutes } from "./cron-routes-
|
|
22
|
-
import { t as createCronStore } from "./cron-store-
|
|
23
|
-
import { a as parseBackupTimestamp, i as parseBackupDestination, n as createBackupRoutes, o as readBackupBytes, r as listBackupObjects } from "./backup-
|
|
20
|
+
import { r as validateCronExpression, t as CronScheduler } from "./cron-scheduler-BhFZWR0T.js";
|
|
21
|
+
import { t as createCronRoutes } from "./cron-routes-D5a9v1HY.js";
|
|
22
|
+
import { t as createCronStore } from "./cron-store-Cu4sOseb.js";
|
|
23
|
+
import { a as parseBackupTimestamp, i as parseBackupDestination, n as createBackupRoutes, o as readBackupBytes, r as listBackupObjects } from "./backup-BJiY_mM-.js";
|
|
24
24
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
25
25
|
import * as fs$2 from "fs";
|
|
26
26
|
import fs, { existsSync } from "fs";
|
|
@@ -1055,11 +1055,18 @@ function assertKnownWriteFields(values, collection, options) {
|
|
|
1055
1055
|
* This shapes the *response*, which is what the parameter says it does; it is
|
|
1056
1056
|
* not a column pushdown, so it saves bandwidth rather than database work.
|
|
1057
1057
|
*
|
|
1058
|
-
*
|
|
1059
|
-
* the admin table, realtime reconciliation, the offline
|
|
1060
|
-
* arrives without one is not a smaller row, it is an
|
|
1061
|
-
* `fields=title` and being unable to open the record
|
|
1062
|
-
* answer than one extra key.
|
|
1058
|
+
* The collection's key always survives. Rows are addressed by it everywhere
|
|
1059
|
+
* above this layer — the admin table, realtime reconciliation, the offline
|
|
1060
|
+
* cache — and a row that arrives without one is not a smaller row, it is an
|
|
1061
|
+
* unusable one. Asking for `fields=title` and being unable to open the record
|
|
1062
|
+
* you clicked is a worse answer than one extra key.
|
|
1063
|
+
*
|
|
1064
|
+
* That is a statement about the key, not about the name `id`: a collection
|
|
1065
|
+
* keyed on `slug`, or on `user_id + role_id`, was projected down to the fields
|
|
1066
|
+
* asked for and nothing else, which is the very outcome the paragraph above
|
|
1067
|
+
* describes. `assertKnownWriteFields` one function up already has a dedicated
|
|
1068
|
+
* error for collections with no `id` column, so this layer had no excuse for
|
|
1069
|
+
* assuming one.
|
|
1063
1070
|
*/
|
|
1064
1071
|
function projectResponseFields(rows, fields, collection, options) {
|
|
1065
1072
|
if (!fields || fields.length === 0) return rows;
|
|
@@ -1077,7 +1084,8 @@ function projectResponseFields(rows, fields, collection, options) {
|
|
|
1077
1084
|
collection: collection.slug
|
|
1078
1085
|
});
|
|
1079
1086
|
}
|
|
1080
|
-
const
|
|
1087
|
+
const primaryKeys = resolvePrimaryKeys(collection).map((key) => key.fieldName);
|
|
1088
|
+
const keep = /* @__PURE__ */ new Set([...fields, ...primaryKeys.length > 0 ? primaryKeys : ["id"]]);
|
|
1081
1089
|
return rows.map((row) => {
|
|
1082
1090
|
const projected = {};
|
|
1083
1091
|
for (const key of Object.keys(row)) if (keep.has(key)) projected[key] = row[key];
|
|
@@ -1161,26 +1169,43 @@ function createIdempotencyStore(driver) {
|
|
|
1161
1169
|
return ready;
|
|
1162
1170
|
};
|
|
1163
1171
|
return {
|
|
1164
|
-
async
|
|
1165
|
-
if (!key || !await ensure()) return
|
|
1172
|
+
async claim(key, uid) {
|
|
1173
|
+
if (!key || !await ensure()) return { status: "claimed" };
|
|
1166
1174
|
try {
|
|
1167
|
-
|
|
1168
|
-
|
|
1175
|
+
if ((await exec(`INSERT INTO ${TABLE} (key, uid, response, created_at)
|
|
1176
|
+
VALUES ($1, $2, NULL, NOW())
|
|
1177
|
+
ON CONFLICT (uid, key) DO UPDATE
|
|
1178
|
+
SET response = NULL, created_at = NOW()
|
|
1179
|
+
WHERE ${TABLE}.created_at < NOW() - INTERVAL '${TTL_HOURS} hours'
|
|
1180
|
+
RETURNING 1 AS claimed`, [key, principal(uid)])).length > 0) return { status: "claimed" };
|
|
1181
|
+
const row = (await exec(`SELECT response, response IS NULL AS pending FROM ${TABLE}
|
|
1182
|
+
WHERE uid = $1 AND key = $2`, [principal(uid), key]))[0];
|
|
1183
|
+
if (!row) return { status: "claimed" };
|
|
1184
|
+
if (row.pending) return { status: "in-flight" };
|
|
1185
|
+
return {
|
|
1186
|
+
status: "replay",
|
|
1187
|
+
response: row.response
|
|
1188
|
+
};
|
|
1169
1189
|
} catch {
|
|
1170
|
-
return;
|
|
1190
|
+
return { status: "claimed" };
|
|
1171
1191
|
}
|
|
1172
1192
|
},
|
|
1173
|
-
async
|
|
1193
|
+
async complete(key, uid, response) {
|
|
1174
1194
|
if (!key || !await ensure()) return;
|
|
1175
1195
|
try {
|
|
1176
|
-
await exec(`
|
|
1177
|
-
ON CONFLICT (uid, key) DO NOTHING`, [
|
|
1178
|
-
key,
|
|
1196
|
+
await exec(`UPDATE ${TABLE} SET response = $3::jsonb WHERE uid = $1 AND key = $2`, [
|
|
1179
1197
|
principal(uid),
|
|
1198
|
+
key,
|
|
1180
1199
|
JSON.stringify(response ?? null)
|
|
1181
1200
|
]);
|
|
1182
1201
|
if (Math.random() < .01) await exec(`DELETE FROM ${TABLE} WHERE created_at < NOW() - INTERVAL '${TTL_HOURS} hours'`);
|
|
1183
1202
|
} catch {}
|
|
1203
|
+
},
|
|
1204
|
+
async release(key, uid) {
|
|
1205
|
+
if (!key || !await ensure()) return;
|
|
1206
|
+
try {
|
|
1207
|
+
await exec(`DELETE FROM ${TABLE} WHERE uid = $1 AND key = $2 AND response IS NULL`, [principal(uid), key]);
|
|
1208
|
+
} catch {}
|
|
1184
1209
|
}
|
|
1185
1210
|
};
|
|
1186
1211
|
}
|
|
@@ -1395,92 +1420,83 @@ var RestApiGenerator = class {
|
|
|
1395
1420
|
});
|
|
1396
1421
|
});
|
|
1397
1422
|
this.router.post(basePath, async (c) => {
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
const prepared = await this.authAdapter.prepareUserCreation(body, collectionAuthConfig);
|
|
1413
|
-
const entity = await driver.save({
|
|
1414
|
-
path,
|
|
1415
|
-
values: prepared.values,
|
|
1416
|
-
collection: resolvedCollection,
|
|
1417
|
-
status: "new"
|
|
1418
|
-
});
|
|
1419
|
-
const result = prepared.hookHandledEmail ? {
|
|
1420
|
-
temporaryPassword: prepared.clearPassword,
|
|
1421
|
-
invitationSent: prepared.invitationSent
|
|
1422
|
-
} : this.authAdapter.finalizeUserCreation ? await this.authAdapter.finalizeUserCreation({
|
|
1423
|
-
id: entity.id,
|
|
1424
|
-
values: entity
|
|
1425
|
-
}, prepared.clearPassword) : { invitationSent: false };
|
|
1426
|
-
const response = this.formatResponse(entity);
|
|
1427
|
-
return c.json({
|
|
1428
|
-
...response,
|
|
1429
|
-
invitationSent: result.invitationSent,
|
|
1430
|
-
...result.temporaryPassword ? { temporaryPassword: result.temporaryPassword } : {},
|
|
1431
|
-
..."emailDeliveryFailed" in result && result.emailDeliveryFailed ? { emailDeliveryFailed: true } : {}
|
|
1432
|
-
}, 201);
|
|
1433
|
-
}
|
|
1434
|
-
const idempotencyKey = c.req.header(IDEMPOTENCY_HEADER);
|
|
1435
|
-
const uid = c.get("user")?.uid;
|
|
1436
|
-
const store = this.idempotency();
|
|
1437
|
-
if (idempotencyKey && store) {
|
|
1438
|
-
const already = await store.recall(idempotencyKey, uid);
|
|
1439
|
-
if (already !== void 0) return c.json(already, 201);
|
|
1440
|
-
}
|
|
1423
|
+
this.enforceApiKeyPermission(c, collection.slug);
|
|
1424
|
+
const driver = this.getScopedDriver(c);
|
|
1425
|
+
const path = collection.slug;
|
|
1426
|
+
const body = await parseJsonBody(c);
|
|
1427
|
+
const isAuth = collection.auth;
|
|
1428
|
+
const isAuthCollection = isAuth === true || isAuth && typeof isAuth === "object" && isAuth.enabled === true;
|
|
1429
|
+
const collectionAuthConfig = typeof isAuth === "object" ? isAuth : void 0;
|
|
1430
|
+
if (!isAuthCollection) assertKnownWriteFields(body, resolvedCollection);
|
|
1431
|
+
else {
|
|
1432
|
+
const contract = this.authAdapter?.describeUserCreationContract?.(collectionAuthConfig);
|
|
1433
|
+
if (contract?.validate) assertKnownWriteFields(body, resolvedCollection, { extraKnownFields: contract.extraFields });
|
|
1434
|
+
}
|
|
1435
|
+
if (isAuthCollection && this.authAdapter?.prepareUserCreation) {
|
|
1436
|
+
const prepared = await this.authAdapter.prepareUserCreation(body, collectionAuthConfig);
|
|
1441
1437
|
const entity = await driver.save({
|
|
1442
1438
|
path,
|
|
1443
|
-
values:
|
|
1439
|
+
values: prepared.values,
|
|
1444
1440
|
collection: resolvedCollection,
|
|
1445
1441
|
status: "new"
|
|
1446
1442
|
});
|
|
1443
|
+
const result = prepared.hookHandledEmail ? {
|
|
1444
|
+
temporaryPassword: prepared.clearPassword,
|
|
1445
|
+
invitationSent: prepared.invitationSent
|
|
1446
|
+
} : this.authAdapter.finalizeUserCreation ? await this.authAdapter.finalizeUserCreation({
|
|
1447
|
+
id: entity.id,
|
|
1448
|
+
values: entity
|
|
1449
|
+
}, prepared.clearPassword) : { invitationSent: false };
|
|
1447
1450
|
const response = this.formatResponse(entity);
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
}
|
|
1454
|
-
throw error;
|
|
1451
|
+
return c.json({
|
|
1452
|
+
...response,
|
|
1453
|
+
invitationSent: result.invitationSent,
|
|
1454
|
+
...result.temporaryPassword ? { temporaryPassword: result.temporaryPassword } : {},
|
|
1455
|
+
..."emailDeliveryFailed" in result && result.emailDeliveryFailed ? { emailDeliveryFailed: true } : {}
|
|
1456
|
+
}, 201);
|
|
1455
1457
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
+
const idempotencyKey = c.req.header(IDEMPOTENCY_HEADER);
|
|
1459
|
+
const uid = c.get("user")?.uid;
|
|
1460
|
+
const store = this.idempotency();
|
|
1461
|
+
const claimed = idempotencyKey && store ? await store.claim(idempotencyKey, uid) : void 0;
|
|
1462
|
+
if (claimed?.status === "replay") return c.json(claimed.response, 201);
|
|
1463
|
+
if (claimed?.status === "in-flight") throw ApiError.conflict(`A request with Idempotency-Key '${idempotencyKey}' is already in progress. Retry once it has answered; its result will be replayed.`, "IDEMPOTENCY_KEY_IN_PROGRESS");
|
|
1464
|
+
let response;
|
|
1458
1465
|
try {
|
|
1459
|
-
this.enforceApiKeyPermission(c, collection.slug);
|
|
1460
|
-
const id = c.req.param("id");
|
|
1461
|
-
const driver = this.getScopedDriver(c);
|
|
1462
|
-
if (!await driver.fetchOne({
|
|
1463
|
-
path: getCollectionDataPath(collection),
|
|
1464
|
-
id: String(id),
|
|
1465
|
-
collection: resolvedCollection
|
|
1466
|
-
})) throw ApiError.notFound("Entity not found");
|
|
1467
|
-
const body = await parseJsonBody(c);
|
|
1468
|
-
assertKnownWriteFields(body, resolvedCollection);
|
|
1469
1466
|
const entity = await driver.save({
|
|
1470
|
-
path
|
|
1471
|
-
id: String(id),
|
|
1467
|
+
path,
|
|
1472
1468
|
values: body,
|
|
1473
1469
|
collection: resolvedCollection,
|
|
1474
|
-
status: "
|
|
1470
|
+
status: "new"
|
|
1475
1471
|
});
|
|
1476
|
-
|
|
1477
|
-
return c.json(response);
|
|
1472
|
+
response = this.formatResponse(entity);
|
|
1478
1473
|
} catch (error) {
|
|
1479
|
-
if (
|
|
1480
|
-
if (!(error instanceof TypeError || error instanceof RangeError || error instanceof SyntaxError || error instanceof ReferenceError)) error.code = "BAD_REQUEST";
|
|
1481
|
-
}
|
|
1474
|
+
if (claimed?.status === "claimed" && idempotencyKey && store) await store.release(idempotencyKey, uid);
|
|
1482
1475
|
throw error;
|
|
1483
1476
|
}
|
|
1477
|
+
if (claimed?.status === "claimed" && idempotencyKey && store) await store.complete(idempotencyKey, uid, response);
|
|
1478
|
+
return c.json(response, 201);
|
|
1479
|
+
});
|
|
1480
|
+
this.router.put(`${basePath}/:id`, async (c) => {
|
|
1481
|
+
this.enforceApiKeyPermission(c, collection.slug);
|
|
1482
|
+
const id = c.req.param("id");
|
|
1483
|
+
const driver = this.getScopedDriver(c);
|
|
1484
|
+
if (!await driver.fetchOne({
|
|
1485
|
+
path: getCollectionDataPath(collection),
|
|
1486
|
+
id: String(id),
|
|
1487
|
+
collection: resolvedCollection
|
|
1488
|
+
})) throw ApiError.notFound("Entity not found");
|
|
1489
|
+
const body = await parseJsonBody(c);
|
|
1490
|
+
assertKnownWriteFields(body, resolvedCollection);
|
|
1491
|
+
const entity = await driver.save({
|
|
1492
|
+
path: getCollectionDataPath(collection),
|
|
1493
|
+
id: String(id),
|
|
1494
|
+
values: body,
|
|
1495
|
+
collection: resolvedCollection,
|
|
1496
|
+
status: "existing"
|
|
1497
|
+
});
|
|
1498
|
+
const response = this.formatResponse(entity);
|
|
1499
|
+
return c.json(response);
|
|
1484
1500
|
});
|
|
1485
1501
|
this.router.delete(`${basePath}/:id`, async (c) => {
|
|
1486
1502
|
this.enforceApiKeyPermission(c, collection.slug);
|
|
@@ -1552,6 +1568,7 @@ var RestApiGenerator = class {
|
|
|
1552
1568
|
const total = driver.count ? await driver.count({
|
|
1553
1569
|
path: parsed.collectionPath,
|
|
1554
1570
|
filter: queryOptions.where,
|
|
1571
|
+
logical: queryOptions.logical,
|
|
1555
1572
|
searchString
|
|
1556
1573
|
}) : 0;
|
|
1557
1574
|
return c.json({ count: total });
|
|
@@ -1563,7 +1580,9 @@ var RestApiGenerator = class {
|
|
|
1563
1580
|
id: parsed.id
|
|
1564
1581
|
});
|
|
1565
1582
|
if (!entity) throw ApiError.notFound("Entity not found");
|
|
1566
|
-
|
|
1583
|
+
const nestedCollection = this.resolveNestedWriteCollection(parsed.collectionPath);
|
|
1584
|
+
if (!nestedCollection) return c.json(entity);
|
|
1585
|
+
return c.json(projectResponseFields([entity], queryOptions.fields, nestedCollection, { include: queryOptions.include })[0]);
|
|
1567
1586
|
} else {
|
|
1568
1587
|
const queryDict = c.req.queries();
|
|
1569
1588
|
const queryOptions = this.parseQuery(queryDict);
|
|
@@ -1588,8 +1607,9 @@ var RestApiGenerator = class {
|
|
|
1588
1607
|
logical: queryOptions.logical,
|
|
1589
1608
|
searchString
|
|
1590
1609
|
}) : entities.length;
|
|
1610
|
+
const listCollection = this.resolveNestedWriteCollection(parsed.collectionPath);
|
|
1591
1611
|
return c.json({
|
|
1592
|
-
data: entities,
|
|
1612
|
+
data: listCollection ? projectResponseFields(entities, queryOptions.fields, listCollection, { include: queryOptions.include }) : entities,
|
|
1593
1613
|
meta: {
|
|
1594
1614
|
total,
|
|
1595
1615
|
limit: queryOptions.limit,
|
|
@@ -3081,7 +3101,7 @@ function assertStorageAccessControlConfigured(state, isProduction) {
|
|
|
3081
3101
|
//#region src/init/docs.ts
|
|
3082
3102
|
async function mountOpenApiDocs(app, basePath, enableSwagger, activeCollections, requireAuth) {
|
|
3083
3103
|
if (enableSwagger === false || activeCollections.length === 0) return;
|
|
3084
|
-
const { generateOpenApiSpec } = await import("./openapi-generator-
|
|
3104
|
+
const { generateOpenApiSpec } = await import("./openapi-generator-C-Rqz9sp.js");
|
|
3085
3105
|
app.get(`${basePath}/docs`, (c) => {
|
|
3086
3106
|
const spec = generateOpenApiSpec(activeCollections, {
|
|
3087
3107
|
basePath,
|
|
@@ -3418,6 +3438,13 @@ function resolveBaseUrl(configured) {
|
|
|
3418
3438
|
function createTransport(config, environment) {
|
|
3419
3439
|
const fetchFn = config.fetch || globalThis.fetch;
|
|
3420
3440
|
const apiPath = config.apiPath || "/api";
|
|
3441
|
+
for (const field of ["baseUrl", "storageUrlOrigin"]) {
|
|
3442
|
+
const value = config[field];
|
|
3443
|
+
if (!value || !apiPath) continue;
|
|
3444
|
+
const trimmed = value.replace(/\/+$/, "");
|
|
3445
|
+
if (!trimmed.endsWith(apiPath)) continue;
|
|
3446
|
+
console.warn(`[Rebase] ${field} ${JSON.stringify(value)} already ends with the API path ${JSON.stringify(apiPath)}, which is appended to it — requests will go to ${trimmed}${apiPath}/… and 404. Pass the origin only (${JSON.stringify(trimmed.slice(0, trimmed.length - apiPath.length) || "/")}), or set \`apiPath\` if the server really does mount the API one level deeper.`);
|
|
3447
|
+
}
|
|
3421
3448
|
let token = config.token;
|
|
3422
3449
|
let tokenGetter;
|
|
3423
3450
|
let onUnauthorizedHandler = config.onUnauthorized;
|
|
@@ -3628,7 +3655,9 @@ function createAuth(transport, options) {
|
|
|
3628
3655
|
function emit(event, session) {
|
|
3629
3656
|
for (const fn of listeners) try {
|
|
3630
3657
|
fn(event, session);
|
|
3631
|
-
} catch (e) {
|
|
3658
|
+
} catch (e) {
|
|
3659
|
+
console.error("Error in auth state change listener:", e);
|
|
3660
|
+
}
|
|
3632
3661
|
}
|
|
3633
3662
|
function saveSession(session) {
|
|
3634
3663
|
if (!persistSession || authFlowMode === "cookie") return;
|
|
@@ -4573,8 +4602,15 @@ function createCollectionClient(transport, slug, ws) {
|
|
|
4573
4602
|
},
|
|
4574
4603
|
observe(params, onResult, onError, options) {
|
|
4575
4604
|
let closed = false;
|
|
4576
|
-
|
|
4605
|
+
let liveDelivered = false;
|
|
4606
|
+
let signature;
|
|
4607
|
+
const deliver = (result, fromLive) => {
|
|
4577
4608
|
if (closed) return;
|
|
4609
|
+
if (fromLive) liveDelivered = true;
|
|
4610
|
+
else if (liveDelivered) return;
|
|
4611
|
+
const next = `${result.meta?.total ?? ""}|${JSON.stringify(result.data)}`;
|
|
4612
|
+
if (signature !== void 0 && next === signature) return;
|
|
4613
|
+
signature = next;
|
|
4578
4614
|
onResult({
|
|
4579
4615
|
...result,
|
|
4580
4616
|
fromCache: false,
|
|
@@ -4582,10 +4618,10 @@ function createCollectionClient(transport, slug, ws) {
|
|
|
4582
4618
|
partial: false
|
|
4583
4619
|
});
|
|
4584
4620
|
};
|
|
4585
|
-
client.find(params).then(
|
|
4621
|
+
client.find(params).then((result) => deliver(result, false)).catch((error) => {
|
|
4586
4622
|
if (!closed) onError?.(error);
|
|
4587
4623
|
});
|
|
4588
|
-
const live = options?.realtime !== false && client.listen ? client.listen(params,
|
|
4624
|
+
const live = options?.realtime !== false && client.listen ? client.listen(params, (result) => deliver(result, true), onError) : void 0;
|
|
4589
4625
|
return () => {
|
|
4590
4626
|
closed = true;
|
|
4591
4627
|
live?.();
|
|
@@ -4593,17 +4629,24 @@ function createCollectionClient(transport, slug, ws) {
|
|
|
4593
4629
|
},
|
|
4594
4630
|
observeById(id, onResult, onError, options) {
|
|
4595
4631
|
let closed = false;
|
|
4596
|
-
|
|
4632
|
+
let liveDelivered = false;
|
|
4633
|
+
let signature;
|
|
4634
|
+
const deliver = (row, fromLive) => {
|
|
4597
4635
|
if (closed) return;
|
|
4636
|
+
if (fromLive) liveDelivered = true;
|
|
4637
|
+
else if (liveDelivered) return;
|
|
4638
|
+
const next = row === void 0 ? "\0missing" : JSON.stringify(row);
|
|
4639
|
+
if (signature !== void 0 && next === signature) return;
|
|
4640
|
+
signature = next;
|
|
4598
4641
|
onResult(row, {
|
|
4599
4642
|
fromCache: false,
|
|
4600
4643
|
hasPendingWrites: false
|
|
4601
4644
|
});
|
|
4602
4645
|
};
|
|
4603
|
-
client.findById(id).then(
|
|
4646
|
+
client.findById(id).then((row) => deliver(row, false)).catch((error) => {
|
|
4604
4647
|
if (!closed) onError?.(error);
|
|
4605
4648
|
});
|
|
4606
|
-
const live = options?.realtime !== false && client.listenById ? client.listenById(id,
|
|
4649
|
+
const live = options?.realtime !== false && client.listenById ? client.listenById(id, (row) => deliver(row, true), onError) : void 0;
|
|
4607
4650
|
return () => {
|
|
4608
4651
|
closed = true;
|
|
4609
4652
|
live?.();
|
|
@@ -4634,51 +4677,43 @@ function createCollectionClient(transport, slug, ws) {
|
|
|
4634
4677
|
client.listen = (params, onUpdate, onError) => {
|
|
4635
4678
|
let active = true;
|
|
4636
4679
|
let lastUpdateId = 0;
|
|
4680
|
+
let lastKnownTotal;
|
|
4681
|
+
const window = resolveFindWindow(params);
|
|
4637
4682
|
const unsub = ws.listenCollection({
|
|
4638
4683
|
path: slug,
|
|
4639
4684
|
filter: params?.where,
|
|
4685
|
+
logical: params?.logical,
|
|
4640
4686
|
limit: params?.limit,
|
|
4641
|
-
|
|
4687
|
+
offset: window.driverOffset,
|
|
4642
4688
|
orderBy: params?.orderBy?.[0],
|
|
4643
4689
|
order: params?.orderBy?.[1],
|
|
4644
4690
|
searchString: params?.searchString
|
|
4645
4691
|
}, (incomingRows) => {
|
|
4646
4692
|
const currentUpdateId = ++lastUpdateId;
|
|
4647
|
-
const requestedLimit =
|
|
4648
|
-
const offset =
|
|
4693
|
+
const requestedLimit = window.limit;
|
|
4694
|
+
const offset = window.offset;
|
|
4649
4695
|
const rows = incomingRows;
|
|
4650
|
-
const
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
if (active && currentUpdateId === lastUpdateId) onUpdate({
|
|
4696
|
+
const emit = (total, hasMore) => {
|
|
4697
|
+
if (!active || currentUpdateId !== lastUpdateId) return;
|
|
4698
|
+
onUpdate({
|
|
4654
4699
|
data: rows,
|
|
4655
4700
|
meta: {
|
|
4656
4701
|
total,
|
|
4657
4702
|
limit: requestedLimit,
|
|
4658
4703
|
offset,
|
|
4659
|
-
hasMore
|
|
4704
|
+
hasMore
|
|
4660
4705
|
}
|
|
4661
4706
|
});
|
|
4707
|
+
};
|
|
4708
|
+
const emitWithoutCount = () => emit(offset + rows.length, rows.length >= requestedLimit);
|
|
4709
|
+
if (client.count) client.count(params).then((total) => {
|
|
4710
|
+
lastKnownTotal = total;
|
|
4711
|
+
emit(total, offset + rows.length < total);
|
|
4662
4712
|
}).catch(() => {
|
|
4663
|
-
if (
|
|
4664
|
-
|
|
4665
|
-
meta: {
|
|
4666
|
-
total: heuristicTotal,
|
|
4667
|
-
limit: requestedLimit,
|
|
4668
|
-
offset,
|
|
4669
|
-
hasMore: heuristicHasMore
|
|
4670
|
-
}
|
|
4671
|
-
});
|
|
4672
|
-
});
|
|
4673
|
-
else onUpdate({
|
|
4674
|
-
data: rows,
|
|
4675
|
-
meta: {
|
|
4676
|
-
total: heuristicTotal,
|
|
4677
|
-
limit: requestedLimit,
|
|
4678
|
-
offset,
|
|
4679
|
-
hasMore: heuristicHasMore
|
|
4680
|
-
}
|
|
4713
|
+
if (lastKnownTotal !== void 0) emit(lastKnownTotal, offset + rows.length < lastKnownTotal);
|
|
4714
|
+
else emitWithoutCount();
|
|
4681
4715
|
});
|
|
4716
|
+
else emitWithoutCount();
|
|
4682
4717
|
}, onError);
|
|
4683
4718
|
return () => {
|
|
4684
4719
|
active = false;
|
|
@@ -6061,15 +6096,10 @@ var RebaseWebSocketClient = class {
|
|
|
6061
6096
|
}
|
|
6062
6097
|
}
|
|
6063
6098
|
createCollectionSubscriptionKey(props) {
|
|
6099
|
+
const { collection, ...query } = props;
|
|
6064
6100
|
const key = {
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
limit: props.limit,
|
|
6068
|
-
startAfter: props.startAfter,
|
|
6069
|
-
orderBy: props.orderBy,
|
|
6070
|
-
order: props.order,
|
|
6071
|
-
searchString: props.searchString,
|
|
6072
|
-
collection: props.collection?.name
|
|
6101
|
+
...query,
|
|
6102
|
+
collection: collection?.name
|
|
6073
6103
|
};
|
|
6074
6104
|
return JSON.stringify(key, (_, value) => {
|
|
6075
6105
|
if (value && typeof value === "object" && !Array.isArray(value)) return Object.keys(value).sort().reduce((sorted, k) => {
|
|
@@ -7121,12 +7151,20 @@ function sortRows(rows, orderBy) {
|
|
|
7121
7151
|
function tiebreak(a, b) {
|
|
7122
7152
|
return compareValues(a.id, b.id) ?? 0;
|
|
7123
7153
|
}
|
|
7124
|
-
/**
|
|
7154
|
+
/**
|
|
7155
|
+
* Resolve `page`/`offset`/`limit` the way the server does.
|
|
7156
|
+
*
|
|
7157
|
+
* It did not: this defaulted an absent limit to 20 while `/api/data` pages by
|
|
7158
|
+
* 50, so the same `observe()` answered with 20 rows from the local database and
|
|
7159
|
+
* 50 from the network — a list that changed length depending on which side
|
|
7160
|
+
* answered, with `page` striding differently on each. Delegated now, so the
|
|
7161
|
+
* sentence above is true by construction rather than by agreement.
|
|
7162
|
+
*/
|
|
7125
7163
|
function resolvePagination(params) {
|
|
7126
|
-
const limit = params
|
|
7164
|
+
const { limit, offset } = resolveFindWindow(params);
|
|
7127
7165
|
return {
|
|
7128
7166
|
limit,
|
|
7129
|
-
offset
|
|
7167
|
+
offset
|
|
7130
7168
|
};
|
|
7131
7169
|
}
|
|
7132
7170
|
/**
|
|
@@ -7748,9 +7786,8 @@ var OfflineManager = class {
|
|
|
7748
7786
|
if (!state) return {
|
|
7749
7787
|
data: [],
|
|
7750
7788
|
meta: {
|
|
7789
|
+
...resolvePagination(params),
|
|
7751
7790
|
total: 0,
|
|
7752
|
-
limit: params?.limit ?? 20,
|
|
7753
|
-
offset: params?.offset ?? 0,
|
|
7754
7791
|
hasMore: false
|
|
7755
7792
|
},
|
|
7756
7793
|
fromCache: true,
|
|
@@ -7942,17 +7979,17 @@ var OfflineManager = class {
|
|
|
7942
7979
|
return row;
|
|
7943
7980
|
}
|
|
7944
7981
|
recordSnapshot(slug, params, result) {
|
|
7982
|
+
const window = resolvePagination(params);
|
|
7945
7983
|
const meta = result.meta ?? {
|
|
7946
7984
|
total: result.data?.length ?? 0,
|
|
7947
|
-
|
|
7948
|
-
offset: 0,
|
|
7985
|
+
...window,
|
|
7949
7986
|
hasMore: false
|
|
7950
7987
|
};
|
|
7951
7988
|
const snapshot = {
|
|
7952
7989
|
ids: (result.data ?? []).map((row) => row.id).filter((id) => id !== void 0),
|
|
7953
7990
|
total: meta.total ?? result.data?.length ?? 0,
|
|
7954
|
-
limit: meta.limit ??
|
|
7955
|
-
offset: meta.offset ??
|
|
7991
|
+
limit: meta.limit ?? window.limit,
|
|
7992
|
+
offset: meta.offset ?? window.offset,
|
|
7956
7993
|
hasMore: meta.hasMore ?? false
|
|
7957
7994
|
};
|
|
7958
7995
|
const state = this.collectionState(slug);
|
|
@@ -8414,23 +8451,37 @@ var OfflineManager = class {
|
|
|
8414
8451
|
/**
|
|
8415
8452
|
* Derive a WebSocket URL from an HTTP base URL.
|
|
8416
8453
|
* `http://` → `ws://`, `https://` → `wss://`.
|
|
8454
|
+
*
|
|
8455
|
+
* A backend mounted under a path is the reason `baseUrl` accepts one, so the
|
|
8456
|
+
* path is kept. It used to be kept for an absolute `baseUrl` and dropped for a
|
|
8457
|
+
* relative one — resolved through `.origin` — so one deployment dialled two
|
|
8458
|
+
* different sockets depending on whether its config said `"/backend"` or
|
|
8459
|
+
* `"https://app.example.com/backend"`.
|
|
8460
|
+
*
|
|
8461
|
+
* Returns `""` when there is nothing to resolve against: a relative `baseUrl`
|
|
8462
|
+
* outside a browser has no origin, and inventing one would dial somewhere
|
|
8463
|
+
* arbitrary. The caller warns rather than leaving that silent.
|
|
8417
8464
|
*/
|
|
8418
8465
|
function deriveWebSocketUrl(baseUrl) {
|
|
8466
|
+
const toWsProtocol = (url) => {
|
|
8467
|
+
const secure = /^(https|wss):/i.test(url);
|
|
8468
|
+
return url.replace(/^https?:\/\//i, secure ? "wss://" : "ws://").replace(/^wss?:\/\//i, secure ? "wss://" : "ws://").replace(/\/$/, "");
|
|
8469
|
+
};
|
|
8419
8470
|
if (typeof window !== "undefined") {
|
|
8420
|
-
let absoluteUrl
|
|
8471
|
+
let absoluteUrl;
|
|
8421
8472
|
if (!baseUrl) absoluteUrl = window.location.origin;
|
|
8422
8473
|
else if (/^https?:\/\//i.test(baseUrl) || /^wss?:\/\//i.test(baseUrl)) absoluteUrl = baseUrl;
|
|
8423
8474
|
else try {
|
|
8424
|
-
|
|
8475
|
+
const resolved = new URL(baseUrl, window.location.href);
|
|
8476
|
+
absoluteUrl = resolved.origin + resolved.pathname;
|
|
8425
8477
|
} catch {
|
|
8426
8478
|
absoluteUrl = window.location.origin;
|
|
8427
8479
|
}
|
|
8428
|
-
|
|
8429
|
-
return absoluteUrl.replace(/^https?:\/\//i, `${protocol}//`).replace(/^wss?:\/\//i, `${protocol}//`).replace(/\/$/, "");
|
|
8480
|
+
return toWsProtocol(absoluteUrl);
|
|
8430
8481
|
}
|
|
8431
8482
|
if (!baseUrl) return "";
|
|
8432
8483
|
if (!/^https?:\/\//i.test(baseUrl) && !/^wss?:\/\//i.test(baseUrl)) return "";
|
|
8433
|
-
return baseUrl
|
|
8484
|
+
return toWsProtocol(baseUrl);
|
|
8434
8485
|
}
|
|
8435
8486
|
function createRebaseClient(options) {
|
|
8436
8487
|
const transport = createTransport(options, { credentialOutOfBand: options.auth?.authFlowMode === "cookie" });
|
|
@@ -8458,7 +8509,11 @@ function createRebaseClient(options) {
|
|
|
8458
8509
|
});
|
|
8459
8510
|
return storageSourcesPromise;
|
|
8460
8511
|
};
|
|
8461
|
-
const
|
|
8512
|
+
const realtimeEnabled = options.realtime !== false;
|
|
8513
|
+
const resolvedWsUrl = realtimeEnabled ? options.websocketUrl ?? deriveWebSocketUrl(options.baseUrl) : void 0;
|
|
8514
|
+
const realtimeUnreachable = realtimeEnabled && !resolvedWsUrl;
|
|
8515
|
+
const unreachableReason = `no WebSocket URL could be derived from baseUrl ${JSON.stringify(options.baseUrl ?? null)} — outside a browser there is no page origin to resolve a relative URL against. Pass an absolute \`baseUrl\`, set \`websocketUrl\` explicitly, or pass \`realtime: false\` to say this was intended.`;
|
|
8516
|
+
if (realtimeUnreachable) console.warn(`[Rebase] Realtime is enabled but ${unreachableReason} Live queries will fall back to a single fetch and channels will throw.`);
|
|
8462
8517
|
let ws;
|
|
8463
8518
|
/** One channel object per name — see `realtime.channel`. */
|
|
8464
8519
|
const realtimeChannels = /* @__PURE__ */ new Map();
|
|
@@ -8578,7 +8633,7 @@ function createRebaseClient(options) {
|
|
|
8578
8633
|
* cut off the others.
|
|
8579
8634
|
*/
|
|
8580
8635
|
channel: (name, options) => {
|
|
8581
|
-
if (!ws) throw new RebaseClientError("Realtime is disabled on this client (realtime: false), so channels are unavailable.");
|
|
8636
|
+
if (!ws) throw new RebaseClientError(realtimeUnreachable ? `Realtime is enabled but ${unreachableReason}` : "Realtime is disabled on this client (realtime: false), so channels are unavailable.");
|
|
8582
8637
|
let existing = realtimeChannels.get(name);
|
|
8583
8638
|
if (!existing) {
|
|
8584
8639
|
existing = new RebaseRealtimeChannel(name, ws, options);
|
|
@@ -9249,7 +9304,7 @@ async function _initializeRebaseBackend(config) {
|
|
|
9249
9304
|
]) {
|
|
9250
9305
|
const providerConfig = safeAuthConfig[key];
|
|
9251
9306
|
if (providerConfig && requiredFields.every((f) => Boolean(providerConfig[f]))) {
|
|
9252
|
-
const createFn = (await import("./auth-
|
|
9307
|
+
const createFn = (await import("./auth-BE_FSK1l.js").then((n) => n.t))[factory];
|
|
9253
9308
|
oauthProviders.push(createFn(providerConfig));
|
|
9254
9309
|
}
|
|
9255
9310
|
}
|
|
@@ -9343,7 +9398,7 @@ async function _initializeRebaseBackend(config) {
|
|
|
9343
9398
|
let schemaEditorOff = schemaEditorUnavailable();
|
|
9344
9399
|
let schemaEditorRoutes;
|
|
9345
9400
|
if (!schemaEditorOff && config.collectionsDir) try {
|
|
9346
|
-
schemaEditorRoutes = (await import("./schema-editor-routes-
|
|
9401
|
+
schemaEditorRoutes = (await import("./schema-editor-routes-C1DxDnDR.js")).createSchemaEditorRoutes(config.collectionsDir);
|
|
9347
9402
|
} catch (err) {
|
|
9348
9403
|
if (err?.code === "ERR_MODULE_NOT_FOUND") {
|
|
9349
9404
|
schemaEditorOff = {
|
|
@@ -9556,9 +9611,9 @@ async function _initializeRebaseBackend(config) {
|
|
|
9556
9611
|
let cronScheduler;
|
|
9557
9612
|
if (config.cronsDir) {
|
|
9558
9613
|
const { loadCronJobsFromDirectory } = await import("./cron-loader-B1S2MCSl.js").then((n) => n.t);
|
|
9559
|
-
const { CronScheduler } = await import("./cron-scheduler-
|
|
9560
|
-
const { createCronRoutes } = await import("./cron-routes-
|
|
9561
|
-
const { createCronStore } = await import("./cron-store-
|
|
9614
|
+
const { CronScheduler } = await import("./cron-scheduler-BhFZWR0T.js").then((n) => n.n);
|
|
9615
|
+
const { createCronRoutes } = await import("./cron-routes-D5a9v1HY.js").then((n) => n.n);
|
|
9616
|
+
const { createCronStore } = await import("./cron-store-Cu4sOseb.js").then((n) => n.n);
|
|
9562
9617
|
const loadedCronJobs = await loadCronJobsFromDirectory(config.cronsDir);
|
|
9563
9618
|
cronScheduler = new CronScheduler();
|
|
9564
9619
|
cronScheduler.setClient(serverClient);
|
|
@@ -9583,7 +9638,7 @@ async function _initializeRebaseBackend(config) {
|
|
|
9583
9638
|
} else logger.warn(`Cron routes mounted at ${basePath}/cron, but no jobs loaded from ${config.cronsDir}. Nothing is scheduled — check the messages above for files that failed to load.`);
|
|
9584
9639
|
}
|
|
9585
9640
|
{
|
|
9586
|
-
const { createBackupRoutes, parseBackupDestination } = await import("./backup-
|
|
9641
|
+
const { createBackupRoutes, parseBackupDestination } = await import("./backup-BJiY_mM-.js").then((n) => n.t);
|
|
9587
9642
|
const backupRouter = new Hono();
|
|
9588
9643
|
applyAdminGate(backupRouter, "Backup");
|
|
9589
9644
|
backupRouter.route("/", createBackupRoutes({
|
|
@@ -11785,7 +11840,8 @@ async function bootFromBundle(options = {}) {
|
|
|
11785
11840
|
});
|
|
11786
11841
|
await ensureCollectionPolicies(bundle, dataSources, env);
|
|
11787
11842
|
metrics?.setKnownCollections(backend.collectionRegistry.getCollections().map((collection) => collection.slug).filter((slug) => Boolean(slug)));
|
|
11788
|
-
|
|
11843
|
+
const healthPaths = ["/health", `${(env.REBASE_BASE_PATH || "/api").replace(/\/$/, "")}/health`];
|
|
11844
|
+
for (const healthPath of [...new Set(healthPaths)]) app.get(healthPath, async (c) => {
|
|
11789
11845
|
const result = await backend.healthCheck();
|
|
11790
11846
|
const unhealthy = (await Promise.all(dataSources.filter((source) => source.key !== DEFAULT_DATA_SOURCE_KEY).map(async (source) => ({
|
|
11791
11847
|
key: source.key,
|
|
@@ -11891,7 +11947,7 @@ async function bootStaticApp(bundle, devRoot, options) {
|
|
|
11891
11947
|
if (metrics) app.use("/*", metrics.middleware);
|
|
11892
11948
|
const server = createServer(getRequestListener(app.fetch));
|
|
11893
11949
|
app.get("/livez", (c) => c.json({ status: "ok" }));
|
|
11894
|
-
|
|
11950
|
+
for (const healthPath of [.../* @__PURE__ */ new Set(["/health", `${basePath.replace(/\/$/, "")}/health`])]) app.get(healthPath, (c) => c.json({
|
|
11895
11951
|
status: "ok",
|
|
11896
11952
|
latencyMs: 0
|
|
11897
11953
|
}));
|
|
@@ -12109,6 +12165,6 @@ async function ensureCollectionPolicies(bundle, dataSources, env) {
|
|
|
12109
12165
|
logger.info(applied > 0 ? `Applied ${applied} RLS policy statement(s) before serving.` : "RLS policies are up to date.");
|
|
12110
12166
|
}
|
|
12111
12167
|
//#endregion
|
|
12112
|
-
export { ApiError, BundleError, CronScheduler, DEFAULT_DRIVER_ID, DEFAULT_MAX_FILE_SIZE, DEFAULT_STORAGE_ID, DOCUMENT_MIME_TYPES, DefaultDriverRegistry, DefaultStorageRegistry, GCSStorageController, IMAGE_MIME_TYPES, LocalStorageController, MetricsRegistry, S3StorageController, SMTPEmailService, TransformCache, TusHandler, WebhookDispatcher, _resetRebaseMock, _setRebaseMock, applyCollectionDefaults, assertCollectionConfigs, assertDistinctSuffixes, authJwt, authRoles, authUid, bootFromBundle, classifySurface, cleanupDevPortFile, createAppleProvider, createBackupRoutes, createBitbucketProvider, createBuiltinAuthAdapter, createContractRoutes, createCronRoutes, createCronStore, createCustomAuthAdapter, createDiscordProvider, createEmailService, createFacebookProvider, createFunctionRoutes, createGitHubProvider, createGitLabProvider, createGoogleProvider, createHistoryRoutes, createLinkedinProvider, createMetricsMiddleware, createMetricsRoutes, createMicrosoftProvider, createSlackProvider, createSourceBundle, createSpotifyProvider, createStorageController, createStorageRoutes, createTwitterProvider, defineCron, defineFunction, envSuffixForKey, errorHandler, extractUserFromToken, fileTokenAuth, findCollectionConfigProblems, generateSecurePassword, getEmailVerificationTemplate, getMagicLinkTemplate, getPasswordResetTemplate, getUserInvitationTemplate, getWelcomeEmailTemplate, hashPassword, httpMethodToOperation, initializeDataSource, initializeDataSources, initializeRebaseBackend, installShutdownHandlers, isApiKeyToken, isAuthAdapter, isDatabaseAdapter, isLocalhostOrigin, isOperationAllowed,
|
|
12168
|
+
export { ApiError, BundleError, CronScheduler, DEFAULT_DRIVER_ID, DEFAULT_MAX_FILE_SIZE, DEFAULT_STORAGE_ID, DOCUMENT_MIME_TYPES, DefaultDriverRegistry, DefaultStorageRegistry, GCSStorageController, IMAGE_MIME_TYPES, LocalStorageController, MetricsRegistry, S3StorageController, SMTPEmailService, TransformCache, TusHandler, WebhookDispatcher, _resetRebaseMock, _setRebaseMock, applyCollectionDefaults, assertCollectionConfigs, assertDistinctSuffixes, authJwt, authRoles, authUid, bootFromBundle, classifySurface, cleanupDevPortFile, createAppleProvider, createBackupRoutes, createBitbucketProvider, createBuiltinAuthAdapter, createContractRoutes, createCronRoutes, createCronStore, createCustomAuthAdapter, createDiscordProvider, createEmailService, createFacebookProvider, createFunctionRoutes, createGitHubProvider, createGitLabProvider, createGoogleProvider, createHistoryRoutes, createLinkedinProvider, createMetricsMiddleware, createMetricsRoutes, createMicrosoftProvider, createSlackProvider, createSourceBundle, createSpotifyProvider, createStorageController, createStorageRoutes, createTwitterProvider, defineCron, defineFunction, envSuffixForKey, errorHandler, extractUserFromToken, fileTokenAuth, findCollectionConfigProblems, generateSecurePassword, getEmailVerificationTemplate, getMagicLinkTemplate, getPasswordResetTemplate, getUserInvitationTemplate, getWelcomeEmailTemplate, hashPassword, httpMethodToOperation, initializeDataSource, initializeDataSources, initializeRebaseBackend, installShutdownHandlers, isApiKeyToken, isAuthAdapter, isDatabaseAdapter, isLocalhostOrigin, isOperationAllowed, isTransformableImage, listBackupObjects, listenWithPortRetry, loadBootEnv, loadBundle, loadBundleConfigExports, loadBundleSchema, loadCollectionsFromDirectory, loadCronJobsFromDirectory, loadDeclaredStorageSources, loadEnv, loadFunctionsFromDirectory, loadUsersCollection, logger, optionalAuth, parseBackupDestination, parseBackupTimestamp, parseTransformOptions, queryTokenAuth, readBackupBytes, readBundleManifest, rebase, requireAdmin, requireAuth, resolveAuthHooks, resolveAuthOptions, resolveCorsOrigin, resolveDataSources, resolveEmailOptions, resolveRequireAuth, resolveStorageBackend, resolveStorageSources, runFromBundle, safeCompare, serveSPA, transformImage, unknownKeyPolicyFromEnv, validateApiKey, validateCronExpression, validatePasswordStrength, verifyPassword };
|
|
12113
12169
|
|
|
12114
12170
|
//# sourceMappingURL=index.es.js.map
|