@rebasepro/server 0.24.0 → 0.24.1-canary.gcb918fc
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/README.md +27 -2
- package/dist/GCSStorageController-fv6JAZ87.js +402 -0
- package/dist/GCSStorageController-fv6JAZ87.js.map +1 -0
- package/dist/S3StorageController-BNg-pXiY.js +480 -0
- package/dist/S3StorageController-BNg-pXiY.js.map +1 -0
- package/dist/api/mount-path.d.ts +30 -0
- package/dist/api/mount.d.ts +6 -13
- package/dist/api/rest/api-generator.d.ts +53 -1
- package/dist/api/rest/auth-collection-writes.d.ts +28 -21
- package/dist/api/rest/field-access-query.d.ts +28 -8
- package/dist/api/rest/field-ops.d.ts +19 -7
- package/dist/api/rest/query-body.d.ts +10 -0
- package/dist/api/rest/write-validation.d.ts +7 -5
- package/dist/api/schema-editor-routes.d.ts +10 -1
- package/dist/api/sql-export-routes.d.ts +8 -0
- package/dist/api/types.d.ts +35 -0
- package/dist/{ast-schema-editor-CWqS_sLJ.js → ast-schema-editor-mCeSC03x.js} +3 -3
- package/dist/{ast-schema-editor-CWqS_sLJ.js.map → ast-schema-editor-mCeSC03x.js.map} +1 -1
- package/dist/auth/access.d.ts +57 -8
- package/dist/auth/admin-user-ops.d.ts +24 -2
- package/dist/auth/admin-users-route.d.ts +1 -0
- package/dist/auth/api-keys/api-key-middleware.d.ts +10 -3
- package/dist/auth/api-keys/api-key-routes.d.ts +4 -1
- package/dist/auth/builtin-auth-adapter.d.ts +13 -0
- package/dist/auth/email-change-routes.d.ts +3 -0
- package/dist/auth/expired-token-sweep.d.ts +5 -1
- package/dist/auth/interfaces.d.ts +10 -0
- package/dist/auth/jwks-routes.d.ts +5 -1
- package/dist/auth/jwt-crypto.d.ts +7 -0
- package/dist/auth/jwt-keys.d.ts +4 -0
- package/dist/auth/jwt.d.ts +282 -166
- package/dist/auth/magic-link-routes.d.ts +3 -0
- package/dist/auth/mfa-crypto.d.ts +9 -3
- package/dist/auth/mfa-gate.d.ts +4 -2
- package/dist/auth/mfa-routes.d.ts +6 -0
- package/dist/auth/middleware.d.ts +9 -2
- package/dist/auth/otp-routes.d.ts +3 -0
- package/dist/auth/rate-limiter.d.ts +61 -34
- package/dist/auth/registration-policy.d.ts +17 -0
- package/dist/auth/require-auth.d.ts +1 -1
- package/dist/auth/routes.d.ts +16 -0
- package/dist/auth/session-routes.d.ts +6 -0
- package/dist/auth/user-picking.d.ts +37 -0
- package/dist/auth/verify-credential.d.ts +25 -4
- package/dist/{auth-DMLngxn_.js → auth-GnONzteu.js} +2869 -1871
- package/dist/auth-GnONzteu.js.map +1 -0
- package/dist/auth_adapter-CIItCTc8.js +21 -0
- package/dist/auth_adapter-CIItCTc8.js.map +1 -0
- package/dist/backend/create-backend.d.ts +281 -0
- package/dist/backend/default-backend.d.ts +35 -0
- package/dist/backend/options.d.ts +912 -0
- package/dist/backend/scope.d.ts +23 -0
- package/dist/backend/services.d.ts +54 -0
- package/dist/backend-DTAOsLQc.js.map +1 -1
- package/dist/backup/backup-common.d.ts +14 -3
- package/dist/backup/backup-routes.d.ts +23 -2
- package/dist/backup/backup-storage.d.ts +3 -1
- package/dist/backup/index.d.ts +3 -1
- package/dist/{backup-CN0s50D2.js → backup-BnvkSLHi.js} +176 -35
- package/dist/backup-BnvkSLHi.js.map +1 -0
- package/dist/boot/boot.d.ts +2 -2
- package/dist/boot/driver.d.ts +3 -0
- package/dist/boot/env.d.ts +9 -2
- package/dist/boot/http-server.d.ts +22 -0
- package/dist/boot/options.d.ts +16 -1
- package/dist/boot/provision.d.ts +4 -2
- package/dist/boot/runtime-cors.d.ts +17 -0
- package/dist/boot/sources.d.ts +2 -0
- package/dist/boot/static-routing.d.ts +9 -0
- package/dist/{contract-routes-fz8i4pxs.js → contract-routes-Ey6ftnKH.js} +4 -20
- package/dist/contract-routes-Ey6ftnKH.js.map +1 -0
- package/dist/cron/cron-loader.d.ts +77 -18
- package/dist/cron/cron-routes.d.ts +1 -1
- package/dist/cron/cron-scheduler.d.ts +69 -3
- package/dist/cron/cron-store.d.ts +33 -5
- package/dist/cron/define-cron.d.ts +6 -2
- package/dist/cron/index.d.ts +3 -3
- package/dist/cron-loader-B-u0snqq.js +202 -0
- package/dist/cron-loader-B-u0snqq.js.map +1 -0
- package/dist/{cron-routes-Bc-SB0Se.js → cron-routes-OD6BstUj.js} +27 -4
- package/dist/cron-routes-OD6BstUj.js.map +1 -0
- package/dist/{cron-scheduler-CYQgco86.js → cron-scheduler-idtLPoN-.js} +299 -33
- package/dist/cron-scheduler-idtLPoN-.js.map +1 -0
- package/dist/cron-store-CZ30ZBi-.js +577 -0
- package/dist/cron-store-CZ30ZBi-.js.map +1 -0
- package/dist/email/smtp-email-service.d.ts +23 -0
- package/dist/email/types.d.ts +18 -0
- package/dist/env.d.ts +0 -37
- package/dist/filter-dialect-O1HK6Nvr.js +1628 -0
- package/dist/filter-dialect-O1HK6Nvr.js.map +1 -0
- package/dist/{function-loader-D7o5Epjj.js → function-loader-iKhOZatS.js} +68 -38
- package/dist/function-loader-iKhOZatS.js.map +1 -0
- package/dist/{function-routes-CaNG4waN.js → function-routes-j9TwpvQe.js} +5 -4
- package/dist/function-routes-j9TwpvQe.js.map +1 -0
- package/dist/functions/context.d.ts +9 -0
- package/dist/functions/define-function.d.ts +10 -6
- package/dist/functions/function-loader.d.ts +75 -18
- package/dist/functions/function-routes.d.ts +2 -1
- package/dist/functions/index.d.ts +5 -4
- package/dist/functions/index.js +42 -13
- package/dist/functions/index.js.map +1 -1
- package/dist/functions/internal.d.ts +2 -2
- package/dist/functions/proxy.d.ts +6 -2
- package/dist/functions/request-timeout.d.ts +7 -5
- package/dist/history/history-routes.d.ts +9 -0
- package/dist/history/retention-sweep.d.ts +81 -0
- package/dist/{history-recorder-Nr8zLvoU.js → history-recorder-BfWRwmPy.js} +3 -3
- package/dist/{history-recorder-Nr8zLvoU.js.map → history-recorder-BfWRwmPy.js.map} +1 -1
- package/dist/{history-store-rcAm_xFR.js → history-store-DPofGVDp.js} +2 -2
- package/dist/{history-store-rcAm_xFR.js.map → history-store-DPofGVDp.js.map} +1 -1
- package/dist/index.d.ts +23 -10
- package/dist/index.es.js +24423 -20038
- package/dist/index.es.js.map +1 -1
- package/dist/init/docs.d.ts +27 -10
- package/dist/init/process-safety.d.ts +7 -2
- package/dist/init/shutdown.d.ts +18 -3
- package/dist/init.d.ts +49 -865
- package/dist/internal-tables-L2t39RdT.js +136 -0
- package/dist/internal-tables-L2t39RdT.js.map +1 -0
- package/dist/jobs/job-queue.d.ts +8 -0
- package/dist/jobs/job-store.d.ts +24 -0
- package/dist/jobs/types.d.ts +25 -4
- package/dist/{jobs-DqYNfquG.js → jobs-BCbflZj2.js} +234 -24
- package/dist/jobs-BCbflZj2.js.map +1 -0
- package/dist/{jwt-R6bSPMjk.js → jwt-BlvuKoR6.js} +529 -454
- package/dist/jwt-BlvuKoR6.js.map +1 -0
- package/dist/{keys-GAVZqbqx.js → keys-COzQ2aE8.js} +2 -2
- package/dist/{keys-GAVZqbqx.js.map → keys-COzQ2aE8.js.map} +1 -1
- package/dist/load-failure-L5hvfDoG.js +80 -0
- package/dist/load-failure-L5hvfDoG.js.map +1 -0
- package/dist/mcp/mcp-routes.d.ts +6 -0
- package/dist/mcp/mcp-tools.d.ts +8 -0
- package/dist/mcp/oauth-routes.d.ts +7 -0
- package/dist/metrics/index.d.ts +18 -0
- package/dist/metrics/pool-wait.d.ts +50 -0
- package/dist/offline-QNQgsPOq-B2yGeXkn.js +3305 -0
- package/dist/offline-QNQgsPOq-B2yGeXkn.js.map +1 -0
- package/dist/offline-store-Cm5sAX81-CALiO4Gn.js +1915 -0
- package/dist/offline-store-Cm5sAX81-CALiO4Gn.js.map +1 -0
- package/dist/{openapi-generator-DAq_XVDu.js → openapi-generator-D9zUQmEp.js} +366 -82
- package/dist/openapi-generator-D9zUQmEp.js.map +1 -0
- package/dist/policy-PdzX-Opd.js +121 -0
- package/dist/policy-PdzX-Opd.js.map +1 -0
- package/dist/project_manifest-R6y_KHms.js +59 -0
- package/dist/project_manifest-R6y_KHms.js.map +1 -0
- package/dist/{proxy-qRlqeUmO.js → proxy-CkTlMGmh.js} +4 -3
- package/dist/proxy-CkTlMGmh.js.map +1 -0
- package/dist/{query-parser-BgiKJKvc.js → query-parser-4WkMoA_K.js} +510 -15
- package/dist/query-parser-4WkMoA_K.js.map +1 -0
- package/dist/{request-timeout-DgH7j8qO.js → request-timeout-Dnl2_OBc.js} +15 -8
- package/dist/request-timeout-Dnl2_OBc.js.map +1 -0
- package/dist/resumable-upload-threshold-CKv-Ry0l.js +24 -0
- package/dist/resumable-upload-threshold-CKv-Ry0l.js.map +1 -0
- package/dist/schema-edit/apply-schema-change.d.ts +10 -0
- package/dist/schema-edit/local-source.d.ts +29 -0
- package/dist/schema-edit/remote-source.d.ts +13 -3
- package/dist/schema-edit/source-editor.d.ts +28 -0
- package/dist/{schema-editor-routes-oIyuWl3L.js → schema-editor-routes-C11Tumyd.js} +54 -10
- package/dist/schema-editor-routes-C11Tumyd.js.map +1 -0
- package/dist/services/outbound-post.d.ts +50 -0
- package/dist/services/outbound-url-guard.d.ts +34 -5
- package/dist/services/routed-realtime-service.d.ts +5 -0
- package/dist/services/webhook-service.d.ts +66 -14
- package/dist/singleton.d.ts +9 -5
- package/dist/soft-delete-params-DfV3vVN5.js +668 -0
- package/dist/soft-delete-params-DfV3vVN5.js.map +1 -0
- package/dist/sql-export-routes-ClRwzIsC.js +240 -0
- package/dist/sql-export-routes-ClRwzIsC.js.map +1 -0
- package/dist/{src-CatHFUym.js → src-D5Y3N-S4.js} +2 -1
- package/dist/{src-CatHFUym.js.map → src-D5Y3N-S4.js.map} +1 -1
- package/dist/storage/GCSStorageController.d.ts +46 -2
- package/dist/storage/LocalStorageController.d.ts +67 -2
- package/dist/storage/S3StorageController.d.ts +37 -3
- package/dist/storage/image-transform.d.ts +5 -0
- package/dist/storage/maintenance-routes.d.ts +23 -0
- package/dist/storage/maintenance.d.ts +126 -0
- package/dist/storage/rendition-cache.d.ts +9 -11
- package/dist/storage/request-principals.d.ts +30 -0
- package/dist/storage/routes.d.ts +20 -0
- package/dist/storage/source-variables.d.ts +10 -0
- package/dist/storage/streams.d.ts +42 -0
- package/dist/storage/tus-handler.d.ts +46 -2
- package/dist/storage/types.d.ts +82 -7
- package/dist/storage/upload-validation.d.ts +13 -0
- package/dist/storage-resumable-VO-cMpse-C_YX71pO.js +125 -0
- package/dist/storage-resumable-VO-cMpse-C_YX71pO.js.map +1 -0
- package/dist/strings.es-BeZWAodn.js +256 -0
- package/dist/strings.es-BeZWAodn.js.map +1 -0
- package/dist/upload-validation-Dd-fnsbA.js +172 -0
- package/dist/upload-validation-Dd-fnsbA.js.map +1 -0
- package/dist/utils/byte-size.d.ts +10 -0
- package/dist/utils/compression.d.ts +6 -0
- package/dist/utils/load-failure.d.ts +14 -0
- package/package.json +5 -5
- package/dist/GCSStorageController-BSiP1c-f.js +0 -256
- package/dist/GCSStorageController-BSiP1c-f.js.map +0 -1
- package/dist/S3StorageController-CAwFRgjV.js +0 -276
- package/dist/S3StorageController-CAwFRgjV.js.map +0 -1
- package/dist/auth-DMLngxn_.js.map +0 -1
- package/dist/backup-CN0s50D2.js.map +0 -1
- package/dist/contract-routes-fz8i4pxs.js.map +0 -1
- package/dist/cron-loader-CwaANlOG.js +0 -118
- package/dist/cron-loader-CwaANlOG.js.map +0 -1
- package/dist/cron-routes-Bc-SB0Se.js.map +0 -1
- package/dist/cron-scheduler-CYQgco86.js.map +0 -1
- package/dist/cron-store-D2Q9-Aco.js +0 -300
- package/dist/cron-store-D2Q9-Aco.js.map +0 -1
- package/dist/dynamic-import-X40pTZUQ.js +0 -23
- package/dist/dynamic-import-X40pTZUQ.js.map +0 -1
- package/dist/function-loader-D7o5Epjj.js.map +0 -1
- package/dist/function-routes-CaNG4waN.js.map +0 -1
- package/dist/jobs-DqYNfquG.js.map +0 -1
- package/dist/jwt-R6bSPMjk.js.map +0 -1
- package/dist/openapi-generator-DAq_XVDu.js.map +0 -1
- package/dist/proxy-qRlqeUmO.js.map +0 -1
- package/dist/query-parser-BgiKJKvc.js.map +0 -1
- package/dist/request-timeout-DgH7j8qO.js.map +0 -1
- package/dist/schema-editor-routes-oIyuWl3L.js.map +0 -1
- package/dist/soft-delete-params-BWPilMPF.js +0 -59
- package/dist/soft-delete-params-BWPilMPF.js.map +0 -1
- package/dist/src-I3aG1PcY.js +0 -6870
- package/dist/src-I3aG1PcY.js.map +0 -1
- package/dist/types-BfKcm9do.js +0 -39
- package/dist/types-BfKcm9do.js.map +0 -1
|
@@ -3,9 +3,172 @@ import __rebaseProcess from "process";
|
|
|
3
3
|
globalThis.process ??= __rebaseProcess;
|
|
4
4
|
__rebaseCreateRequire(import.meta.url);
|
|
5
5
|
import { n as __exportAll } from "./rolldown-runtime-dW7B1o5h.js";
|
|
6
|
-
import
|
|
7
|
-
import "./src-
|
|
8
|
-
import {
|
|
6
|
+
import "./strings.es-BeZWAodn.js";
|
|
7
|
+
import "./src-D5Y3N-S4.js";
|
|
8
|
+
import { r as policy } from "./policy-PdzX-Opd.js";
|
|
9
|
+
import { c as fieldKeyForColumn, f as isRelationRequired, l as findRelation, m as resolveCollectionRelations, n as HARD_DELETE_QUERY_PARAM, o as effectiveAccess, t as DELETED_QUERY_PARAM, u as getTableName } from "./soft-delete-params-DfV3vVN5.js";
|
|
10
|
+
//#region ../types/src/types/relations.ts
|
|
11
|
+
/**
|
|
12
|
+
* The key a junction row's own columns are carried under, in both directions.
|
|
13
|
+
*
|
|
14
|
+
* A read that includes a `manyToMany` relation serves each related row with its
|
|
15
|
+
* link's columns nested here — `{ id: 5, name: "ts", _pivot: { role: "owner" } }`
|
|
16
|
+
* — and a membership write may name the same key on an element to state what
|
|
17
|
+
* the link should hold. One constant because the two have to be the same word:
|
|
18
|
+
* a wire name that differs between the read and the write it round-trips
|
|
19
|
+
* through is a shape no client can echo back.
|
|
20
|
+
*
|
|
21
|
+
* Leading underscore, like `_matches`: it reads as metadata about the row
|
|
22
|
+
* rather than as one of its columns. A payload property may not be named
|
|
23
|
+
* `_pivot` either — `checkJunctionPayload` refuses it — so the key means one
|
|
24
|
+
* thing wherever it appears.
|
|
25
|
+
*
|
|
26
|
+
* @group Models
|
|
27
|
+
*/
|
|
28
|
+
var JUNCTION_PIVOT_KEY = "_pivot";
|
|
29
|
+
/**
|
|
30
|
+
* The key a row carries the totals of its counted relations under.
|
|
31
|
+
*
|
|
32
|
+
* An include that asks for a count — `include: { tags: { limit: 4, count: true } }`
|
|
33
|
+
* — serves, beside the (capped) `tags`, how many related rows there are in all:
|
|
34
|
+
* `{ id: 1, tags: [ …4 rows ], _count: { tags: 37 } }`. One object per row,
|
|
35
|
+
* keyed by relation name, so counting a second relation adds a key rather than
|
|
36
|
+
* a second top-level name.
|
|
37
|
+
*
|
|
38
|
+
* Leading underscore, like {@link JUNCTION_PIVOT_KEY} and `_matches`: it
|
|
39
|
+
* describes the read, not the record, and no column or form writes it. A
|
|
40
|
+
* collection with a property of this name cannot ask for a count — the read
|
|
41
|
+
* answers 400 rather than writing over the column.
|
|
42
|
+
*
|
|
43
|
+
* @group Models
|
|
44
|
+
*/
|
|
45
|
+
var INCLUDE_COUNT_KEY = "_count";
|
|
46
|
+
/** @group Models */
|
|
47
|
+
function hasForeignKeyOnTarget(relation) {
|
|
48
|
+
return relation.kind === "hasOne" || relation.kind === "hasMany";
|
|
49
|
+
}
|
|
50
|
+
/** @group Models */
|
|
51
|
+
function isManyToMany(relation) {
|
|
52
|
+
return relation.kind === "manyToMany";
|
|
53
|
+
}
|
|
54
|
+
/** @group Models */
|
|
55
|
+
function isToMany(relation) {
|
|
56
|
+
return relation.cardinality === "many";
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region ../types/src/types/tenancy.ts
|
|
60
|
+
/** Narrow a {@link TenantSource} to its claim form. @group Models */
|
|
61
|
+
function isTenantClaimSource(source) {
|
|
62
|
+
return typeof source.claim === "string";
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The roles tenancy does not apply to, when the collection names none.
|
|
66
|
+
*
|
|
67
|
+
* `admin`, mirroring the security baseline every collection already carries
|
|
68
|
+
* (`<table>_default_admin_read` / `_write`): the Studio, `dataAsAdmin` and a
|
|
69
|
+
* support operator all run with it, and a tenancy rule that locked them out
|
|
70
|
+
* would make the admin panel show an empty table on a collection full of rows.
|
|
71
|
+
*
|
|
72
|
+
* @group Models
|
|
73
|
+
*/
|
|
74
|
+
var DEFAULT_TENANT_BYPASS_ROLES = ["admin"];
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region ../common/src/util/tenant.ts
|
|
77
|
+
/**
|
|
78
|
+
* The one reading of `collection.tenant`.
|
|
79
|
+
*
|
|
80
|
+
* Four things have to agree for a tenant-scoped collection to work — the
|
|
81
|
+
* column, the RLS policy, the value stamped on insert and the index — and
|
|
82
|
+
* before this they were four hand-written declarations that nothing compared.
|
|
83
|
+
* The three that are schema become a {@link SecurityRule} and a column effect
|
|
84
|
+
* derived here and in `planSchema`; the fourth, the write path, is
|
|
85
|
+
* {@link resolveTenantWrite}.
|
|
86
|
+
*
|
|
87
|
+
* Everything in this module is pure. The policy it builds is a `SecurityRule`
|
|
88
|
+
* like any other, which is what makes `db push`, the doctor, boot-ensure, the
|
|
89
|
+
* drift detector and the Studio treat the tenancy policy as what it is —
|
|
90
|
+
* generated, named, and recognisable — rather than as somebody's hand-written
|
|
91
|
+
* SQL that a push should offer to drop.
|
|
92
|
+
*/
|
|
93
|
+
/**
|
|
94
|
+
* The collection's tenancy declaration, or nothing.
|
|
95
|
+
*
|
|
96
|
+
* Read through this rather than off the object, so the one shape check —
|
|
97
|
+
* `tenant` is an object carrying a `field` and a `from` — is in one place. A
|
|
98
|
+
* config that is *wrong* is refused by `validateCollectionConfig` with a
|
|
99
|
+
* message; this is only asking whether there is one.
|
|
100
|
+
*/
|
|
101
|
+
function getTenantConfig(collection) {
|
|
102
|
+
const tenant = collection?.tenant;
|
|
103
|
+
if (!tenant || typeof tenant !== "object") return void 0;
|
|
104
|
+
if (typeof tenant.field !== "string" || !tenant.field) return void 0;
|
|
105
|
+
if (!tenant.from || typeof tenant.from !== "object") return void 0;
|
|
106
|
+
return tenant;
|
|
107
|
+
}
|
|
108
|
+
/** The roles tenancy does not apply to, defaulted. */
|
|
109
|
+
function tenantBypassRoles(tenant) {
|
|
110
|
+
return tenant.bypassRoles ?? DEFAULT_TENANT_BYPASS_ROLES;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The name of the policy a tenant declaration compiles to.
|
|
114
|
+
*
|
|
115
|
+
* Explicit — not a `getPolicyNameHash` of the rule — precisely because the
|
|
116
|
+
* rule's *body* is compiled with more information in some callers than in
|
|
117
|
+
* others (`planSchema` can resolve a relation's target collection and so knows
|
|
118
|
+
* the column's type; the Studio, asking only for names, cannot). A hashed name
|
|
119
|
+
* would then differ between the two, and the same policy would read as drift.
|
|
120
|
+
* A frozen identifier: see `contracts/derived-names.txt`.
|
|
121
|
+
*/
|
|
122
|
+
function tenantPolicyName(tableName) {
|
|
123
|
+
return `${tableName}_tenant_scope`;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The condition a tenant declaration means, as a policy expression.
|
|
127
|
+
*
|
|
128
|
+
* `serverContext()` first, for the same reason every injected baseline rule
|
|
129
|
+
* carries it: the trusted plane runs migrations, the auth flows and the boot,
|
|
130
|
+
* and a restrictive policy that excluded it would not protect a tenant, it
|
|
131
|
+
* would stop the server from starting.
|
|
132
|
+
*
|
|
133
|
+
* Then the bypass roles, then the tenancy test itself — a claim comparison or a
|
|
134
|
+
* correlated `EXISTS` over the membership table, which are the two ways a
|
|
135
|
+
* deployment answers "which tenant is this caller in".
|
|
136
|
+
*/
|
|
137
|
+
function tenantScopeExpression(tenant) {
|
|
138
|
+
const match = isTenantClaimSource(tenant.from) ? policy.compare(policy.field(tenant.field), "eq", policy.authClaim(tenant.from.claim)) : policy.existsIn({
|
|
139
|
+
collection: tenant.from.membership.collection,
|
|
140
|
+
where: policy.and(policy.compare(policy.field(tenant.from.membership.tenantField), "eq", policy.outerField(tenant.field)), policy.compare(policy.field(tenant.from.membership.userField), "eq", policy.authUid()))
|
|
141
|
+
});
|
|
142
|
+
const bypass = tenantBypassRoles(tenant);
|
|
143
|
+
return bypass.length > 0 ? policy.or(policy.serverContext(), policy.rolesOverlap(bypass), match) : policy.or(policy.serverContext(), match);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The rule a tenant declaration compiles to, or nothing when there is none.
|
|
147
|
+
*
|
|
148
|
+
* **Restrictive**, and that is the whole design. A restrictive policy is ANDed
|
|
149
|
+
* with every other policy on the table, so tenancy narrows what the
|
|
150
|
+
* collection's own `securityRules` allow and can never widen it. A permissive
|
|
151
|
+
* one would OR with them, and a single `access: "public"` rule elsewhere in the
|
|
152
|
+
* file would take the entire tenancy boundary off without contradicting
|
|
153
|
+
* anything a reader could see.
|
|
154
|
+
*
|
|
155
|
+
* One rule with `operation: "all"` rather than four with `operations: [...]`:
|
|
156
|
+
* `FOR ALL` gives Postgres the USING clause for SELECT/UPDATE/DELETE and the
|
|
157
|
+
* WITH CHECK clause for INSERT/UPDATE, which is exactly the coverage wanted,
|
|
158
|
+
* as one policy with one name instead of four.
|
|
159
|
+
*/
|
|
160
|
+
function buildTenantSecurityRule(collection) {
|
|
161
|
+
const tenant = getTenantConfig(collection);
|
|
162
|
+
if (!tenant) return void 0;
|
|
163
|
+
const expression = tenantScopeExpression(tenant);
|
|
164
|
+
return {
|
|
165
|
+
name: tenantPolicyName(getTableName(collection)),
|
|
166
|
+
mode: "restrictive",
|
|
167
|
+
operation: "all",
|
|
168
|
+
condition: expression,
|
|
169
|
+
check: expression
|
|
170
|
+
};
|
|
171
|
+
}
|
|
9
172
|
/**
|
|
10
173
|
* The property a `softDelete` collection records a deletion in — its wire
|
|
11
174
|
* name, what a delete stamps and what a restore (an update to `null`) clears —
|
|
@@ -82,7 +245,7 @@ function generateOpenApiSpec(collections, options = {}) {
|
|
|
82
245
|
type: "integer",
|
|
83
246
|
minimum: 1
|
|
84
247
|
},
|
|
85
|
-
description: "Page number (alternative to offset). Calculates offset as (page-1)*limit"
|
|
248
|
+
description: "Page number (alternative to offset). Calculates offset as (page-1)*limit. Cannot be combined with `offset` (400 PAGE_WITH_OFFSET)."
|
|
86
249
|
},
|
|
87
250
|
{
|
|
88
251
|
name: "after",
|
|
@@ -143,9 +306,20 @@ function generateOpenApiSpec(collections, options = {}) {
|
|
|
143
306
|
name: "distinct",
|
|
144
307
|
in: "query",
|
|
145
308
|
schema: { type: "boolean" },
|
|
146
|
-
description: "`SELECT DISTINCT` over the returned columns. Only meaningful alongside `fields`: the primary key is always in the projection, so without narrowing it every row is already distinct. The response has no `meta.total` — the rows before deduplication are a different set, so their count would not describe the page — and `meta.hasMore`
|
|
309
|
+
description: "`SELECT DISTINCT` over the returned columns. Only meaningful alongside `fields`: the primary key is always in the projection, so without narrowing it every row is already distinct. The response has no `meta.total` — the rows before deduplication are a different set, so their count would not describe the page — and `meta.hasMore` comes from reading one row past the page. Refused (400) alongside `searchString` or a vector search, which attach a per-row score that makes every row distinct by construction, and (400 DISTINCT_ORDER_BY_NOT_SELECTED) when `orderBy` names a column `fields` does not return.",
|
|
147
310
|
example: "true"
|
|
148
311
|
},
|
|
312
|
+
{
|
|
313
|
+
name: "count",
|
|
314
|
+
in: "query",
|
|
315
|
+
schema: {
|
|
316
|
+
type: "string",
|
|
317
|
+
enum: ["exact", "none"],
|
|
318
|
+
default: "exact"
|
|
319
|
+
},
|
|
320
|
+
description: "Whether to count every matching row for `meta.total`. `exact` (the default) runs a `COUNT(*)` beside the page, which on a large table costs more than the page itself; `none` skips it, and the response then has no `meta.total`. `meta.hasMore` is exact either way — without a count it comes from reading one row past the page — so a walk that pages until `hasMore` is false needs no count. Anything else is a 400 INVALID_COUNT.",
|
|
321
|
+
example: "none"
|
|
322
|
+
},
|
|
149
323
|
{
|
|
150
324
|
name: "searchString",
|
|
151
325
|
in: "query",
|
|
@@ -184,7 +358,7 @@ function generateOpenApiSpec(collections, options = {}) {
|
|
|
184
358
|
name: "vector_threshold",
|
|
185
359
|
in: "query",
|
|
186
360
|
schema: { type: "number" },
|
|
187
|
-
description: "Drop rows farther than this distance. Rows are returned closest-first with a `_distance` field."
|
|
361
|
+
description: "Drop rows farther than this distance. Rows are returned closest-first with a `_distance` field. The response then has no `meta.total`: counting the rows within a distance computes it for every row of the table. `meta.hasMore` is exact, from reading one row past the page."
|
|
188
362
|
}
|
|
189
363
|
];
|
|
190
364
|
const spec = {
|
|
@@ -218,7 +392,7 @@ function generateOpenApiSpec(collections, options = {}) {
|
|
|
218
392
|
properties: {
|
|
219
393
|
total: {
|
|
220
394
|
type: "integer",
|
|
221
|
-
description: "Total number of matching records. Absent on a `distinct` read, which has no count of the rows it returns
|
|
395
|
+
description: "Total number of matching records. Absent on a `distinct` read, which has no count of the rows it returns, on a vector search with a `vector_threshold`, whose count would compute a distance for every row, and when the request asked for `count=none`."
|
|
222
396
|
},
|
|
223
397
|
limit: {
|
|
224
398
|
type: "integer",
|
|
@@ -466,31 +640,58 @@ function generateOpenApiSpec(collections, options = {}) {
|
|
|
466
640
|
schemas[`${schemaName}Update`] = buildCollectionUpdateSchema(collection);
|
|
467
641
|
const dataPath = `/data/${slug}`;
|
|
468
642
|
const softDeleteNote = softDeleteBehaviour(collection);
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
643
|
+
const countNarrowing = /* @__PURE__ */ new Set([
|
|
644
|
+
"where",
|
|
645
|
+
"or",
|
|
646
|
+
"and",
|
|
647
|
+
"not",
|
|
648
|
+
"searchString",
|
|
649
|
+
"vector_search",
|
|
650
|
+
"vector",
|
|
651
|
+
"vector_distance",
|
|
652
|
+
"vector_threshold"
|
|
653
|
+
]);
|
|
654
|
+
const countParameters = [
|
|
655
|
+
...listQueryParameters().filter((p) => countNarrowing.has(p.name)).map((p) => p.name === "vector_threshold" ? {
|
|
656
|
+
...p,
|
|
657
|
+
description: "Count only the rows within this distance of `vector`."
|
|
658
|
+
} : p),
|
|
659
|
+
...deletedParameters(collection),
|
|
660
|
+
...buildFilterParameters(collection, reservedParameterNames)
|
|
661
|
+
];
|
|
662
|
+
const countResponses = {
|
|
663
|
+
200: {
|
|
664
|
+
description: "The number of matching rows",
|
|
665
|
+
content: { "application/json": { schema: {
|
|
666
|
+
type: "object",
|
|
667
|
+
required: ["count"],
|
|
668
|
+
properties: { count: {
|
|
669
|
+
type: "integer",
|
|
670
|
+
description: "Rows matching the filters"
|
|
671
|
+
} }
|
|
672
|
+
} } }
|
|
673
|
+
},
|
|
674
|
+
...errorResponses(requireAuth)
|
|
675
|
+
};
|
|
676
|
+
paths[`${dataPath}/count`] = {
|
|
677
|
+
get: {
|
|
678
|
+
tags: [collection.name],
|
|
679
|
+
summary: `Count ${collection.name}`,
|
|
680
|
+
description: "The number of rows the same filters would return, without returning them. Takes the filter and search parameters of the list endpoint; `limit`, `offset` and `orderBy` are not part of the question and are ignored.",
|
|
681
|
+
operationId: `count${schemaName}`,
|
|
682
|
+
parameters: countParameters,
|
|
683
|
+
responses: countResponses
|
|
684
|
+
},
|
|
685
|
+
post: queryOperation({
|
|
686
|
+
tags: [collection.name],
|
|
687
|
+
summary: `Count ${collection.name}, parameters in the body`,
|
|
688
|
+
description: "The count `GET` answers, with its query parameters in a JSON body instead of the URL: the same filters, search and vector search, the same row-level security, and the same errors. It reads and never writes, so a credential needs `data:read` for it. Use it when the URL would not fit: a vector search's embedding, a long `in` list. A parameter also on the URL is a 400 INVALID_QUERY_BODY.",
|
|
689
|
+
operationId: `count${schemaName}Query`,
|
|
690
|
+
parameters: countParameters,
|
|
691
|
+
responses: countResponses,
|
|
692
|
+
reserved: reservedParameterNames
|
|
693
|
+
})
|
|
694
|
+
};
|
|
494
695
|
paths[`${dataPath}/aggregate`] = { get: {
|
|
495
696
|
tags: [collection.name],
|
|
496
697
|
summary: `Aggregate ${collection.name}`,
|
|
@@ -558,32 +759,42 @@ function generateOpenApiSpec(collections, options = {}) {
|
|
|
558
759
|
...errorResponses(requireAuth)
|
|
559
760
|
}
|
|
560
761
|
} };
|
|
762
|
+
const listParameters = [
|
|
763
|
+
...listQueryParameters(),
|
|
764
|
+
...deletedParameters(collection),
|
|
765
|
+
...buildFilterParameters(collection, reservedParameterNames)
|
|
766
|
+
];
|
|
767
|
+
const listResponses = {
|
|
768
|
+
200: {
|
|
769
|
+
description: "Paginated list of entities",
|
|
770
|
+
content: { "application/json": { schema: {
|
|
771
|
+
type: "object",
|
|
772
|
+
properties: {
|
|
773
|
+
data: {
|
|
774
|
+
type: "array",
|
|
775
|
+
items: { $ref: `#/components/schemas/${schemaName}` }
|
|
776
|
+
},
|
|
777
|
+
meta: { $ref: "#/components/schemas/PaginationMeta" }
|
|
778
|
+
}
|
|
779
|
+
} } }
|
|
780
|
+
},
|
|
781
|
+
...errorResponses(requireAuth)
|
|
782
|
+
};
|
|
783
|
+
paths[`${dataPath}/query`] = { post: queryOperation({
|
|
784
|
+
tags: [collection.name],
|
|
785
|
+
summary: `List ${collection.name}, parameters in the body`,
|
|
786
|
+
operationId: `query${schemaName}`,
|
|
787
|
+
parameters: listParameters,
|
|
788
|
+
responses: listResponses,
|
|
789
|
+
reserved: reservedParameterNames
|
|
790
|
+
}) };
|
|
561
791
|
paths[dataPath] = {
|
|
562
792
|
get: {
|
|
563
793
|
tags: [collection.name],
|
|
564
794
|
summary: `List ${collection.name}`,
|
|
565
795
|
operationId: `list${schemaName}`,
|
|
566
|
-
parameters:
|
|
567
|
-
|
|
568
|
-
...deletedParameters(collection),
|
|
569
|
-
...buildFilterParameters(collection, reservedParameterNames)
|
|
570
|
-
],
|
|
571
|
-
responses: {
|
|
572
|
-
200: {
|
|
573
|
-
description: "Paginated list of entities",
|
|
574
|
-
content: { "application/json": { schema: {
|
|
575
|
-
type: "object",
|
|
576
|
-
properties: {
|
|
577
|
-
data: {
|
|
578
|
-
type: "array",
|
|
579
|
-
items: { $ref: `#/components/schemas/${schemaName}` }
|
|
580
|
-
},
|
|
581
|
-
meta: { $ref: "#/components/schemas/PaginationMeta" }
|
|
582
|
-
}
|
|
583
|
-
} } }
|
|
584
|
-
},
|
|
585
|
-
...errorResponses(requireAuth)
|
|
586
|
-
}
|
|
796
|
+
parameters: listParameters,
|
|
797
|
+
responses: listResponses
|
|
587
798
|
},
|
|
588
799
|
post: {
|
|
589
800
|
tags: [collection.name],
|
|
@@ -594,8 +805,8 @@ function generateOpenApiSpec(collections, options = {}) {
|
|
|
594
805
|
in: "query",
|
|
595
806
|
required: false,
|
|
596
807
|
schema: { type: "string" },
|
|
597
|
-
description: "Comma-separated columns to upsert on, turning the create into INSERT ... ON CONFLICT DO UPDATE. They must carry a declared uniqueness guarantee — `validation.unique`, a `unique` index, or the primary key — or the request is refused with a 400 naming the targets that do exist. Left off, this is a plain insert and a duplicate key still raises.",
|
|
598
|
-
example: "
|
|
808
|
+
description: "Comma-separated columns to upsert on, turning the create into INSERT ... ON CONFLICT DO UPDATE. They must carry a declared uniqueness guarantee — `validation.unique`, a `unique` index, or the primary key — or the request is refused with a 400 naming the targets that do exist. Left off, this is a plain insert and a duplicate key still raises. Refused (400 `INVALID_CONFLICT_TARGET`) on the auth collection, whose rows are the users: create them with a plain POST and change them with PATCH.",
|
|
809
|
+
example: "sku"
|
|
599
810
|
}, preferHeader],
|
|
600
811
|
requestBody: {
|
|
601
812
|
required: true,
|
|
@@ -652,7 +863,7 @@ function generateOpenApiSpec(collections, options = {}) {
|
|
|
652
863
|
},
|
|
653
864
|
upsert: {
|
|
654
865
|
type: "boolean",
|
|
655
|
-
description: "Write each row as INSERT ... ON CONFLICT DO UPDATE."
|
|
866
|
+
description: "Write each row as INSERT ... ON CONFLICT DO UPDATE. Refused (400 `INVALID_CONFLICT_TARGET`) on the auth collection, whose rows are the users."
|
|
656
867
|
},
|
|
657
868
|
onConflict: {
|
|
658
869
|
type: "array",
|
|
@@ -872,34 +1083,44 @@ function generateOpenApiSpec(collections, options = {}) {
|
|
|
872
1083
|
const relationName = relation.relationName;
|
|
873
1084
|
const targetSchema = schemaNameFor(relation.target());
|
|
874
1085
|
const subPath = `/data/${slug}/{parentId}/${relationName}`;
|
|
1086
|
+
const nestedParameters = [{
|
|
1087
|
+
name: "parentId",
|
|
1088
|
+
in: "path",
|
|
1089
|
+
required: true,
|
|
1090
|
+
schema: { type: "string" },
|
|
1091
|
+
description: `${collection.singularName || collection.name} ID`
|
|
1092
|
+
}, ...listQueryParameters()];
|
|
1093
|
+
const nestedResponses = {
|
|
1094
|
+
200: {
|
|
1095
|
+
description: `List of related ${relationName}`,
|
|
1096
|
+
content: { "application/json": { schema: {
|
|
1097
|
+
type: "object",
|
|
1098
|
+
properties: {
|
|
1099
|
+
data: {
|
|
1100
|
+
type: "array",
|
|
1101
|
+
items: schemas[targetSchema] ? { $ref: `#/components/schemas/${targetSchema}` } : { type: "object" }
|
|
1102
|
+
},
|
|
1103
|
+
meta: { $ref: "#/components/schemas/PaginationMeta" }
|
|
1104
|
+
}
|
|
1105
|
+
} } }
|
|
1106
|
+
},
|
|
1107
|
+
...errorResponses(requireAuth)
|
|
1108
|
+
};
|
|
875
1109
|
paths[subPath] = { get: {
|
|
876
1110
|
tags: [collection.name],
|
|
877
1111
|
summary: `List ${relationName} for ${withIndefiniteArticle(collection.singularName || collection.name)}`,
|
|
878
1112
|
operationId: `list${schemaName}${toPascalCase(relationName)}`,
|
|
879
|
-
parameters:
|
|
880
|
-
|
|
881
|
-
in: "path",
|
|
882
|
-
required: true,
|
|
883
|
-
schema: { type: "string" },
|
|
884
|
-
description: `${collection.singularName || collection.name} ID`
|
|
885
|
-
}, ...listQueryParameters()],
|
|
886
|
-
responses: {
|
|
887
|
-
200: {
|
|
888
|
-
description: `List of related ${relationName}`,
|
|
889
|
-
content: { "application/json": { schema: {
|
|
890
|
-
type: "object",
|
|
891
|
-
properties: {
|
|
892
|
-
data: {
|
|
893
|
-
type: "array",
|
|
894
|
-
items: schemas[targetSchema] ? { $ref: `#/components/schemas/${targetSchema}` } : { type: "object" }
|
|
895
|
-
},
|
|
896
|
-
meta: { $ref: "#/components/schemas/PaginationMeta" }
|
|
897
|
-
}
|
|
898
|
-
} } }
|
|
899
|
-
},
|
|
900
|
-
...errorResponses(requireAuth)
|
|
901
|
-
}
|
|
1113
|
+
parameters: nestedParameters,
|
|
1114
|
+
responses: nestedResponses
|
|
902
1115
|
} };
|
|
1116
|
+
paths[`${subPath}/query`] = { post: queryOperation({
|
|
1117
|
+
tags: [collection.name],
|
|
1118
|
+
summary: `List ${relationName} for ${withIndefiniteArticle(collection.singularName || collection.name)}, parameters in the body`,
|
|
1119
|
+
operationId: `query${schemaName}${toPascalCase(relationName)}`,
|
|
1120
|
+
parameters: nestedParameters,
|
|
1121
|
+
responses: nestedResponses,
|
|
1122
|
+
reserved: reservedParameterNames
|
|
1123
|
+
}) };
|
|
903
1124
|
}
|
|
904
1125
|
}
|
|
905
1126
|
return spec;
|
|
@@ -1195,6 +1416,10 @@ function updateOperation(collection, schemaName, requireAuth, shared) {
|
|
|
1195
1416
|
responses: {
|
|
1196
1417
|
200: {
|
|
1197
1418
|
description: "Updated entity",
|
|
1419
|
+
headers: { ETag: {
|
|
1420
|
+
schema: { type: "string" },
|
|
1421
|
+
description: "The version this write produced — the tag a `GET` of the row now answers. Send it as `If-Match` on the next write to chain conditional edits without reading the row back. Absent on an answer replayed from an `Idempotency-Key`."
|
|
1422
|
+
} },
|
|
1198
1423
|
content: { "application/json": { schema: { $ref: `#/components/schemas/${schemaName}` } } }
|
|
1199
1424
|
},
|
|
1200
1425
|
404: {
|
|
@@ -1248,7 +1473,7 @@ function buildCollectionInputSchema(collection) {
|
|
|
1248
1473
|
if ("isId" in property && property.isId && property.isId !== "manual" && property.isId !== true) continue;
|
|
1249
1474
|
properties[key] = convertPropertyToSchema(property);
|
|
1250
1475
|
emitted.add(key);
|
|
1251
|
-
if (property.validation?.required) required.push(key);
|
|
1476
|
+
if (property.validation?.required && !property.databaseDefault) required.push(key);
|
|
1252
1477
|
}
|
|
1253
1478
|
if (!emitted.has(idKey)) {
|
|
1254
1479
|
properties[idKey] = {
|
|
@@ -1481,6 +1706,65 @@ function buildFilterParameters(collection, reservedNames = /* @__PURE__ */ new S
|
|
|
1481
1706
|
return params;
|
|
1482
1707
|
}
|
|
1483
1708
|
/**
|
|
1709
|
+
* A `POST …/query` operation: the listing whose `parameters` are given, with
|
|
1710
|
+
* its query parameters moved into a JSON body.
|
|
1711
|
+
*
|
|
1712
|
+
* Built from the `GET`'s own parameter list, so the body documents exactly
|
|
1713
|
+
* what the route accepts — it turns the body back into those parameters and
|
|
1714
|
+
* runs the `GET`'s parser (`query-body.ts`). A filter parameter takes a list
|
|
1715
|
+
* where the URL would repeat it, and the four parameters whose URL value is
|
|
1716
|
+
* JSON take the JSON value itself.
|
|
1717
|
+
*/
|
|
1718
|
+
function queryOperation(operation) {
|
|
1719
|
+
const jsonValued = {
|
|
1720
|
+
where: { oneOf: [{
|
|
1721
|
+
type: "object",
|
|
1722
|
+
additionalProperties: true
|
|
1723
|
+
}, { type: "string" }] },
|
|
1724
|
+
include: { oneOf: [{
|
|
1725
|
+
type: "object",
|
|
1726
|
+
additionalProperties: true
|
|
1727
|
+
}, { type: "string" }] },
|
|
1728
|
+
orderBy: { oneOf: [{
|
|
1729
|
+
type: "array",
|
|
1730
|
+
items: {}
|
|
1731
|
+
}, { type: "string" }] },
|
|
1732
|
+
vector: { oneOf: [{
|
|
1733
|
+
type: "array",
|
|
1734
|
+
items: { type: "number" }
|
|
1735
|
+
}, { type: "string" }] }
|
|
1736
|
+
};
|
|
1737
|
+
const properties = {};
|
|
1738
|
+
for (const parameter of operation.parameters) {
|
|
1739
|
+
if (parameter.in !== "query") continue;
|
|
1740
|
+
const name = String(parameter.name);
|
|
1741
|
+
const schema = parameter.schema;
|
|
1742
|
+
const isFilter = !operation.reserved.has(name);
|
|
1743
|
+
properties[name] = {
|
|
1744
|
+
...jsonValued[name] ?? (isFilter ? { oneOf: [schema, {
|
|
1745
|
+
type: "array",
|
|
1746
|
+
items: schema
|
|
1747
|
+
}] } : schema),
|
|
1748
|
+
...parameter.description ? { description: parameter.description } : {}
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
return {
|
|
1752
|
+
tags: operation.tags,
|
|
1753
|
+
summary: operation.summary,
|
|
1754
|
+
description: operation.description ?? "The listing `GET` answers, with its query parameters in a JSON body instead of the URL: the same filters, page, count, cursor and includes, the same row-level security, and the same errors. It reads and never writes, so a credential needs `data:read` for it. Use it when the URL would not fit: a vector search's embedding is a JSON array in `vector`, and 768 dimensions of it is 17 KB of URL, past what Node and most proxies accept. A parameter also on the URL is a 400 INVALID_QUERY_BODY.",
|
|
1755
|
+
operationId: operation.operationId,
|
|
1756
|
+
parameters: operation.parameters.filter((parameter) => parameter.in !== "query"),
|
|
1757
|
+
requestBody: {
|
|
1758
|
+
required: true,
|
|
1759
|
+
content: { "application/json": { schema: {
|
|
1760
|
+
type: "object",
|
|
1761
|
+
properties
|
|
1762
|
+
} } }
|
|
1763
|
+
},
|
|
1764
|
+
responses: operation.responses
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1484
1768
|
* Standard error responses included on every endpoint.
|
|
1485
1769
|
*/
|
|
1486
1770
|
function errorResponses(requireAuth) {
|
|
@@ -1537,6 +1821,6 @@ function toPascalCase(str) {
|
|
|
1537
1821
|
return str.replace(/[^a-zA-Z0-9]+/g, " ").split(" ").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
1538
1822
|
}
|
|
1539
1823
|
//#endregion
|
|
1540
|
-
export { softDeleteFieldOf as a, restoresSoftDeletedRow as i, buildCollectionSchema as n, openapi_generator_exports as r, buildCollectionInputSchema as t };
|
|
1824
|
+
export { softDeleteFieldOf as a, JUNCTION_PIVOT_KEY as c, restoresSoftDeletedRow as i, hasForeignKeyOnTarget as l, buildCollectionSchema as n, buildTenantSecurityRule as o, openapi_generator_exports as r, INCLUDE_COUNT_KEY as s, buildCollectionInputSchema as t, isManyToMany as u };
|
|
1541
1825
|
|
|
1542
|
-
//# sourceMappingURL=openapi-generator-
|
|
1826
|
+
//# sourceMappingURL=openapi-generator-D9zUQmEp.js.map
|