tina4-nodejs 3.13.147 → 3.13.149
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/CLAUDE.md +4 -3
- package/package.json +1 -1
- package/packages/cli/dist/bin.js +10901 -9855
- package/packages/cli/src/commands/generate.ts +184 -25
- package/packages/core/dist/index.js +10874 -9828
- package/packages/core/src/devAdmin.ts +72 -1
- package/packages/core/src/dispatchPipeline.ts +4 -12
- package/packages/core/src/index.ts +3 -0
- package/packages/core/src/messenger.ts +57 -1
- package/packages/core/src/router.ts +11 -1
- package/packages/core/src/server.ts +5 -2
- package/packages/core/src/session.ts +45 -3
- package/packages/core/templates/crud/form.twig +26 -0
- package/packages/core/templates/crud/modals.twig +31 -0
- package/packages/core/templates/crud/page.twig +401 -0
- package/packages/core/templates/crud/table.twig +69 -0
- package/packages/frond/dist/index.js +9 -1
- package/packages/frond/src/engine.ts +9 -0
- package/packages/frond/src/index.ts +1 -1
- package/packages/orm/dist/index.js +1283 -227
- package/packages/orm/src/adapters/mongodb.ts +209 -34
- package/packages/orm/src/autoCrud.ts +9 -0
- package/packages/orm/src/crud.ts +273 -0
- package/packages/orm/src/crudHelpers.ts +194 -0
- package/packages/orm/src/crudRender.ts +202 -0
- package/packages/orm/src/crudTable.ts +171 -0
- package/packages/orm/src/index.ts +7 -1
- package/packages/orm/src/migration.ts +167 -4
- package/packages/orm/src/query.ts +99 -40
- package/packages/orm/src/sqlTranslator.ts +8 -1
- package/packages/orm/src/types.ts +19 -0
- package/types/core/src/devAdmin.d.ts +23 -0
- package/types/core/src/messenger.d.ts +4 -0
- package/types/core/src/router.d.ts +0 -5
- package/types/core/src/session.d.ts +25 -0
- package/types/frond/src/engine.d.ts +6 -0
- package/types/frond/src/index.d.ts +1 -1
- package/types/orm/src/crud.d.ts +82 -0
- package/types/orm/src/crudHelpers.d.ts +63 -0
- package/types/orm/src/crudRender.d.ts +38 -0
- package/types/orm/src/crudTable.d.ts +45 -0
- package/types/orm/src/index.d.ts +3 -1
- package/types/orm/src/migration.d.ts +0 -18
- package/types/orm/src/query.d.ts +0 -12
- package/types/orm/src/types.d.ts +19 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crud (ADR-0094) — the pure helpers behind the HTML admin page.
|
|
3
|
+
*
|
|
4
|
+
* No I/O, no templates, no DB: column/label/alignment derivation, safe-sort
|
|
5
|
+
* resolution, the pre-joined table-data hash, the pagination controls, the
|
|
6
|
+
* injected JS config, and the two linear SQL-listing parsers. Kept in their own
|
|
7
|
+
* module so `crud.ts` stays a thin orchestrator and no single file carries the
|
|
8
|
+
* whole feature (the second-pass split by concern).
|
|
9
|
+
*/
|
|
10
|
+
import { escapeHtml } from "../../frond/src/engine.js";
|
|
11
|
+
/** A BaseModel-like class: the statics Crud reads + the query statics it calls. */
|
|
12
|
+
export interface CrudModel {
|
|
13
|
+
tableName: string;
|
|
14
|
+
fields: Record<string, {
|
|
15
|
+
type?: string;
|
|
16
|
+
primaryKey?: boolean;
|
|
17
|
+
[k: string]: unknown;
|
|
18
|
+
}>;
|
|
19
|
+
fieldMapping?: Record<string, string>;
|
|
20
|
+
softDelete?: boolean;
|
|
21
|
+
tableFilter?: string;
|
|
22
|
+
name?: string;
|
|
23
|
+
all(limit?: number, offset?: number, include?: string[], orderBy?: string): Promise<any>;
|
|
24
|
+
where(conditions: string, params?: unknown[], limit?: number, offset?: number, include?: string[], orderBy?: string): Promise<any>;
|
|
25
|
+
count(conditions?: string, params?: unknown[]): Promise<number>;
|
|
26
|
+
}
|
|
27
|
+
/** Escape alias used throughout the CRUD HTML assembly. */
|
|
28
|
+
export declare const h: typeof escapeHtml;
|
|
29
|
+
/** The DB column a property name maps to (fieldMapping or the property itself). */
|
|
30
|
+
export declare function columnOf(model: CrudModel, prop: string): string;
|
|
31
|
+
/** The primary-key property name (the field flagged primaryKey, else "id"). */
|
|
32
|
+
export declare function primaryKeyProp(model: CrudModel): string;
|
|
33
|
+
/** The model's declared string/text property names. */
|
|
34
|
+
export declare function searchableProps(model: CrudModel): string[];
|
|
35
|
+
/** Column alignment from the field type: numeric right, everything else left. */
|
|
36
|
+
export declare function columnAlignment(model: CrudModel | null, col: string): string;
|
|
37
|
+
/** Pretty label from a column name: "user_name" => "User Name". */
|
|
38
|
+
export declare function prettyLabel(col: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* ADR-0069 safe sort: resolve the requested sort to a declared field PROPERTY
|
|
41
|
+
* (the grid's headers + client state are keyed by property), else the primary
|
|
42
|
+
* key. A request may name the field by its property or its mapped column; the
|
|
43
|
+
* DB column for the ORDER BY is derived with columnOf(). A rendered page ignores
|
|
44
|
+
* a bad sort rather than erroring.
|
|
45
|
+
*/
|
|
46
|
+
export declare function crudSortProp(model: CrudModel, requested: string | undefined, pkProp: string): string;
|
|
47
|
+
/** Read one column value from a record hash (keyed by property name). */
|
|
48
|
+
export declare function cellValue(record: Record<string, unknown>, col: string): unknown;
|
|
49
|
+
/** Build the pre-joined <td> run for one row (every value escaped + aligned). */
|
|
50
|
+
export declare function buildCells(columns: string[], record: Record<string, unknown>, editable: boolean, aligns: string[]): string;
|
|
51
|
+
/**
|
|
52
|
+
* Drop a trailing ORDER BY / LIMIT clause from each line of a custom listing SQL.
|
|
53
|
+
* Pure string scanning — no backtracking regex.
|
|
54
|
+
*/
|
|
55
|
+
export declare function stripOrderAndLimit(sql: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* The column names a custom listing SQL selects (for the search CAST LIKE).
|
|
58
|
+
* Linear string scan: locate the first SELECT / FROM keywords (whitespace
|
|
59
|
+
* bounded, case-insensitive) and split the projection on commas — no
|
|
60
|
+
* backtracking regex over caller-supplied SQL (ReDoS-safe), mirroring the
|
|
61
|
+
* Ruby master's plain-string SQL parsing.
|
|
62
|
+
*/
|
|
63
|
+
export declare function extractColumns(sql: string): string[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render a crud/<name>.twig template, app-first-then-framework: an app override
|
|
3
|
+
* at src/templates/crud/<name>.twig wins over the framework's shipped copy (the
|
|
4
|
+
* same resolution the error pages use).
|
|
5
|
+
*/
|
|
6
|
+
export declare function renderCrudTemplate(name: string, data: Record<string, unknown>): string;
|
|
7
|
+
/** Render the create/edit/delete modal shell (crud/modals.twig). */
|
|
8
|
+
export declare function renderModals(editableColumns: string[], pk: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Render an HTML table fragment from an array of record hashes via crud/table.twig.
|
|
11
|
+
* Inline-editable (contenteditable cells + Save/Delete wired by the template's
|
|
12
|
+
* delegated listener). Synchronous — no model, no DB.
|
|
13
|
+
*/
|
|
14
|
+
export declare function generateTable(records: Array<Record<string, unknown>> | null | undefined, options?: {
|
|
15
|
+
tableName?: string;
|
|
16
|
+
primaryKey?: string;
|
|
17
|
+
editable?: boolean;
|
|
18
|
+
}): string;
|
|
19
|
+
export interface FormFieldDef {
|
|
20
|
+
name: string;
|
|
21
|
+
type?: string;
|
|
22
|
+
label?: string;
|
|
23
|
+
value?: unknown;
|
|
24
|
+
required?: boolean;
|
|
25
|
+
options?: Array<{
|
|
26
|
+
value: unknown;
|
|
27
|
+
label: unknown;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Render an HTML form from a field-definition array via crud/form.twig.
|
|
32
|
+
* Synchronous — no model, no DB.
|
|
33
|
+
*/
|
|
34
|
+
export declare function generateForm(fields: FormFieldDef[], options?: {
|
|
35
|
+
action?: string;
|
|
36
|
+
method?: string;
|
|
37
|
+
tableName?: string;
|
|
38
|
+
}): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crud (ADR-0094) — table + pagination assembly.
|
|
3
|
+
*
|
|
4
|
+
* The sort links, the pagination controls, the injected JS config, and the
|
|
5
|
+
* pre-joined table-data hash the crud/table.twig template consumes. Split from
|
|
6
|
+
* crudHelpers so neither file carries the whole feature (one concern per file).
|
|
7
|
+
*/
|
|
8
|
+
import { type CrudModel } from "./crudHelpers.js";
|
|
9
|
+
export declare function sortIndicator(sortCol: string, col: string, sortDir: string): string;
|
|
10
|
+
export declare function sortUrl(requestPath: string, col: string, nextDir: string, page: number, search: string, limit: number): string;
|
|
11
|
+
export declare function pageUrl(requestPath: string, p: number, search: string, sortCol: string, sortDir: string, limit: number): string;
|
|
12
|
+
/** One flat list of pagination controls (Prev, numbered pages, Next). */
|
|
13
|
+
export declare function pageControls(page: number, totalPages: number, requestPath: string, search: string, sortCol: string, sortDir: string, limit: number): Array<Record<string, unknown>>;
|
|
14
|
+
/** The JSON config injected into the page's nonce'd <script>. */
|
|
15
|
+
export declare function jsConfig(opts: {
|
|
16
|
+
apiPath: string;
|
|
17
|
+
pk: string;
|
|
18
|
+
columns: string[];
|
|
19
|
+
editable: string[];
|
|
20
|
+
model: CrudModel;
|
|
21
|
+
limit: number;
|
|
22
|
+
search: string;
|
|
23
|
+
sortCol: string;
|
|
24
|
+
sortDir: string;
|
|
25
|
+
page: number;
|
|
26
|
+
}): string;
|
|
27
|
+
export interface TableDataOpts {
|
|
28
|
+
columns: string[];
|
|
29
|
+
records: Array<Record<string, unknown>>;
|
|
30
|
+
pk: string;
|
|
31
|
+
tableName: string;
|
|
32
|
+
editable: boolean;
|
|
33
|
+
sortable: boolean;
|
|
34
|
+
inlineScript: boolean;
|
|
35
|
+
requestPath: string;
|
|
36
|
+
search: string;
|
|
37
|
+
sortCol: string;
|
|
38
|
+
sortDir: string;
|
|
39
|
+
page: number;
|
|
40
|
+
limit: number;
|
|
41
|
+
tableId: string | null;
|
|
42
|
+
model: CrudModel | null;
|
|
43
|
+
}
|
|
44
|
+
/** Build the data hash crud/table.twig consumes (headers + pre-joined rows). */
|
|
45
|
+
export declare function tableData(opts: TableDataOpts): Record<string, unknown>;
|
package/types/orm/src/index.d.ts
CHANGED
|
@@ -15,7 +15,9 @@ export { syncModels, ensureMigrationTable, getNextBatch, isMigrationApplied, rec
|
|
|
15
15
|
export type { MigrationResult, MigrationStatus } from "./migration.js";
|
|
16
16
|
export { AutoCrud, generateCrudRoutes, crudEligibleModels } from "./autoCrud.js";
|
|
17
17
|
export type { AutoCrudOptions } from "./autoCrud.js";
|
|
18
|
-
export {
|
|
18
|
+
export { Crud, CRUD, toCrud, registerBackend, generateTable, generateForm, stripOrderAndLimit, _resetCrudRegistrations } from "./crud.js";
|
|
19
|
+
export type { ToCrudOptions, CrudModel, FormFieldDef } from "./crud.js";
|
|
20
|
+
export { buildQuery, parseQueryString, resolveField, resolveFieldColumn, UnknownFieldError, InvalidQueryParameterError } from "./query.js";
|
|
19
21
|
export { validate } from "./validation.js";
|
|
20
22
|
export type { ValidationError } from "./validation.js";
|
|
21
23
|
export { BaseModel, snakeToCamel, camelToSnake } from "./baseModel.js";
|
|
@@ -181,24 +181,6 @@ export declare function splitStatements(sql: string, delimiter?: string): string
|
|
|
181
181
|
* AFTER the numbered ones, then lexically. Mirrors Python's `_migration_sort_key`.
|
|
182
182
|
*/
|
|
183
183
|
export declare function sortMigrationFiles(files: string[]): string[];
|
|
184
|
-
/**
|
|
185
|
-
* Run all pending SQL-file migrations.
|
|
186
|
-
*
|
|
187
|
-
* Supports both naming patterns:
|
|
188
|
-
* - Sequential: 000001_description.sql
|
|
189
|
-
* - Timestamp: YYYYMMDDHHMMSS_description.sql
|
|
190
|
-
*
|
|
191
|
-
* 1. Creates the `tina4_migration` tracking table if it doesn't exist.
|
|
192
|
-
* 2. Scans `migrationsDir` for `.sql` files (excluding `.down.sql`), sorted.
|
|
193
|
-
* 3. Skips files already recorded as applied.
|
|
194
|
-
* 4. Splits file content on `delimiter` and executes each statement.
|
|
195
|
-
* 5. On success records the migration with the current batch number.
|
|
196
|
-
* 6. On error logs and continues.
|
|
197
|
-
* 7. Returns a summary of applied / skipped / failed files.
|
|
198
|
-
*
|
|
199
|
-
* @param adapter - A DatabaseAdapter instance (or omit to use the global adapter).
|
|
200
|
-
* @param options - Optional configuration.
|
|
201
|
-
*/
|
|
202
184
|
export declare function migrate(adapter?: DatabaseAdapter, options?: {
|
|
203
185
|
migrationsDir?: string;
|
|
204
186
|
delimiter?: string;
|
package/types/orm/src/query.d.ts
CHANGED
|
@@ -36,18 +36,6 @@ export declare class UnknownFieldError extends Error {
|
|
|
36
36
|
export declare class InvalidQueryParameterError extends Error {
|
|
37
37
|
constructor(message: string);
|
|
38
38
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Build the list SQL from parsed query options.
|
|
41
|
-
*
|
|
42
|
-
* `quote` renders every table/column name the builder emits - pass the bound
|
|
43
|
-
* adapter's dialect (`(name) => quoteIdentifier(adapter, name)`); the default is
|
|
44
|
-
* the ANSI `"name"`.
|
|
45
|
-
*
|
|
46
|
-
* Every filter key and sort field is passed through `resolveColumn` (see
|
|
47
|
-
* resolveFieldColumn) and only the column it returns is emitted; a key it does
|
|
48
|
-
* not resolve throws UnknownFieldError before any SQL exists. With no
|
|
49
|
-
* resolver, no filter or sort key resolves (ADR-0069).
|
|
50
|
-
*/
|
|
51
39
|
export declare function buildQuery(tableName: string, options: QueryOptions, extraConditions?: string[], quote?: (name: string) => string, resolveColumn?: (key: string) => string | null): {
|
|
52
40
|
sql: string;
|
|
53
41
|
countSql: string;
|
package/types/orm/src/types.d.ts
CHANGED
|
@@ -187,4 +187,23 @@ export interface QueryOptions {
|
|
|
187
187
|
sort?: string;
|
|
188
188
|
page?: number;
|
|
189
189
|
limit?: number;
|
|
190
|
+
/**
|
|
191
|
+
* ADR-0094: full-text search term. LIKE %term% is OR'd across `searchColumns`
|
|
192
|
+
* and added to the WHERE before limit/offset, so the total reflects the
|
|
193
|
+
* filtered set. The CRUD admin grid (and any client) drives this via ?search=.
|
|
194
|
+
*/
|
|
195
|
+
search?: string;
|
|
196
|
+
/**
|
|
197
|
+
* DB columns the `search` term matches against (the model's declared
|
|
198
|
+
* string/text columns, already resolved to their mapped column names). The
|
|
199
|
+
* caller resolves these from the model; buildQuery only quotes and binds them,
|
|
200
|
+
* so nothing but a declared column can reach SQL (ADR-0069).
|
|
201
|
+
*/
|
|
202
|
+
searchColumns?: string[];
|
|
203
|
+
/**
|
|
204
|
+
* ADR-0094: direction for a single bare ?sort=column (the CRUD grid's
|
|
205
|
+
* spelling). "desc" sorts descending; anything else ascending. Ignored for a
|
|
206
|
+
* Mongo-style "-field,field" sort, which carries its own inline direction.
|
|
207
|
+
*/
|
|
208
|
+
sortDir?: string;
|
|
190
209
|
}
|