@tekki-forge/core 0.1.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 +5 -0
- package/dist/app.d.ts +308 -0
- package/dist/app.js +10 -0
- package/dist/app.js.map +1 -0
- package/dist/dashboard.d.ts +54 -0
- package/dist/dashboard.js +4 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/fields.d.ts +130 -0
- package/dist/fields.js +33 -0
- package/dist/fields.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +64 -0
- package/dist/plugin.js +4 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# @tekki-forge/core
|
|
2
|
+
|
|
3
|
+
Forge schema DSL: defineApp, entity and field builders.
|
|
4
|
+
|
|
5
|
+
Part of [Tekki Forge](https://www.npmjs.com/package/tekki-forge), which turns a `forge.config.ts` into a production-ready full-stack app. Apps created with `forge new` install this package for you; see the [tekki-forge](https://www.npmjs.com/package/tekki-forge) package for the documentation.
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import type { AnyField } from "./fields.js";
|
|
2
|
+
import type { DashboardWidget } from "./dashboard.js";
|
|
3
|
+
import type { PluginDefinition } from "./plugin.js";
|
|
4
|
+
/**
|
|
5
|
+
* A permission rule lists who may perform an operation. Tokens:
|
|
6
|
+
* - a role name, e.g. "admin", "manager", "member"
|
|
7
|
+
* - "owner" the user referenced by the entity's owner relation
|
|
8
|
+
* - "team" members of the record's team (entities with features: { teams: true })
|
|
9
|
+
* - "authenticated" any signed-in user
|
|
10
|
+
* - "public" anyone, including anonymous visitors
|
|
11
|
+
* - "policy:<name>" a named policy implemented in the API extension file
|
|
12
|
+
*/
|
|
13
|
+
export type PermissionToken = string;
|
|
14
|
+
export type PermissionRule = readonly PermissionToken[];
|
|
15
|
+
export interface EntityPermissions {
|
|
16
|
+
create?: PermissionRule;
|
|
17
|
+
read?: PermissionRule;
|
|
18
|
+
update?: PermissionRule;
|
|
19
|
+
delete?: PermissionRule;
|
|
20
|
+
}
|
|
21
|
+
export interface EntityFeatures {
|
|
22
|
+
/** createdAt / updatedAt columns. Default: true. */
|
|
23
|
+
timestamps?: boolean;
|
|
24
|
+
/** Keep deleted rows with a deletedAt marker and expose a restore endpoint. */
|
|
25
|
+
softDelete?: boolean;
|
|
26
|
+
/** Record every create/update/delete in the audit log. */
|
|
27
|
+
audit?: boolean;
|
|
28
|
+
/** Scope rows to the active organization. Default: true when multi-tenancy is enabled. */
|
|
29
|
+
tenant?: boolean;
|
|
30
|
+
/** CSV export endpoint and button. Default: true. */
|
|
31
|
+
export?: boolean;
|
|
32
|
+
/** Bulk delete endpoint and selection UI. Default: true. */
|
|
33
|
+
bulkDelete?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Records belong to a team of the organization: adds a `team` relation (built-in Team model) and
|
|
36
|
+
* enables the "team" permission token (members of the record's team). Requires multiTenant.
|
|
37
|
+
*/
|
|
38
|
+
teams?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Comments with @mentions on each record, shown with the audit history in the record page's Activity panel.
|
|
41
|
+
* Anyone who can read a record can comment on it. Default: false.
|
|
42
|
+
*/
|
|
43
|
+
comments?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface ActionDefinition {
|
|
46
|
+
readonly __forge: "action";
|
|
47
|
+
label?: string;
|
|
48
|
+
/** Confirmation prompt shown before running the action. */
|
|
49
|
+
confirm?: string;
|
|
50
|
+
/** Who may run it. Default: the entity's update rule. */
|
|
51
|
+
permission?: PermissionRule;
|
|
52
|
+
/** Visual emphasis in the UI. */
|
|
53
|
+
variant?: "default" | "danger";
|
|
54
|
+
}
|
|
55
|
+
export declare function action(definition?: Omit<ActionDefinition, "__forge">): ActionDefinition;
|
|
56
|
+
export interface EntityListOptions {
|
|
57
|
+
columns?: readonly string[];
|
|
58
|
+
/** e.g. "-createdAt" or "name" */
|
|
59
|
+
defaultSort?: string;
|
|
60
|
+
pageSize?: number;
|
|
61
|
+
}
|
|
62
|
+
export interface WorkflowTransition {
|
|
63
|
+
/** State(s) the transition starts from; "*" for any. */
|
|
64
|
+
from: string | readonly string[];
|
|
65
|
+
to: string;
|
|
66
|
+
label?: string;
|
|
67
|
+
/** Who may run it. Default: the entity's update rule. */
|
|
68
|
+
permission?: PermissionRule;
|
|
69
|
+
confirm?: string;
|
|
70
|
+
variant?: "default" | "danger";
|
|
71
|
+
}
|
|
72
|
+
export interface WorkflowDefinition {
|
|
73
|
+
/** An enumeration field holding the state. It can then only change through transitions. */
|
|
74
|
+
field: string;
|
|
75
|
+
/** State of new records. Default: the field's default, else its first value. */
|
|
76
|
+
initial?: string;
|
|
77
|
+
transitions: Record<string, WorkflowTransition>;
|
|
78
|
+
}
|
|
79
|
+
export interface EntityViews {
|
|
80
|
+
/** Kanban board grouped by an enum field (drag cards between columns). */
|
|
81
|
+
board?: {
|
|
82
|
+
groupBy: string;
|
|
83
|
+
title?: string;
|
|
84
|
+
fields?: readonly string[];
|
|
85
|
+
};
|
|
86
|
+
/** Month calendar placed by a date/datetime field. */
|
|
87
|
+
calendar?: {
|
|
88
|
+
date: string;
|
|
89
|
+
end?: string;
|
|
90
|
+
title?: string;
|
|
91
|
+
};
|
|
92
|
+
/** Map of records by a location field. */
|
|
93
|
+
map?: {
|
|
94
|
+
location: string;
|
|
95
|
+
title?: string;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export interface EntityDefinition {
|
|
99
|
+
readonly __forge: "entity";
|
|
100
|
+
label?: string;
|
|
101
|
+
pluralLabel?: string;
|
|
102
|
+
/** Database table name. Default: snake_case plural of the entity name. */
|
|
103
|
+
table?: string;
|
|
104
|
+
/** URL segment. Default: kebab-case plural of the entity name. */
|
|
105
|
+
path?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Name the stored data is keyed on: the Prisma model (and so its enum types and many-to-many link
|
|
108
|
+
* tables) and the entity name recorded in uploaded files, the audit log and notifications.
|
|
109
|
+
* Default: the entity name. Renaming an entity in the schema editor sets it to the previous name
|
|
110
|
+
* (with `table` and `path`), so the rename changes no database object and no stored row.
|
|
111
|
+
* Changing it yourself renames those database objects — review the migration.
|
|
112
|
+
*/
|
|
113
|
+
storageName?: string;
|
|
114
|
+
/** Field used as the human-readable label of a record. */
|
|
115
|
+
display?: string;
|
|
116
|
+
/** lucide icon name used in navigation. */
|
|
117
|
+
icon?: string;
|
|
118
|
+
/** Show in the sidebar. Default true. */
|
|
119
|
+
nav?: boolean;
|
|
120
|
+
description?: string;
|
|
121
|
+
fields: Record<string, AnyField>;
|
|
122
|
+
permissions?: EntityPermissions;
|
|
123
|
+
features?: EntityFeatures;
|
|
124
|
+
actions?: Record<string, ActionDefinition>;
|
|
125
|
+
list?: EntityListOptions;
|
|
126
|
+
workflow?: WorkflowDefinition;
|
|
127
|
+
views?: EntityViews;
|
|
128
|
+
}
|
|
129
|
+
export declare function entity(definition: Omit<EntityDefinition, "__forge">): EntityDefinition;
|
|
130
|
+
export type SocialProvider = "google" | "microsoft" | "github" | "apple" | "gitlab" | "discord";
|
|
131
|
+
export interface AuthConfig {
|
|
132
|
+
emailPassword?: boolean;
|
|
133
|
+
/** Allow self-service sign-up. Default: true. */
|
|
134
|
+
registration?: boolean;
|
|
135
|
+
social?: readonly SocialProvider[];
|
|
136
|
+
emailVerification?: boolean;
|
|
137
|
+
passwordReset?: boolean;
|
|
138
|
+
twoFactor?: boolean;
|
|
139
|
+
passkeys?: boolean;
|
|
140
|
+
}
|
|
141
|
+
export interface MultiTenantConfig {
|
|
142
|
+
enabled: boolean;
|
|
143
|
+
model?: "organization";
|
|
144
|
+
}
|
|
145
|
+
export type UIStyle = "simple" | "shadow" | "neumorphism" | "glassmorphism" | "skeuomorphism" | "material" | "brutalist" | "editorial" | "aurora" | "terminal" | "clay";
|
|
146
|
+
/** Curated looks (style + colours + font + corners + mode + layout). Explicit theme keys override them. */
|
|
147
|
+
export type ThemePreset = "midnight" | "sandstone" | "ocean" | "forest" | "sunset" | "graphite" | "candy" | "paper" | "phosphor";
|
|
148
|
+
/** Typeface pairing (headings + body), loaded from Google Fonts at runtime; "system" loads nothing. */
|
|
149
|
+
export type ThemeFont = "inter" | "geist" | "plex" | "grotesk" | "serif" | "rounded" | "mono" | "system";
|
|
150
|
+
export interface ThemeConfig {
|
|
151
|
+
/**
|
|
152
|
+
* Start from a curated look: midnight, sandstone, ocean, forest, sunset, graphite, candy, paper, phosphor.
|
|
153
|
+
* Any other key set here overrides the preset's value.
|
|
154
|
+
*/
|
|
155
|
+
preset?: ThemePreset;
|
|
156
|
+
/**
|
|
157
|
+
* Visual language of the whole UI:
|
|
158
|
+
* - simple flat surfaces, hairline borders
|
|
159
|
+
* - shadow borderless cards floating on soft layered shadows
|
|
160
|
+
* - neumorphism extruded surfaces the same colour as the page
|
|
161
|
+
* - glassmorphism frosted translucent panels over a colourful backdrop
|
|
162
|
+
* - skeuomorphism tactile gradients, bevels and highlights
|
|
163
|
+
* - material Material Design 3 tonal surfaces and elevation
|
|
164
|
+
* - brutalist thick borders, hard offset shadows, bold type
|
|
165
|
+
* - editorial paper tones, serif headings, hairlines, generous whitespace
|
|
166
|
+
* - aurora soft animated gradient backdrop from your colours, glassy cards
|
|
167
|
+
* - terminal dark-first, monospace, phosphor accents
|
|
168
|
+
* - clay claymorphism: puffy rounded surfaces with inner highlights
|
|
169
|
+
*/
|
|
170
|
+
style?: UIStyle;
|
|
171
|
+
colors?: {
|
|
172
|
+
/** Main brand colour: primary buttons, links, focus rings, active navigation. Hex, e.g. "#4f46e5". */
|
|
173
|
+
primary?: string;
|
|
174
|
+
/** Secondary highlight: badges, charts, the glass backdrop, selected states. */
|
|
175
|
+
accent?: string;
|
|
176
|
+
/** Destructive actions. */
|
|
177
|
+
danger?: string;
|
|
178
|
+
};
|
|
179
|
+
mode?: "light" | "dark" | "system";
|
|
180
|
+
/** Corner roundness. */
|
|
181
|
+
radius?: "none" | "small" | "medium" | "large" | "full";
|
|
182
|
+
/**
|
|
183
|
+
* Typeface pairing: inter, geist, plex (IBM Plex), grotesk (Space Grotesk headings), serif (Fraunces headings),
|
|
184
|
+
* rounded (Nunito), mono (JetBrains Mono), system (no web font). Default: the style's own, else system.
|
|
185
|
+
*/
|
|
186
|
+
font?: ThemeFont;
|
|
187
|
+
/** Navigation: a sidebar (default), a top bar, or a compact icon rail (tooltips on hover/focus, expandable with its toggle). */
|
|
188
|
+
layout?: "sidebar" | "topbar" | "compact";
|
|
189
|
+
/** Spacing of tables, forms and cards. Default: comfortable. */
|
|
190
|
+
density?: "comfortable" | "compact";
|
|
191
|
+
/** Logo shown in the navigation, on sign-in pages and as the favicon: an https:// URL or a file in apps/web/public ("/logo.svg"). */
|
|
192
|
+
logo?: string;
|
|
193
|
+
/** Short line shown on the sign-in pages' brand panel. */
|
|
194
|
+
tagline?: string;
|
|
195
|
+
}
|
|
196
|
+
export interface NotificationRule {
|
|
197
|
+
/**
|
|
198
|
+
* Event that triggers it: "<Entity>.<created|updated|deleted|restored|transitioned|action>",
|
|
199
|
+
* optionally narrowed to a transition or action: "Invoice.transitioned:send".
|
|
200
|
+
*/
|
|
201
|
+
on: string;
|
|
202
|
+
/**
|
|
203
|
+
* Who is notified: "owner", the name of a User relation on the entity ("assignee", "members"),
|
|
204
|
+
* or "role:<role>" (members of the organization with that role). The person who caused the event is never notified.
|
|
205
|
+
*/
|
|
206
|
+
to: string | readonly string[];
|
|
207
|
+
/** Text with {placeholders}: any field of the record, {actor}, {entity}. */
|
|
208
|
+
title: string;
|
|
209
|
+
body?: string;
|
|
210
|
+
/** Where the notification leads. Default: the record's page. */
|
|
211
|
+
link?: string;
|
|
212
|
+
/** Also send an email (templated, queued when the jobs plugin is present). */
|
|
213
|
+
email?: boolean;
|
|
214
|
+
/** Only for updates that changed this field. */
|
|
215
|
+
when?: {
|
|
216
|
+
changed?: string;
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
export interface AppDefinition {
|
|
220
|
+
name: string;
|
|
221
|
+
description?: string;
|
|
222
|
+
database?: {
|
|
223
|
+
provider?: "postgresql";
|
|
224
|
+
};
|
|
225
|
+
auth?: AuthConfig;
|
|
226
|
+
multiTenant?: boolean | MultiTenantConfig;
|
|
227
|
+
/**
|
|
228
|
+
* Roles used by permission rules. "admin" always exists. When multi-tenancy is on,
|
|
229
|
+
* organization member roles (owner → admin, admin, member) are merged in.
|
|
230
|
+
*/
|
|
231
|
+
roles?: readonly string[];
|
|
232
|
+
api?: {
|
|
233
|
+
prefix?: string;
|
|
234
|
+
docs?: boolean;
|
|
235
|
+
};
|
|
236
|
+
/** Client SDKs to generate. Default: TypeScript only (packages/sdk). */
|
|
237
|
+
sdk?: SdkConfig;
|
|
238
|
+
admin?: {
|
|
239
|
+
enabled?: boolean;
|
|
240
|
+
};
|
|
241
|
+
theme?: ThemeConfig;
|
|
242
|
+
/** Plugins such as storage(), jobs(), webhooks(), payments(). */
|
|
243
|
+
plugins?: readonly PluginDefinition[];
|
|
244
|
+
/** Widgets on the home page (metric, chart, list). Default: a count per entity. */
|
|
245
|
+
dashboard?: {
|
|
246
|
+
widgets: readonly DashboardWidget[];
|
|
247
|
+
};
|
|
248
|
+
/** In-app (and optional email) notifications triggered by record events. */
|
|
249
|
+
notifications?: readonly NotificationRule[];
|
|
250
|
+
/**
|
|
251
|
+
* Scheduled database backups (`forge backup` runs them by hand). With the jobs plugin the worker runs
|
|
252
|
+
* them on `schedule` (cron, UTC); otherwise run `forge backup` from cron or CI.
|
|
253
|
+
*/
|
|
254
|
+
backups?: BackupsConfig;
|
|
255
|
+
/** Languages of the admin UI. Translations of your labels live in locales/<locale>.json. */
|
|
256
|
+
i18n?: I18nConfig;
|
|
257
|
+
entities: Record<string, EntityDefinition>;
|
|
258
|
+
/**
|
|
259
|
+
* A public landing page at `/` for signed-out visitors (signed-in users still get the dashboard).
|
|
260
|
+
* `true` builds one from the app's name, description, tagline and entities; an object overrides any part.
|
|
261
|
+
*/
|
|
262
|
+
landing?: boolean | LandingConfig;
|
|
263
|
+
}
|
|
264
|
+
export interface LandingFeature {
|
|
265
|
+
title: string;
|
|
266
|
+
description: string;
|
|
267
|
+
/** Icon name: zap, shield, chart, sparkles, lock, globe, clock, bell, search, heart, rocket, users, calendar… */
|
|
268
|
+
icon?: string;
|
|
269
|
+
}
|
|
270
|
+
export interface LandingConfig {
|
|
271
|
+
/** Default true when the block is present. */
|
|
272
|
+
enabled?: boolean;
|
|
273
|
+
/** Main heading. Default: the theme tagline, else the app name. */
|
|
274
|
+
headline?: string;
|
|
275
|
+
/** Default: the app description. */
|
|
276
|
+
subheadline?: string;
|
|
277
|
+
/** Up to 12 cards. Default: one per entity in the navigation (first 6). */
|
|
278
|
+
features?: readonly LandingFeature[];
|
|
279
|
+
/** Main button. Default: "Get started" → /sign-up (or "Sign in" when registration is off). */
|
|
280
|
+
cta?: {
|
|
281
|
+
label: string;
|
|
282
|
+
href: string;
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
export interface BackupsConfig {
|
|
286
|
+
/** Cron pattern, e.g. "0 3 * * *" (every day at 03:00 UTC). */
|
|
287
|
+
schedule?: string;
|
|
288
|
+
/** Number of backups to keep (older ones are deleted after each backup). Default 14. */
|
|
289
|
+
keep?: number;
|
|
290
|
+
}
|
|
291
|
+
export type SdkLanguage = "typescript" | "python" | "dart";
|
|
292
|
+
export interface SdkConfig {
|
|
293
|
+
/**
|
|
294
|
+
* Languages to generate a typed API client for: "typescript" (packages/sdk), "python" (packages/sdk-python,
|
|
295
|
+
* httpx, sync + async) and "dart" (packages/sdk-dart, package:http, works in Flutter). Default: ["typescript"].
|
|
296
|
+
*/
|
|
297
|
+
languages?: readonly SdkLanguage[];
|
|
298
|
+
}
|
|
299
|
+
export interface I18nConfig {
|
|
300
|
+
/** Language your labels are written in. Default "en". */
|
|
301
|
+
defaultLocale?: string;
|
|
302
|
+
/** Every language users can pick, e.g. ["en", "fr"]. The default locale is always included. */
|
|
303
|
+
locales?: readonly string[];
|
|
304
|
+
}
|
|
305
|
+
export interface AppConfig extends AppDefinition {
|
|
306
|
+
readonly __forge: "app";
|
|
307
|
+
}
|
|
308
|
+
export declare function defineApp(definition: AppDefinition): AppConfig;
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function action(definition = {}) {
|
|
2
|
+
return { __forge: "action", ...definition };
|
|
3
|
+
}
|
|
4
|
+
export function entity(definition) {
|
|
5
|
+
return { __forge: "entity", ...definition };
|
|
6
|
+
}
|
|
7
|
+
export function defineApp(definition) {
|
|
8
|
+
return { __forge: "app", ...definition };
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AA2DA,MAAM,UAAU,MAAM,CAAC,aAAgD,EAAE;IACvE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,UAAU,EAAE,CAAC;AAC9C,CAAC;AAqED,MAAM,UAAU,MAAM,CAAC,UAA6C;IAClE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,UAAU,EAAE,CAAC;AAC9C,CAAC;AAiMD,MAAM,UAAU,SAAS,CAAC,UAAyB;IACjD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,UAAU,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard widgets declared in forge.config.ts. Filters use the same syntax as list query parameters
|
|
3
|
+
* ({ stage: "won", "amount.gte": 1000, owner: "$me" }) plus relative dates: "$today", "$today-30d", "$now", "$startOfMonth".
|
|
4
|
+
*/
|
|
5
|
+
export type WidgetFilter = Record<string, string | number | boolean | readonly (string | number)[]>;
|
|
6
|
+
export type Aggregate = "count" | "sum" | "avg" | "min" | "max";
|
|
7
|
+
interface WidgetBase {
|
|
8
|
+
title: string;
|
|
9
|
+
entity: string;
|
|
10
|
+
where?: WidgetFilter;
|
|
11
|
+
/** Columns in a 3-column grid. Default 1 (charts: 2, lists: 2). */
|
|
12
|
+
span?: 1 | 2 | 3;
|
|
13
|
+
}
|
|
14
|
+
export interface MetricWidget extends WidgetBase {
|
|
15
|
+
readonly type: "metric";
|
|
16
|
+
aggregate?: Aggregate;
|
|
17
|
+
/** Numeric field for sum/avg/min/max. */
|
|
18
|
+
field?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Show the change versus the previous period ("+12% vs previous month") with a sparkline of the last 12 periods.
|
|
21
|
+
* Periods are rolling windows ending now (month = the last month, compared with the month before).
|
|
22
|
+
* Default "month" when the entity has a date to compare on, false when `where` already uses relative dates ($today, $startOfMonth…).
|
|
23
|
+
*/
|
|
24
|
+
compare?: "week" | "month" | "quarter" | "year" | false;
|
|
25
|
+
/** Date or datetime field that places records in a period. Default "createdAt". */
|
|
26
|
+
dateField?: string;
|
|
27
|
+
/** Which direction is good news (colours the change). Default "up-is-good". */
|
|
28
|
+
trend?: "up-is-good" | "down-is-good";
|
|
29
|
+
}
|
|
30
|
+
export interface ChartWidget extends WidgetBase {
|
|
31
|
+
readonly type: "chart";
|
|
32
|
+
chart: "bar" | "line" | "donut";
|
|
33
|
+
/** Enum, boolean or many-to-one relation field — or a date field bucketed by day/week/month/year. */
|
|
34
|
+
groupBy: string | {
|
|
35
|
+
field: string;
|
|
36
|
+
by: "day" | "week" | "month" | "year";
|
|
37
|
+
};
|
|
38
|
+
aggregate?: Aggregate;
|
|
39
|
+
field?: string;
|
|
40
|
+
/** Max categories shown (the rest are grouped as "Other"). Default 8. */
|
|
41
|
+
limit?: number;
|
|
42
|
+
}
|
|
43
|
+
export interface ListWidget extends WidgetBase {
|
|
44
|
+
readonly type: "list";
|
|
45
|
+
/** e.g. "-createdAt" */
|
|
46
|
+
sort?: string;
|
|
47
|
+
limit?: number;
|
|
48
|
+
columns?: readonly string[];
|
|
49
|
+
}
|
|
50
|
+
export type DashboardWidget = MetricWidget | ChartWidget | ListWidget;
|
|
51
|
+
export declare const metric: (w: Omit<MetricWidget, "type">) => MetricWidget;
|
|
52
|
+
export declare const chart: (w: Omit<ChartWidget, "type">) => ChartWidget;
|
|
53
|
+
export declare const list: (w: Omit<ListWidget, "type">) => ListWidget;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAqDA,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAA6B,EAAgB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;AAClG,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAA4B,EAAe,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;AAC9F,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAA2B,EAAc,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC"}
|
package/dist/fields.d.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field builders. Each builder returns a plain, serializable description of a
|
|
3
|
+
* field; the compiler turns these into the normalized IR consumed by generators.
|
|
4
|
+
*/
|
|
5
|
+
export type FieldKind = "string" | "text" | "richtext" | "integer" | "decimal" | "money" | "percentage" | "boolean" | "date" | "datetime" | "enum" | "email" | "url" | "phone" | "color" | "json" | "location" | "file" | "image" | "computed" | "relation";
|
|
6
|
+
export interface BaseFieldOptions {
|
|
7
|
+
label?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
required?: boolean;
|
|
10
|
+
unique?: boolean;
|
|
11
|
+
/** Add a database index on this column. */
|
|
12
|
+
index?: boolean;
|
|
13
|
+
default?: unknown;
|
|
14
|
+
/** Included in the `search` query parameter (text-like fields only). */
|
|
15
|
+
searchable?: boolean;
|
|
16
|
+
/** Exposed as a list filter. */
|
|
17
|
+
filterable?: boolean;
|
|
18
|
+
/** Allowed in the `sort` query parameter. Defaults to true for scalar fields. */
|
|
19
|
+
sortable?: boolean;
|
|
20
|
+
/** Shown as a column in list views. */
|
|
21
|
+
list?: boolean;
|
|
22
|
+
/** Never returned by the API nor rendered in the UI. */
|
|
23
|
+
hidden?: boolean;
|
|
24
|
+
/** Returned by the API but never writable through it. */
|
|
25
|
+
readonly?: boolean;
|
|
26
|
+
placeholder?: string;
|
|
27
|
+
/** Override the UI widget, e.g. "textarea". */
|
|
28
|
+
widget?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Field-level access on top of the entity's permissions. Tokens as in entity permissions
|
|
31
|
+
* (roles, "owner", "authenticated", "policy:<name>"). Unreadable fields are removed from API
|
|
32
|
+
* responses, exports and search; unwritable fields are rejected on create/update.
|
|
33
|
+
*/
|
|
34
|
+
permissions?: {
|
|
35
|
+
read?: readonly string[];
|
|
36
|
+
write?: readonly string[];
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export interface StringFieldOptions extends BaseFieldOptions {
|
|
40
|
+
default?: string;
|
|
41
|
+
minLength?: number;
|
|
42
|
+
maxLength?: number;
|
|
43
|
+
pattern?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface NumberFieldOptions extends BaseFieldOptions {
|
|
46
|
+
default?: number;
|
|
47
|
+
min?: number;
|
|
48
|
+
max?: number;
|
|
49
|
+
}
|
|
50
|
+
export interface DecimalFieldOptions extends NumberFieldOptions {
|
|
51
|
+
precision?: number;
|
|
52
|
+
scale?: number;
|
|
53
|
+
}
|
|
54
|
+
export interface MoneyFieldOptions extends DecimalFieldOptions {
|
|
55
|
+
/** ISO 4217 currency code, e.g. "USD", "EUR", "XOF". */
|
|
56
|
+
currency?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface BooleanFieldOptions extends BaseFieldOptions {
|
|
59
|
+
default?: boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface DateFieldOptions extends BaseFieldOptions {
|
|
62
|
+
/** `"now"` sets the current date/time on create. */
|
|
63
|
+
default?: "now" | string;
|
|
64
|
+
}
|
|
65
|
+
export interface EnumFieldOptions<V extends string = string> extends BaseFieldOptions {
|
|
66
|
+
values: readonly V[] | Record<V, string>;
|
|
67
|
+
default?: V;
|
|
68
|
+
}
|
|
69
|
+
export type RelationType = "many-to-one" | "many-to-many";
|
|
70
|
+
export interface RelationFieldOptions extends BaseFieldOptions {
|
|
71
|
+
/** Target entity name, e.g. "Customer" or the built-in "User". */
|
|
72
|
+
entity: string;
|
|
73
|
+
type?: RelationType;
|
|
74
|
+
/** Marks this relation as the record owner used by `"owner"` permission rules. */
|
|
75
|
+
owner?: boolean;
|
|
76
|
+
onDelete?: "cascade" | "restrict" | "setNull";
|
|
77
|
+
/** Name of the inverse (one-to-many) collection on the target entity. */
|
|
78
|
+
inverse?: string;
|
|
79
|
+
}
|
|
80
|
+
export interface FileFieldOptions extends BaseFieldOptions {
|
|
81
|
+
/** Allowed types: MIME types ("application/pdf", "image/*") or extensions (".docx"). */
|
|
82
|
+
accept?: readonly string[];
|
|
83
|
+
/** Max size, e.g. "10MB", "500KB" or bytes. Default 10MB (image: 5MB). */
|
|
84
|
+
maxSize?: string | number;
|
|
85
|
+
}
|
|
86
|
+
export type ComputedType = "integer" | "decimal" | "money" | "percentage" | "string" | "boolean" | "date" | "datetime";
|
|
87
|
+
export interface ComputedFieldOptions extends Omit<BaseFieldOptions, "required" | "unique" | "default" | "readonly"> {
|
|
88
|
+
/** Result type — decides storage, formatting and sorting. */
|
|
89
|
+
type: ComputedType;
|
|
90
|
+
/**
|
|
91
|
+
* Safe expression over this entity's fields, e.g. "quantity * unitPrice", "round(total * 0.18, 2)",
|
|
92
|
+
* "concat(firstName, ' ', lastName)" or an aggregate over a one-to-many relation: "sum(lines.amount)".
|
|
93
|
+
* The value is stored and recomputed on every write (so it can be sorted and filtered).
|
|
94
|
+
*/
|
|
95
|
+
expression: string;
|
|
96
|
+
currency?: string;
|
|
97
|
+
precision?: number;
|
|
98
|
+
scale?: number;
|
|
99
|
+
}
|
|
100
|
+
export interface FieldDefinition<K extends FieldKind = FieldKind, O extends BaseFieldOptions = BaseFieldOptions> {
|
|
101
|
+
readonly __forge: "field";
|
|
102
|
+
readonly kind: K;
|
|
103
|
+
readonly options: O;
|
|
104
|
+
}
|
|
105
|
+
export declare const string: (o?: StringFieldOptions) => FieldDefinition<"string", StringFieldOptions>;
|
|
106
|
+
export declare const text: (o?: StringFieldOptions) => FieldDefinition<"text", StringFieldOptions>;
|
|
107
|
+
export declare const richtext: (o?: StringFieldOptions) => FieldDefinition<"richtext", StringFieldOptions>;
|
|
108
|
+
export declare const email: (o?: StringFieldOptions) => FieldDefinition<"email", StringFieldOptions>;
|
|
109
|
+
export declare const url: (o?: StringFieldOptions) => FieldDefinition<"url", StringFieldOptions>;
|
|
110
|
+
export declare const phone: (o?: StringFieldOptions) => FieldDefinition<"phone", StringFieldOptions>;
|
|
111
|
+
export declare const color: (o?: StringFieldOptions) => FieldDefinition<"color", StringFieldOptions>;
|
|
112
|
+
export declare const integer: (o?: NumberFieldOptions) => FieldDefinition<"integer", NumberFieldOptions>;
|
|
113
|
+
export declare const decimal: (o?: DecimalFieldOptions) => FieldDefinition<"decimal", DecimalFieldOptions>;
|
|
114
|
+
export declare const money: (o?: MoneyFieldOptions) => FieldDefinition<"money", MoneyFieldOptions>;
|
|
115
|
+
export declare const percentage: (o?: NumberFieldOptions) => FieldDefinition<"percentage", NumberFieldOptions>;
|
|
116
|
+
export declare const boolean: (o?: BooleanFieldOptions) => FieldDefinition<"boolean", BooleanFieldOptions>;
|
|
117
|
+
export declare const date: (o?: DateFieldOptions) => FieldDefinition<"date", DateFieldOptions>;
|
|
118
|
+
export declare const datetime: (o?: DateFieldOptions) => FieldDefinition<"datetime", DateFieldOptions>;
|
|
119
|
+
export declare const json: (o?: BaseFieldOptions) => FieldDefinition<"json", BaseFieldOptions>;
|
|
120
|
+
export declare const enumeration: <V extends string>(o: EnumFieldOptions<V>) => FieldDefinition<"enum", EnumFieldOptions<V>>;
|
|
121
|
+
export declare const relation: (o: RelationFieldOptions) => FieldDefinition<"relation", RelationFieldOptions>;
|
|
122
|
+
/** Latitude/longitude pair, e.g. for the map view. */
|
|
123
|
+
export declare const location: (o?: BaseFieldOptions) => FieldDefinition<"location", BaseFieldOptions>;
|
|
124
|
+
/** A file stored in the app's object storage (requires the storage plugin). */
|
|
125
|
+
export declare const file: (o?: FileFieldOptions) => FieldDefinition<"file", FileFieldOptions>;
|
|
126
|
+
/** An image (PNG, JPEG, GIF, WebP, AVIF) stored in object storage (requires the storage plugin). */
|
|
127
|
+
export declare const image: (o?: FileFieldOptions) => FieldDefinition<"image", FileFieldOptions>;
|
|
128
|
+
/** A read-only value derived from other fields, stored and kept up to date by Forge. */
|
|
129
|
+
export declare const computed: (o: ComputedFieldOptions) => FieldDefinition<"computed", ComputedFieldOptions>;
|
|
130
|
+
export type AnyField = FieldDefinition<FieldKind, any>;
|
package/dist/fields.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field builders. Each builder returns a plain, serializable description of a
|
|
3
|
+
* field; the compiler turns these into the normalized IR consumed by generators.
|
|
4
|
+
*/
|
|
5
|
+
function field(kind, options) {
|
|
6
|
+
return { __forge: "field", kind, options };
|
|
7
|
+
}
|
|
8
|
+
export const string = (o = {}) => field("string", o);
|
|
9
|
+
export const text = (o = {}) => field("text", o);
|
|
10
|
+
export const richtext = (o = {}) => field("richtext", o);
|
|
11
|
+
export const email = (o = {}) => field("email", o);
|
|
12
|
+
export const url = (o = {}) => field("url", o);
|
|
13
|
+
export const phone = (o = {}) => field("phone", o);
|
|
14
|
+
export const color = (o = {}) => field("color", o);
|
|
15
|
+
export const integer = (o = {}) => field("integer", o);
|
|
16
|
+
export const decimal = (o = {}) => field("decimal", o);
|
|
17
|
+
export const money = (o = {}) => field("money", o);
|
|
18
|
+
export const percentage = (o = {}) => field("percentage", o);
|
|
19
|
+
export const boolean = (o = {}) => field("boolean", o);
|
|
20
|
+
export const date = (o = {}) => field("date", o);
|
|
21
|
+
export const datetime = (o = {}) => field("datetime", o);
|
|
22
|
+
export const json = (o = {}) => field("json", o);
|
|
23
|
+
export const enumeration = (o) => field("enum", o);
|
|
24
|
+
export const relation = (o) => field("relation", o);
|
|
25
|
+
/** Latitude/longitude pair, e.g. for the map view. */
|
|
26
|
+
export const location = (o = {}) => field("location", o);
|
|
27
|
+
/** A file stored in the app's object storage (requires the storage plugin). */
|
|
28
|
+
export const file = (o = {}) => field("file", o);
|
|
29
|
+
/** An image (PNG, JPEG, GIF, WebP, AVIF) stored in object storage (requires the storage plugin). */
|
|
30
|
+
export const image = (o = {}) => field("image", o);
|
|
31
|
+
/** A read-only value derived from other fields, stored and kept up to date by Forge. */
|
|
32
|
+
export const computed = (o) => field("computed", o);
|
|
33
|
+
//# sourceMappingURL=fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fields.js","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { EntityDefinition } from "./app.js";
|
|
2
|
+
/** A container added to docker-compose.yml by a plugin (Compose service syntax). */
|
|
3
|
+
export interface PluginDockerService {
|
|
4
|
+
image: string;
|
|
5
|
+
command?: string | string[];
|
|
6
|
+
environment?: Record<string, string>;
|
|
7
|
+
ports?: string[];
|
|
8
|
+
volumes?: string[];
|
|
9
|
+
healthcheck?: {
|
|
10
|
+
test: string[];
|
|
11
|
+
interval?: string;
|
|
12
|
+
timeout?: string;
|
|
13
|
+
retries?: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface PluginEnvVar {
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
/** Value written to .env for local development. */
|
|
20
|
+
default?: string;
|
|
21
|
+
/** Value inside docker-compose (service names instead of localhost). */
|
|
22
|
+
docker?: string;
|
|
23
|
+
required?: boolean;
|
|
24
|
+
secret?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* What a plugin contributes. Plugin packages export a factory returning this from their root
|
|
28
|
+
* (kept tiny so forge.config.ts loads fast); runtime code lives in the package's ./api, ./worker and ./web exports.
|
|
29
|
+
*/
|
|
30
|
+
export interface PluginDefinition {
|
|
31
|
+
readonly __forge: "plugin";
|
|
32
|
+
/** Unique name, e.g. "storage". */
|
|
33
|
+
name: string;
|
|
34
|
+
/** npm package providing the runtime, e.g. "@tekki-forge/plugin-storage". */
|
|
35
|
+
package: string;
|
|
36
|
+
version?: string;
|
|
37
|
+
/** JSON-serializable options, passed to the runtime. */
|
|
38
|
+
options?: Record<string, unknown>;
|
|
39
|
+
/** Other plugins this one needs, e.g. webhooks → ["jobs"]. */
|
|
40
|
+
requires?: readonly string[];
|
|
41
|
+
/** Entities added to the schema. */
|
|
42
|
+
entities?: Record<string, EntityDefinition>;
|
|
43
|
+
/** URL segments under /api the plugin serves (so no entity can use them). */
|
|
44
|
+
reservedPaths?: readonly string[];
|
|
45
|
+
/** Which runtime entry points the package exports. */
|
|
46
|
+
runtime?: {
|
|
47
|
+
api?: boolean;
|
|
48
|
+
worker?: boolean;
|
|
49
|
+
web?: boolean;
|
|
50
|
+
};
|
|
51
|
+
env?: readonly PluginEnvVar[];
|
|
52
|
+
docker?: {
|
|
53
|
+
services?: Record<string, PluginDockerService>;
|
|
54
|
+
volumes?: readonly string[];
|
|
55
|
+
};
|
|
56
|
+
/** Navigation entries in the admin UI. `admin: true` shows them to admins only. */
|
|
57
|
+
nav?: readonly {
|
|
58
|
+
label: string;
|
|
59
|
+
path: string;
|
|
60
|
+
icon?: string;
|
|
61
|
+
admin?: boolean;
|
|
62
|
+
}[];
|
|
63
|
+
}
|
|
64
|
+
export declare function definePlugin(definition: Omit<PluginDefinition, "__forge">): PluginDefinition;
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAkDA,MAAM,UAAU,YAAY,CAAC,UAA6C;IACxE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,UAAU,EAAE,CAAC;AAC9C,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tekki-forge/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Forge schema DSL: defineApp, entity and field builders",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"code-generator",
|
|
7
|
+
"forge",
|
|
8
|
+
"full-stack",
|
|
9
|
+
"tekki-forge"
|
|
10
|
+
],
|
|
11
|
+
"author": "Mahy KANE",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=22"
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc -p tsconfig.json",
|
|
34
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
35
|
+
}
|
|
36
|
+
}
|