@rebasepro/cms-types 0.17.3-canary.gdd23447 → 0.18.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/README.md +49 -0
- package/dist/admin_collection.d.ts +49 -53
- package/dist/collections.d.ts +1 -1
- package/dist/controllers/customization_controller.d.ts +2 -2
- package/dist/controllers/navigation.d.ts +0 -1
- package/dist/controllers/registry.d.ts +20 -0
- package/dist/define_collection.d.ts +132 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +12 -8
- package/dist/index.es.js.map +1 -1
- package/dist/types/plugins.d.ts +2 -2
- package/dist/types/property_options.d.ts +132 -1
- package/dist/types/slots.d.ts +30 -4
- package/dist/types/translations.d.ts +96 -4
- package/package.json +27 -23
- package/src/admin_collection.ts +0 -775
- package/src/augment.ts +0 -79
- package/src/collections.ts +0 -312
- package/src/controllers/analytics_controller.tsx +0 -57
- package/src/controllers/auth.ts +0 -122
- package/src/controllers/customization_controller.tsx +0 -81
- package/src/controllers/dialogs_controller.tsx +0 -37
- package/src/controllers/index.ts +0 -10
- package/src/controllers/local_config_persistence.tsx +0 -22
- package/src/controllers/navigation.ts +0 -288
- package/src/controllers/registry.ts +0 -114
- package/src/controllers/side_dialogs_controller.tsx +0 -82
- package/src/controllers/side_panel_controller.tsx +0 -112
- package/src/controllers/snackbar.ts +0 -51
- package/src/index.ts +0 -20
- package/src/react_component_ref.ts +0 -52
- package/src/rebase_context.ts +0 -81
- package/src/types/breadcrumbs.ts +0 -16
- package/src/types/builders.ts +0 -18
- package/src/types/collection_views.tsx +0 -125
- package/src/types/component_overrides.ts +0 -244
- package/src/types/entity_actions.tsx +0 -134
- package/src/types/entity_display.ts +0 -182
- package/src/types/entity_link_builder.ts +0 -8
- package/src/types/entity_views.tsx +0 -135
- package/src/types/export_import.ts +0 -26
- package/src/types/form_layout.ts +0 -137
- package/src/types/formex.ts +0 -45
- package/src/types/index.ts +0 -18
- package/src/types/locales.ts +0 -81
- package/src/types/modify_collections.tsx +0 -6
- package/src/types/plugins.tsx +0 -346
- package/src/types/property_config.tsx +0 -97
- package/src/types/property_options.ts +0 -300
- package/src/types/slots.tsx +0 -334
- package/src/types/translations.ts +0 -1104
- package/src/types/user_management_delegate.ts +0 -23
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @rebasepro/cms-types
|
|
2
|
+
|
|
3
|
+
Type definitions for the Rebase CMS: collection and property shapes, the entity
|
|
4
|
+
and navigation models, and the translation keys the admin panel renders.
|
|
5
|
+
|
|
6
|
+
This package contains **types only**. Nothing here executes — it is the
|
|
7
|
+
vocabulary that the runtime, the generated SDK and the admin panel all agree on,
|
|
8
|
+
kept in one package so a change to a collection's shape cannot mean one thing to
|
|
9
|
+
the server and another to the panel.
|
|
10
|
+
|
|
11
|
+
The runtime that consumes these types is
|
|
12
|
+
[`@rebasepro/cms`](https://www.npmjs.com/package/@rebasepro/cms). If you are
|
|
13
|
+
building an app, that is the package you want; you will normally get this one as
|
|
14
|
+
a transitive dependency rather than installing it yourself.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @rebasepro/cms-types
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
ESM-only: `"type": "module"` with no CommonJS build, so it is loaded with
|
|
23
|
+
`import`. `require()` of it resolves only on Node 22.12+, which supports
|
|
24
|
+
`require(esm)`.
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import type { CollectionConfig } from "@rebasepro/cms-types";
|
|
30
|
+
|
|
31
|
+
export const posts: CollectionConfig = {
|
|
32
|
+
name: "Posts",
|
|
33
|
+
slug: "posts",
|
|
34
|
+
table: "posts",
|
|
35
|
+
properties: {
|
|
36
|
+
title: { name: "Title", type: "string", validation: { required: true } },
|
|
37
|
+
body: { name: "Body", type: "string", admin: { multiline: true } }
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Documentation
|
|
43
|
+
|
|
44
|
+
- [Collections](https://rebase.pro/docs/backend/collections)
|
|
45
|
+
- [Full documentation](https://rebase.pro/docs)
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
MIT
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* `WhereFilterOp` mistake, and this block is far bigger than one union.
|
|
16
16
|
*/
|
|
17
17
|
import type React from "react";
|
|
18
|
-
import type { CollectionConfig, ComponentRef, FilterPreset, FilterValues,
|
|
18
|
+
import type { CollectionCallbacks, CollectionConfig, ComponentRef, FilterPreset, FilterValues, OrderBySpec, PostgresCollectionConfig, User } from "@rebasepro/types";
|
|
19
19
|
import type { AdditionalFieldDelegate, CollectionActionsProps, CollectionSize, DefaultSelectedViewBuilder, KanbanConfig, SelectionController, ViewMode } from "./collections.js";
|
|
20
20
|
import type { EntityCustomView, FormViewConfig } from "./types/entity_views.js";
|
|
21
21
|
import type { CollectionCustomView } from "./types/collection_views.js";
|
|
@@ -122,6 +122,48 @@ export type AdminCollectionOptions<M extends Record<string, unknown> = Record<st
|
|
|
122
122
|
* If not specified, the list view uses a smart default (Title, Status, Date).
|
|
123
123
|
*/
|
|
124
124
|
listProperties?: ColumnKey<M>[];
|
|
125
|
+
/**
|
|
126
|
+
* Lifecycle callbacks that run **in the browser**, in the admin panel.
|
|
127
|
+
*
|
|
128
|
+
* The twin of the collection's top-level `callbacks`, and the distinction is
|
|
129
|
+
* only where the code runs — the shape is identical:
|
|
130
|
+
*
|
|
131
|
+
* - `callbacks` runs on the server, on every path that reaches it (REST,
|
|
132
|
+
* realtime, `dataAsAdmin`). Its bodies are stripped from the admin bundle,
|
|
133
|
+
* so a secret read there never leaves the server.
|
|
134
|
+
* - `browserCallbacks` runs in the panel, and nowhere else. It ships to
|
|
135
|
+
* every visitor.
|
|
136
|
+
*
|
|
137
|
+
* This exists for collections on a `direct` or `custom` transport — a
|
|
138
|
+
* Firestore collection the panel talks to itself, with no Rebase server in
|
|
139
|
+
* the request path. Nothing server-side sees those writes, so `callbacks`
|
|
140
|
+
* can never fire for them; this block is the only place their lifecycle
|
|
141
|
+
* logic can live.
|
|
142
|
+
*
|
|
143
|
+
* Two rules follow from "ships to every visitor", and neither is a style
|
|
144
|
+
* preference:
|
|
145
|
+
*
|
|
146
|
+
* 1. **No secrets.** No API keys, no `process.env`, no logic you would mind
|
|
147
|
+
* a reader of the bundle seeing. Put that in `callbacks`.
|
|
148
|
+
* 2. **Not a security boundary.** A `browserCallbacks.afterRead` that
|
|
149
|
+
* redacts a field redacts it *after* the browser already holds the row —
|
|
150
|
+
* for a direct transport the raw document came straight from the store.
|
|
151
|
+
* It is presentation. Redaction that has to hold belongs in `callbacks`,
|
|
152
|
+
* or in the store's own rules.
|
|
153
|
+
*
|
|
154
|
+
* On a server-transport collection (the default) the server has already run
|
|
155
|
+
* `callbacks` before the row arrives, so a `browserCallbacks.afterRead`
|
|
156
|
+
* here runs *in addition* — write it to be idempotent, or don't write it.
|
|
157
|
+
*
|
|
158
|
+
* ```ts
|
|
159
|
+
* admin: {
|
|
160
|
+
* browserCallbacks: {
|
|
161
|
+
* afterRead: ({ row }) => ({ ...row, label: `${row.city} (${row.code})` })
|
|
162
|
+
* }
|
|
163
|
+
* }
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
browserCallbacks?: CollectionCallbacks<M, USER>;
|
|
125
167
|
/**
|
|
126
168
|
* How a record of this collection shows up — its title, subtitle, image,
|
|
127
169
|
* status, date and tags.
|
|
@@ -509,55 +551,13 @@ export type AdminCollectionOptions<M extends Record<string, unknown> = Record<st
|
|
|
509
551
|
* writing one is an error — which is the guarantee a BaaS install depends on.
|
|
510
552
|
*/
|
|
511
553
|
/**
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
* The same identity function as `defineCollection` in `@rebasepro/common` — which
|
|
515
|
-
* is what a BaaS or headless project uses, and where `admin` does not exist at all
|
|
516
|
-
* — with one difference: importing this one brings the augmentation with it, so
|
|
517
|
-
* `admin: { icon, listProperties, kanban }` gets completion and a typo is an
|
|
518
|
-
* error. See {@link AdminCollectionOptions}.
|
|
519
|
-
*
|
|
520
|
-
* Import it from the layer you are in. A project with an admin panel wants this
|
|
521
|
-
* one; a project without one has no `admin` block to check.
|
|
522
|
-
*
|
|
523
|
-
* `const P` captures the literal property types, which is what gives
|
|
524
|
-
* `admin.display`, `admin.sort` and `admin.propertiesOrder` completion over
|
|
525
|
-
* the collection's own property keys rather than plain `string`.
|
|
554
|
+
* `defineCollection` lives in `./define_collection`, and this is why.
|
|
526
555
|
*
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
* properties: {
|
|
532
|
-
* title: { name: "Title", type: "string" },
|
|
533
|
-
* status: { name: "Status", type: "string" }
|
|
534
|
-
* },
|
|
535
|
-
* admin: {
|
|
536
|
-
* icon: "FileText",
|
|
537
|
-
* display: { title: "title" }, // completion: "title" | "status"
|
|
538
|
-
* listProperties: ["title", "status"]
|
|
539
|
-
* }
|
|
540
|
-
* });
|
|
541
|
-
*
|
|
542
|
-
* @group Builder
|
|
556
|
+
* A collection file is loaded by the backend as well as by the panel, so the
|
|
557
|
+
* builder it imports has to be reachable without React. This module names
|
|
558
|
+
* `React` throughout — it describes the panel's option types — so the builder
|
|
559
|
+
* sits apart from it and the barrel exports both.
|
|
543
560
|
*/
|
|
544
|
-
export declare function defineCollection<const P extends PostgresProperties, USER extends User = User>(collection: Omit<PostgresCollectionConfig<InferEntityType<P>, USER>, "properties"> & {
|
|
545
|
-
properties: P;
|
|
546
|
-
}): PostgresCollectionConfig<InferEntityType<P>, USER> & {
|
|
547
|
-
properties: P;
|
|
548
|
-
};
|
|
549
|
-
/** Define a Firestore-backed collection with the admin block checked. @group Builder */
|
|
550
|
-
export declare function defineCollection<const P extends FirebaseProperties, USER extends User = User>(collection: Omit<FirebaseCollectionConfig<InferEntityType<P>, USER>, "properties"> & {
|
|
551
|
-
properties: P;
|
|
552
|
-
}): FirebaseCollectionConfig<InferEntityType<P>, USER> & {
|
|
553
|
-
properties: P;
|
|
554
|
-
};
|
|
555
|
-
/** Define a MongoDB-backed collection with the admin block checked. @group Builder */
|
|
556
|
-
export declare function defineCollection<const P extends MongoProperties, USER extends User = User>(collection: Omit<MongoDBCollectionConfig<InferEntityType<P>, USER>, "properties"> & {
|
|
557
|
-
properties: P;
|
|
558
|
-
}): MongoDBCollectionConfig<InferEntityType<P>, USER> & {
|
|
559
|
-
properties: P;
|
|
560
|
-
};
|
|
561
561
|
/**
|
|
562
562
|
* Re-exported from `@rebasepro/types`, where the list has to live: the ts-morph
|
|
563
563
|
* schema editor in `@rebasepro/server` needs it to know which keys go inside the
|
|
@@ -573,12 +573,8 @@ export type { AdminCollectionKey } from "@rebasepro/types";
|
|
|
573
573
|
* Core's list, re-exported through a `satisfies` clause that is the agreement
|
|
574
574
|
* check: a key core names that is not an option here fails to compile, and
|
|
575
575
|
* `satisfies` keeps the literal tuple type rather than widening it to `string[]`.
|
|
576
|
-
*
|
|
577
|
-
* The reverse direction — an option missing from core's list — has no type-level
|
|
578
|
-
* expression, since there is no exhaustiveness check over an optional-property
|
|
579
|
-
* keyof. `test/admin_collection.test.ts` counts them instead.
|
|
580
576
|
*/
|
|
581
|
-
export declare const ADMIN_COLLECTION_KEYS: readonly ["Actions", "additionalFields", "alwaysApplyDefaultValues", "components", "customViews", "defaultEntityAction", "defaultFilter", "defaultSelectedView", "defaultSize", "defaultViewMode", "disableDefaultActions", "display", "enabledViews", "entityActions", "entityViews", "exportable", "filterPresets", "fixedFilter", "form", "formAutoSave", "formView", "group", "hideFromEntityViews", "hideFromNavigation", "hideIdFromCollection", "hideIdFromForm", "icon", "includeJsonView", "inlineEditing", "kanban", "listProperties", "localChangesBackup", "openEntityMode", "orderProperty", "pagination", "previewProperties", "propertiesOrder", "selectionController", "selectionEnabled", "sideDialogWidth", "sort"];
|
|
577
|
+
export declare const ADMIN_COLLECTION_KEYS: readonly ["Actions", "additionalFields", "alwaysApplyDefaultValues", "browserCallbacks", "components", "customViews", "defaultEntityAction", "defaultFilter", "defaultSelectedView", "defaultSize", "defaultViewMode", "disableDefaultActions", "display", "enabledViews", "entityActions", "entityViews", "exportable", "filterPresets", "fixedFilter", "form", "formAutoSave", "formView", "group", "hideFromEntityViews", "hideFromNavigation", "hideIdFromCollection", "hideIdFromForm", "icon", "includeJsonView", "inlineEditing", "kanban", "listProperties", "localChangesBackup", "openEntityMode", "orderProperty", "pagination", "previewProperties", "propertiesOrder", "selectionController", "selectionEnabled", "sideDialogWidth", "sort"];
|
|
582
578
|
/**
|
|
583
579
|
* A collection as the admin panel works with it: the contract with the `admin`
|
|
584
580
|
* block flattened onto the top level.
|
package/dist/collections.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* That is what made them safe to lift: they were never part of the BaaS surface,
|
|
13
13
|
* only stored next to it.
|
|
14
14
|
*/
|
|
15
|
-
import React from "react";
|
|
15
|
+
import type React from "react";
|
|
16
16
|
import type { Entity, EntityStatus, FilterValues, OrderByTuple, User } from "@rebasepro/types";
|
|
17
17
|
import type { RebaseContext } from "./rebase_context.js";
|
|
18
18
|
import type { AdminCollection, PropertyPath } from "@rebasepro/cms-types";
|
|
@@ -5,7 +5,7 @@ import type { EntityCustomView } from "../types/entity_views.js";
|
|
|
5
5
|
import type { CollectionCustomView } from "../types/collection_views.js";
|
|
6
6
|
import type { RebasePlugin } from "../types/plugins.js";
|
|
7
7
|
import type { PropertyConfig } from "../types/property_config.js";
|
|
8
|
-
import type {
|
|
8
|
+
import type { AnySlotContribution } from "../types/slots.js";
|
|
9
9
|
import type { ComponentOverrideMap } from "../types/component_overrides.js";
|
|
10
10
|
export type CustomizationController = {
|
|
11
11
|
/**
|
|
@@ -19,7 +19,7 @@ export type CustomizationController = {
|
|
|
19
19
|
/**
|
|
20
20
|
* Pre-merged slots from plugins + direct slot contributions.
|
|
21
21
|
*/
|
|
22
|
-
resolvedSlots:
|
|
22
|
+
resolvedSlots: AnySlotContribution[];
|
|
23
23
|
/**
|
|
24
24
|
* List of additional custom views for entities.
|
|
25
25
|
* You can use the key to reference the custom view in
|
|
@@ -125,7 +125,6 @@ export interface AppView {
|
|
|
125
125
|
* You can use any of the icons in the Lucide specs:
|
|
126
126
|
* https://lucide.dev/icons/
|
|
127
127
|
* e.g. 'ShoppingCart' or 'User'
|
|
128
|
-
* Find all the icons in https://rebase.pro/docs/icons
|
|
129
128
|
*/
|
|
130
129
|
icon?: string | React.ReactNode;
|
|
131
130
|
/**
|
|
@@ -67,8 +67,28 @@ export interface RebaseCMSConfig<EC extends AdminCollection = AdminCollection> {
|
|
|
67
67
|
basePath?: string;
|
|
68
68
|
}
|
|
69
69
|
export interface RebaseStudioConfig {
|
|
70
|
+
/**
|
|
71
|
+
* Which built-in tools to register. Omit for all of them; pass a shorter
|
|
72
|
+
* list to hide the rest.
|
|
73
|
+
*/
|
|
70
74
|
tools?: ("sql" | "js" | "rls" | "schema" | "storage" | "cron" | "schema-visualizer" | "branches" | "backups" | "api" | "logs" | "api-keys")[];
|
|
75
|
+
/** Replaces the Studio landing page. */
|
|
71
76
|
homePage?: ReactNode;
|
|
77
|
+
/**
|
|
78
|
+
* Your own tools, added beside the built-in ones.
|
|
79
|
+
*
|
|
80
|
+
* These are ordinary {@link AppView}s — the only thing that makes a view a
|
|
81
|
+
* Studio tool rather than a CMS view is being registered here rather than
|
|
82
|
+
* on `<RebaseCMS views>`: the drawer shows CMS views in content mode and
|
|
83
|
+
* these in Studio mode.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* <RebaseStudio devViews={[
|
|
88
|
+
* { slug: "queues", name: "Queues", group: "Compute", view: <QueuesView/> }
|
|
89
|
+
* ]}/>
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
72
92
|
devViews?: AppView[];
|
|
73
93
|
}
|
|
74
94
|
/**
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `defineCollection` — the admin-aware builder, in a module a backend can load.
|
|
3
|
+
*
|
|
4
|
+
* This is the function every scaffolded collection file imports, and it must be
|
|
5
|
+
* reachable from a Node process that has no React and no DOM. So it lives here,
|
|
6
|
+
* apart from `admin_collection.ts` (which describes the panel's option types and
|
|
7
|
+
* names `React` throughout) and well away from `collections.ts` (the panel's
|
|
8
|
+
* view models, which import React as a value).
|
|
9
|
+
*
|
|
10
|
+
* The side-effect import below is the other half of what the import buys you:
|
|
11
|
+
* `augment.ts` is what declares `admin` on `BaseCollectionConfig` and on every
|
|
12
|
+
* property type, so importing this builder brings the block's type-checking with
|
|
13
|
+
* it. It is types only, and compiles to nothing.
|
|
14
|
+
*/
|
|
15
|
+
import "./augment.js";
|
|
16
|
+
import type { FirebaseCollectionConfig, FirebaseProperties, FirebaseProperty, InferEntityType, MongoDBCollectionConfig, MongoProperties, MongoProperty, PostgresCollectionConfig, PostgresProperties, PostgresProperty, Properties, Property, StrictProperties, User } from "@rebasepro/types";
|
|
17
|
+
import { type ResourceRef } from "@rebasepro/types";
|
|
18
|
+
/**
|
|
19
|
+
* The engines a collection can name. Absent means Postgres.
|
|
20
|
+
*
|
|
21
|
+
* The discriminant that replaced three overloads of `defineCollection`. See
|
|
22
|
+
* {@link CollectionConfigForEngine} for why that mattered.
|
|
23
|
+
*/
|
|
24
|
+
type CollectionEngine = "postgres" | "firestore" | "mongodb";
|
|
25
|
+
/**
|
|
26
|
+
* The concrete collection type an `engine` selects.
|
|
27
|
+
*
|
|
28
|
+
* `defineCollection` used to be three overloads — one per engine — and overload
|
|
29
|
+
* resolution is what made its errors unreadable. When no overload matches,
|
|
30
|
+
* TypeScript emits **one** diagnostic at the call site listing each overload's
|
|
31
|
+
* *first* failure, so:
|
|
32
|
+
*
|
|
33
|
+
* - a bad `defaultValue` **and** a misspelled `admin.display.title` in the same
|
|
34
|
+
* collection reported only the first. Fixing it revealed the second on the
|
|
35
|
+
* next run, one per edit-compile cycle;
|
|
36
|
+
* - the error landed on `defineCollection(`, not on the key that was wrong;
|
|
37
|
+
* - and every Postgres collection's error dragged `FirebaseCollectionConfig`
|
|
38
|
+
* and `MongoDBCollectionConfig` through the message, naming two engines the
|
|
39
|
+
* author had not mentioned and does not use.
|
|
40
|
+
*
|
|
41
|
+
* With one signature there is no resolution to fail: each error is reported
|
|
42
|
+
* where it is, all of them at once, against the one config type the `engine`
|
|
43
|
+
* selects.
|
|
44
|
+
*/
|
|
45
|
+
type CollectionConfigForEngine<E, P, USER extends User> = E extends "firestore" ? FirebaseCollectionConfig<EntityShapeOf<P>, USER> : E extends "mongodb" ? MongoDBCollectionConfig<EntityShapeOf<P>, USER> : PostgresCollectionConfig<EntityShapeOf<P>, USER>;
|
|
46
|
+
/**
|
|
47
|
+
* `InferEntityType`, tolerant of a property map that has an error in it.
|
|
48
|
+
*
|
|
49
|
+
* `P` is deliberately **unconstrained** on the builder, and this is why. A
|
|
50
|
+
* constraint TypeScript cannot satisfy is a constraint it silently falls back
|
|
51
|
+
* from: one property with a bad `defaultValue` made `P extends PostgresProperties`
|
|
52
|
+
* fail, `P` became `PostgresProperties`, `M` became `Record<string, unknown>`,
|
|
53
|
+
* and every `admin` key — `display.title`, `listProperties`, `propertiesOrder` —
|
|
54
|
+
* widened to `string` and stopped being checked. So a collection with two
|
|
55
|
+
* mistakes reported one, and reported the second only after the first was fixed.
|
|
56
|
+
*
|
|
57
|
+
* With no constraint, `keyof P` survives a bad property and the `admin` block is
|
|
58
|
+
* still checked against the real key set. Exactness and the engine gate move
|
|
59
|
+
* into `StrictProperties`, which reports them on the property itself.
|
|
60
|
+
*/
|
|
61
|
+
type EntityShapeOf<P> = InferEntityType<{
|
|
62
|
+
[K in keyof P]: P[K] extends Property ? P[K] : Property;
|
|
63
|
+
}>;
|
|
64
|
+
/** The property union an engine admits — the engine gate, as a type. */
|
|
65
|
+
type PropertyForEngine<E> = E extends "firestore" ? FirebaseProperty : E extends "mongodb" ? MongoProperty : PostgresProperty;
|
|
66
|
+
/** {@link PropertyForEngine} as a property map, for the `P` constraint. */
|
|
67
|
+
type PropertiesForEngine<E> = E extends "firestore" ? FirebaseProperties : E extends "mongodb" ? MongoProperties : PostgresProperties;
|
|
68
|
+
/**
|
|
69
|
+
* Define a collection with the admin block type-checked.
|
|
70
|
+
*
|
|
71
|
+
* The same identity function as `defineCollection` in `@rebasepro/common` — which
|
|
72
|
+
* is what a BaaS or headless project uses, and where `admin` does not exist at all
|
|
73
|
+
* — with one difference: importing this one brings the augmentation with it, so
|
|
74
|
+
* `admin: { icon, listProperties, kanban }` gets completion and a typo is an
|
|
75
|
+
* error. See {@link AdminCollectionOptions}.
|
|
76
|
+
*
|
|
77
|
+
* Import it from the layer you are in. A project with an admin panel wants this
|
|
78
|
+
* one; a project without one has no `admin` block to check.
|
|
79
|
+
*
|
|
80
|
+
* `const P` captures the literal property types, which is what gives
|
|
81
|
+
* `admin.display`, `admin.sort` and `admin.propertiesOrder` completion over
|
|
82
|
+
* the collection's own property keys rather than plain `string`.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* export default defineCollection({
|
|
86
|
+
* slug: "posts",
|
|
87
|
+
* table: "posts",
|
|
88
|
+
* properties: {
|
|
89
|
+
* title: { name: "Title", type: "string" },
|
|
90
|
+
* status: { name: "Status", type: "string" }
|
|
91
|
+
* },
|
|
92
|
+
* admin: {
|
|
93
|
+
* icon: "FileText",
|
|
94
|
+
* display: { title: "title" }, // completion: "title" | "status"
|
|
95
|
+
* listProperties: ["title", "status"]
|
|
96
|
+
* }
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* @group Builder
|
|
100
|
+
*/
|
|
101
|
+
export declare function defineCollection<const E extends CollectionEngine = "postgres",
|
|
102
|
+
/**
|
|
103
|
+
* The properties, **constrained**. This is what checks them, and — just as
|
|
104
|
+
* importantly — what supplies the contextual type inside them: without a
|
|
105
|
+
* constraint the parameter of an inline
|
|
106
|
+
* `callbacks: { beforeSave: ({ value }) => … }` has nothing to be typed
|
|
107
|
+
* from, and TypeScript reports an implicit `any` on a callback the author
|
|
108
|
+
* wrote correctly.
|
|
109
|
+
*/
|
|
110
|
+
const P extends PropertiesForEngine<E> & Properties = PropertiesForEngine<E> & Properties,
|
|
111
|
+
/**
|
|
112
|
+
* The properties again, **unconstrained**, and this is why there are two.
|
|
113
|
+
*
|
|
114
|
+
* A constraint TypeScript cannot satisfy is one it silently falls back
|
|
115
|
+
* from: one property with a bad `defaultValue` made `P` become
|
|
116
|
+
* `PostgresProperties`, the entity shape become `Record<string, unknown>`,
|
|
117
|
+
* and every `admin` key — `display.title`, `listProperties`,
|
|
118
|
+
* `propertiesOrder` — widen to `string` and stop being checked. A
|
|
119
|
+
* collection with two mistakes reported one, and revealed the second only
|
|
120
|
+
* after the first was fixed.
|
|
121
|
+
*
|
|
122
|
+
* `KEYS` has no constraint to fall back from, so `keyof KEYS` survives a bad
|
|
123
|
+
* property and the `admin` block is still checked against the real key set.
|
|
124
|
+
*/
|
|
125
|
+
const KEYS = Properties, USER extends User = User>(collection: Omit<CollectionConfigForEngine<E, KEYS, USER>, "properties" | "engine" | "dataSource"> & {
|
|
126
|
+
engine?: E;
|
|
127
|
+
properties: StrictProperties<P, PropertyForEngine<E>> & KEYS;
|
|
128
|
+
dataSource?: ResourceRef;
|
|
129
|
+
}): CollectionConfigForEngine<E, KEYS, USER> & {
|
|
130
|
+
properties: KEYS;
|
|
131
|
+
};
|
|
132
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import "./augment.js";
|
|
12
12
|
export * from "./types/property_options.js";
|
|
13
13
|
export * from "./react_component_ref.js";
|
|
14
|
+
export * from "./define_collection.js";
|
|
14
15
|
export * from "./collections.js";
|
|
15
16
|
export * from "./admin_collection.js";
|
|
16
17
|
export * from "./rebase_context.js";
|
package/dist/index.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ADMIN_COLLECTION_KEYS as ADMIN_COLLECTION_KEYS$1, ADMIN_PROPERTY_KEYS as ADMIN_PROPERTY_KEYS$1, nestAdminCollectionKeys } from "@rebasepro/types";
|
|
1
|
+
import { ADMIN_COLLECTION_KEYS as ADMIN_COLLECTION_KEYS$1, ADMIN_PROPERTY_KEYS as ADMIN_PROPERTY_KEYS$1, nestAdminCollectionKeys, resolveResourceRefs } from "@rebasepro/types";
|
|
2
2
|
//#region src/types/property_options.ts
|
|
3
3
|
/**
|
|
4
4
|
* Core's list, re-exported through the same `satisfies` agreement check that
|
|
@@ -39,19 +39,23 @@ function asReactComponent(component) {
|
|
|
39
39
|
return component;
|
|
40
40
|
}
|
|
41
41
|
//#endregion
|
|
42
|
-
//#region src/
|
|
43
|
-
/**
|
|
42
|
+
//#region src/define_collection.ts
|
|
43
|
+
/**
|
|
44
|
+
* At runtime this records the collection as data: a resource handle written
|
|
45
|
+
* where a key belongs — `dataSource: analytics`, `storageSource: media` — is
|
|
46
|
+
* replaced by its key, so what leaves here serialises and compares like the
|
|
47
|
+
* string it always was. The signature above is the rest of the point.
|
|
48
|
+
* @group Builder
|
|
49
|
+
*/
|
|
44
50
|
function defineCollection(collection) {
|
|
45
|
-
return collection;
|
|
51
|
+
return resolveResourceRefs(collection);
|
|
46
52
|
}
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/admin_collection.ts
|
|
47
55
|
/**
|
|
48
56
|
* Core's list, re-exported through a `satisfies` clause that is the agreement
|
|
49
57
|
* check: a key core names that is not an option here fails to compile, and
|
|
50
58
|
* `satisfies` keeps the literal tuple type rather than widening it to `string[]`.
|
|
51
|
-
*
|
|
52
|
-
* The reverse direction — an option missing from core's list — has no type-level
|
|
53
|
-
* expression, since there is no exhaustiveness check over an optional-property
|
|
54
|
-
* keyof. `test/admin_collection.test.ts` counts them instead.
|
|
55
59
|
*/
|
|
56
60
|
var ADMIN_COLLECTION_KEYS = ADMIN_COLLECTION_KEYS$1;
|
|
57
61
|
/**
|