@happyvertical/smrt-core 0.40.69 → 0.40.70
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/AGENTS.md +29 -4
- package/README.md +20 -1
- package/agents/query-bounds.md +45 -0
- package/agents/schema-paths.md +328 -0
- package/dist/browser.d.ts +1 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2 -1
- package/dist/class.d.ts.map +1 -1
- package/dist/class.js +28 -4
- package/dist/class.js.map +1 -1
- package/dist/collection.d.ts +101 -2
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +224 -43
- package/dist/collection.js.map +1 -1
- package/dist/database.d.ts +8 -0
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +16 -8
- package/dist/database.js.map +1 -1
- package/dist/db-errors.d.ts +105 -0
- package/dist/db-errors.d.ts.map +1 -0
- package/dist/db-errors.js +382 -0
- package/dist/db-errors.js.map +1 -0
- package/dist/decorators/index.d.ts +17 -1
- package/dist/decorators/index.d.ts.map +1 -1
- package/dist/decorators/index.js +65 -7
- package/dist/decorators/index.js.map +1 -1
- package/dist/dispatch/bus.d.ts.map +1 -1
- package/dist/dispatch/bus.js +4 -3
- package/dist/dispatch/bus.js.map +1 -1
- package/dist/errors.d.ts +30 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +34 -2
- package/dist/errors.js.map +1 -1
- package/dist/generators/changes-route.d.ts.map +1 -1
- package/dist/generators/changes-route.js +6 -3
- package/dist/generators/changes-route.js.map +1 -1
- package/dist/generators/mcp-runtime-template.d.ts +8 -0
- package/dist/generators/mcp-runtime-template.d.ts.map +1 -1
- package/dist/generators/mcp-runtime-template.js +38 -4
- package/dist/generators/mcp-runtime-template.js.map +1 -1
- package/dist/generators/mcp.d.ts +16 -0
- package/dist/generators/mcp.d.ts.map +1 -1
- package/dist/generators/mcp.js +41 -3
- package/dist/generators/mcp.js.map +1 -1
- package/dist/generators/rest.d.ts +22 -0
- package/dist/generators/rest.d.ts.map +1 -1
- package/dist/generators/rest.js +34 -3
- package/dist/generators/rest.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/manifest/static-manifest.js +1 -1
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.js +1 -1
- package/dist/manifest.json +1 -1
- package/dist/migrations/differ.d.ts +202 -8
- package/dist/migrations/differ.d.ts.map +1 -1
- package/dist/migrations/differ.js +604 -46
- package/dist/migrations/differ.js.map +1 -1
- package/dist/migrations/generator.d.ts +31 -4
- package/dist/migrations/generator.d.ts.map +1 -1
- package/dist/migrations/generator.js +49 -5
- package/dist/migrations/generator.js.map +1 -1
- package/dist/migrations/index.d.ts +3 -2
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +5 -3
- package/dist/migrations/orchestrate.js +35 -6
- package/dist/migrations/orchestrate.js.map +1 -1
- package/dist/migrations/sqlite-rebuild.d.ts +142 -0
- package/dist/migrations/sqlite-rebuild.d.ts.map +1 -0
- package/dist/migrations/sqlite-rebuild.js +514 -0
- package/dist/migrations/sqlite-rebuild.js.map +1 -0
- package/dist/migrations/tracker.d.ts +114 -1
- package/dist/migrations/tracker.d.ts.map +1 -1
- package/dist/migrations/tracker.js +331 -16
- package/dist/migrations/tracker.js.map +1 -1
- package/dist/migrations/types.d.ts +19 -4
- package/dist/migrations/types.d.ts.map +1 -1
- package/dist/migrations.js +5 -3
- package/dist/object.d.ts +45 -6
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +60 -13
- package/dist/object.js.map +1 -1
- package/dist/postgres-timeouts.d.ts +240 -0
- package/dist/postgres-timeouts.d.ts.map +1 -0
- package/dist/postgres-timeouts.js +204 -0
- package/dist/postgres-timeouts.js.map +1 -0
- package/dist/query-bounds.d.ts +97 -0
- package/dist/query-bounds.d.ts.map +1 -0
- package/dist/query-bounds.js +173 -0
- package/dist/query-bounds.js.map +1 -0
- package/dist/registry/types.d.ts +32 -1
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry.js +1 -1
- package/dist/scanner/types.d.ts +5 -0
- package/dist/scanner/types.d.ts.map +1 -1
- package/dist/scanner/types.js.map +1 -1
- package/dist/schema/ddl/base-strategy.d.ts.map +1 -1
- package/dist/schema/ddl/base-strategy.js +2 -2
- package/dist/schema/ddl/base-strategy.js.map +1 -1
- package/dist/schema/generator.d.ts +70 -5
- package/dist/schema/generator.d.ts.map +1 -1
- package/dist/schema/generator.js +124 -6
- package/dist/schema/generator.js.map +1 -1
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +4 -1
- package/dist/schema/live-parity.d.ts +90 -0
- package/dist/schema/live-parity.d.ts.map +1 -0
- package/dist/schema/live-parity.js +600 -0
- package/dist/schema/live-parity.js.map +1 -0
- package/dist/schema/manifest-schema.d.ts +121 -0
- package/dist/schema/manifest-schema.d.ts.map +1 -0
- package/dist/schema/manifest-schema.js +267 -0
- package/dist/schema/manifest-schema.js.map +1 -0
- package/dist/schema/schema-aggregator.d.ts +24 -10
- package/dist/schema/schema-aggregator.d.ts.map +1 -1
- package/dist/schema/schema-aggregator.js +35 -90
- package/dist/schema/schema-aggregator.js.map +1 -1
- package/dist/schema/system-table-shapes.d.ts +52 -0
- package/dist/schema/system-table-shapes.d.ts.map +1 -0
- package/dist/schema/system-table-shapes.js +174 -0
- package/dist/schema/system-table-shapes.js.map +1 -0
- package/dist/schema/types.d.ts +103 -4
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/utils.d.ts +1 -0
- package/dist/schema/utils.d.ts.map +1 -1
- package/dist/schema/utils.js +3 -1
- package/dist/schema/utils.js.map +1 -1
- package/dist/schema.js +4 -1
- package/dist/smrt-knowledge.json +18 -6
- package/dist/sync/apply.d.ts.map +1 -1
- package/dist/sync/apply.js +9 -16
- package/dist/sync/apply.js.map +1 -1
- package/dist/testing/database.d.ts.map +1 -1
- package/dist/testing/database.js +1 -0
- package/dist/testing/database.js.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
- package/dist/vite-plugin/sveltekit-generator.js +71 -5
- package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
- package/dist/vite-plugin/web-collections.d.ts.map +1 -1
- package/dist/vite-plugin/web-collections.js +6 -4
- package/dist/vite-plugin/web-collections.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { ValidationError } from "./errors.js";
|
|
2
|
+
//#region src/query-bounds.ts
|
|
3
|
+
/**
|
|
4
|
+
* Query bounds for list surfaces (#2367).
|
|
5
|
+
*
|
|
6
|
+
* Every generated read surface — REST, SvelteKit routes, the MCP server and the
|
|
7
|
+
* MCP runtime bootstrap — takes `limit`/`offset` straight from untrusted input.
|
|
8
|
+
* Before this module each one parsed them by hand, and each got it wrong in a
|
|
9
|
+
* different way: `Number.parseInt('abc')` produced `LIMIT NaN` (a 500 from the
|
|
10
|
+
* driver, not a 400 from the API), `Number(x) || 50` silently turned `0` into
|
|
11
|
+
* `50`, and none of them capped the value, so `?limit=100000000` was a
|
|
12
|
+
* single-request table scan on every generated endpoint.
|
|
13
|
+
*
|
|
14
|
+
* This is the one parser they all share. It is deliberately strict on the input
|
|
15
|
+
* (a bound is a non-negative integer or it is a client error) and deliberately
|
|
16
|
+
* forgiving on magnitude (an oversized page is clamped, not rejected, so a
|
|
17
|
+
* caller paging with a too-large window still makes progress instead of
|
|
18
|
+
* receiving an error it cannot act on).
|
|
19
|
+
*
|
|
20
|
+
* The bounds themselves are also available to `SmrtCollection.list()` through
|
|
21
|
+
* the `defaultListLimit` / `maxListLimit` collection options. Those are opt-in:
|
|
22
|
+
* `list()` is the framework's own bulk-read primitive and dozens of internal
|
|
23
|
+
* callers (relationship loaders, junction hydration, `listByIds`) legitimately
|
|
24
|
+
* expect every matching row, so a framework-wide implicit default would
|
|
25
|
+
* silently truncate results rather than bound an attack surface. The bound
|
|
26
|
+
* belongs where untrusted input arrives, which is why the generated surfaces
|
|
27
|
+
* apply it unconditionally and direct programmatic callers opt in.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Page size a generated list surface uses when the caller supplies none.
|
|
31
|
+
*
|
|
32
|
+
* Matches the value the REST and SvelteKit generators already hard-coded, so
|
|
33
|
+
* adopting the shared parser is not a behavior change for callers that omit
|
|
34
|
+
* `limit`.
|
|
35
|
+
*/
|
|
36
|
+
var DEFAULT_LIST_LIMIT = 50;
|
|
37
|
+
/**
|
|
38
|
+
* Largest page a generated list surface will serve.
|
|
39
|
+
*
|
|
40
|
+
* Matches the cap `MCPGenerator` already applied in-process, now enforced on
|
|
41
|
+
* every generated surface rather than one of them.
|
|
42
|
+
*/
|
|
43
|
+
var MAX_LIST_LIMIT = 1e3;
|
|
44
|
+
/**
|
|
45
|
+
* A `limit`/`offset` value that cannot be honored.
|
|
46
|
+
*
|
|
47
|
+
* Extends `ValidationError` so the retry classifier never retries it, and
|
|
48
|
+
* carries `status`/`publicMessage` so `normalizeTypedHttpError()` renders it as
|
|
49
|
+
* a structured 400 instead of letting a caller typo become a 500.
|
|
50
|
+
*/
|
|
51
|
+
var QueryBoundsError = class extends ValidationError {
|
|
52
|
+
status = 400;
|
|
53
|
+
publicMessage;
|
|
54
|
+
constructor(message, code = "INVALID_QUERY_BOUNDS", details) {
|
|
55
|
+
super(message, code, details);
|
|
56
|
+
this.name = "QueryBoundsError";
|
|
57
|
+
this.publicMessage = message;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* An `orderBy` term that cannot be honored (#2367).
|
|
62
|
+
*
|
|
63
|
+
* `orderBy` reaches SQL in the identifier position, and until this rail existed
|
|
64
|
+
* it was checked only against `/^[a-zA-Z0-9_]+$/` — so an unknown column
|
|
65
|
+
* produced a driver error and a *sensitive* column produced a working ordering
|
|
66
|
+
* oracle: `?orderBy=api_secret&limit=1` reveals the extreme value of a secret
|
|
67
|
+
* one request at a time, even though the column itself is never serialized.
|
|
68
|
+
* `where` and `select` have rejected sensitive fields since #1540/#1902; this
|
|
69
|
+
* is the same rail for the third identifier-position input.
|
|
70
|
+
*/
|
|
71
|
+
var QueryOrderByError = class extends ValidationError {
|
|
72
|
+
status = 400;
|
|
73
|
+
publicMessage;
|
|
74
|
+
constructor(message, publicMessage, code = "INVALID_ORDER_BY", details) {
|
|
75
|
+
super(message, code, details);
|
|
76
|
+
this.name = "QueryOrderByError";
|
|
77
|
+
this.publicMessage = publicMessage;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Parse one bound from untrusted input.
|
|
82
|
+
*
|
|
83
|
+
* Accepts a non-negative safe integer, or a string of digits (optionally
|
|
84
|
+
* surrounded by whitespace). Everything else — `'abc'`, `'1.5'`, `'-1'`,
|
|
85
|
+
* `'1e3'`, `NaN`, `Infinity`, booleans, objects — is a client error, because
|
|
86
|
+
* silently substituting a default for a malformed bound hides the caller's bug
|
|
87
|
+
* and returns a page they did not ask for.
|
|
88
|
+
*
|
|
89
|
+
* `0` is preserved rather than folded into the default: `limit=0` means "no
|
|
90
|
+
* rows", which is what the REST surface already did and what the SvelteKit
|
|
91
|
+
* surface's `|| 50` fallback got wrong.
|
|
92
|
+
*/
|
|
93
|
+
function resolveListBound(raw, options) {
|
|
94
|
+
const { defaultValue = 0, maxValue, parameterName = "bound" } = options;
|
|
95
|
+
if (raw === null || raw === void 0 || raw === "") return maxValue !== void 0 ? Math.min(defaultValue, maxValue) : defaultValue;
|
|
96
|
+
let parsed;
|
|
97
|
+
if (typeof raw === "number") parsed = raw;
|
|
98
|
+
else if (typeof raw === "string") {
|
|
99
|
+
const trimmed = raw.trim();
|
|
100
|
+
if (!/^\d+$/.test(trimmed)) throw new QueryBoundsError(`Invalid ${parameterName}: '${raw}' is not a non-negative integer.`, "INVALID_QUERY_BOUNDS", {
|
|
101
|
+
parameterName,
|
|
102
|
+
value: raw
|
|
103
|
+
});
|
|
104
|
+
parsed = Number(trimmed);
|
|
105
|
+
} else throw new QueryBoundsError(`Invalid ${parameterName}: expected a non-negative integer, got ${typeof raw}.`, "INVALID_QUERY_BOUNDS", {
|
|
106
|
+
parameterName,
|
|
107
|
+
value: raw
|
|
108
|
+
});
|
|
109
|
+
if (!Number.isSafeInteger(parsed) || parsed < 0) throw new QueryBoundsError(`Invalid ${parameterName}: '${String(raw)}' is not a non-negative integer.`, "INVALID_QUERY_BOUNDS", {
|
|
110
|
+
parameterName,
|
|
111
|
+
value: raw
|
|
112
|
+
});
|
|
113
|
+
return maxValue !== void 0 ? Math.min(parsed, maxValue) : parsed;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Resolve a page size from untrusted input: default when absent, rejected when
|
|
117
|
+
* malformed, clamped when oversized.
|
|
118
|
+
*
|
|
119
|
+
* @throws {QueryBoundsError} when the input is not a non-negative integer
|
|
120
|
+
*/
|
|
121
|
+
function resolveListLimit(raw, options = {}) {
|
|
122
|
+
return resolveListBound(raw, {
|
|
123
|
+
defaultValue: options.defaultValue ?? 50,
|
|
124
|
+
maxValue: options.maxValue ?? 1e3,
|
|
125
|
+
parameterName: options.parameterName ?? "limit"
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Resolve a page offset from untrusted input.
|
|
130
|
+
*
|
|
131
|
+
* Unbounded above by default: an offset past the end of the table returns an
|
|
132
|
+
* empty page, and capping it would silently serve the wrong page instead.
|
|
133
|
+
*
|
|
134
|
+
* @throws {QueryBoundsError} when the input is not a non-negative integer
|
|
135
|
+
*/
|
|
136
|
+
function resolveListOffset(raw, options = {}) {
|
|
137
|
+
return resolveListBound(raw, {
|
|
138
|
+
defaultValue: options.defaultValue ?? 0,
|
|
139
|
+
maxValue: options.maxValue,
|
|
140
|
+
parameterName: options.parameterName ?? "offset"
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Deterministic default ordering for a generated list page.
|
|
145
|
+
*
|
|
146
|
+
* `LIMIT`/`OFFSET` without `ORDER BY` is not pagination: PostgreSQL may return
|
|
147
|
+
* rows in any order and is free to choose a different one per query, so page 2
|
|
148
|
+
* can repeat or skip rows from page 1. `created_at DESC` alone is not enough
|
|
149
|
+
* either — rows sharing a timestamp still tie — so the primary key follows as a
|
|
150
|
+
* total-order tiebreak.
|
|
151
|
+
*
|
|
152
|
+
* The index that makes this ordering cheap is #2363.
|
|
153
|
+
*/
|
|
154
|
+
var DEFAULT_LIST_ORDER_BY = ["created_at DESC", "id ASC"];
|
|
155
|
+
/**
|
|
156
|
+
* Deterministic default ordering for a model whose primary key may not be `id`.
|
|
157
|
+
*
|
|
158
|
+
* A class declaring `@field({ primaryKey: true })` on its own column has no
|
|
159
|
+
* synthetic `id` column — schema generation omits `id`/`slug`/`context` for
|
|
160
|
+
* custom-primary-key classes — so `ORDER BY ... id ASC` would name a column
|
|
161
|
+
* that does not exist and fail the whole page. The tiebreak therefore follows
|
|
162
|
+
* the declared key.
|
|
163
|
+
*
|
|
164
|
+
* @param primaryKeyField - the model's primary-key field name in SMRT (not
|
|
165
|
+
* column) form; `collection.list()` maps it to the column
|
|
166
|
+
*/
|
|
167
|
+
function buildDefaultListOrderBy(primaryKeyField = "id") {
|
|
168
|
+
return ["created_at DESC", `${primaryKeyField} ASC`];
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
171
|
+
export { DEFAULT_LIST_LIMIT, DEFAULT_LIST_ORDER_BY, MAX_LIST_LIMIT, QueryBoundsError, QueryOrderByError, buildDefaultListOrderBy, resolveListLimit, resolveListOffset };
|
|
172
|
+
|
|
173
|
+
//# sourceMappingURL=query-bounds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-bounds.js","names":[],"sources":["../src/query-bounds.ts"],"sourcesContent":["/**\n * Query bounds for list surfaces (#2367).\n *\n * Every generated read surface — REST, SvelteKit routes, the MCP server and the\n * MCP runtime bootstrap — takes `limit`/`offset` straight from untrusted input.\n * Before this module each one parsed them by hand, and each got it wrong in a\n * different way: `Number.parseInt('abc')` produced `LIMIT NaN` (a 500 from the\n * driver, not a 400 from the API), `Number(x) || 50` silently turned `0` into\n * `50`, and none of them capped the value, so `?limit=100000000` was a\n * single-request table scan on every generated endpoint.\n *\n * This is the one parser they all share. It is deliberately strict on the input\n * (a bound is a non-negative integer or it is a client error) and deliberately\n * forgiving on magnitude (an oversized page is clamped, not rejected, so a\n * caller paging with a too-large window still makes progress instead of\n * receiving an error it cannot act on).\n *\n * The bounds themselves are also available to `SmrtCollection.list()` through\n * the `defaultListLimit` / `maxListLimit` collection options. Those are opt-in:\n * `list()` is the framework's own bulk-read primitive and dozens of internal\n * callers (relationship loaders, junction hydration, `listByIds`) legitimately\n * expect every matching row, so a framework-wide implicit default would\n * silently truncate results rather than bound an attack surface. The bound\n * belongs where untrusted input arrives, which is why the generated surfaces\n * apply it unconditionally and direct programmatic callers opt in.\n */\n\nimport { ValidationError } from './errors';\n\n/**\n * Page size a generated list surface uses when the caller supplies none.\n *\n * Matches the value the REST and SvelteKit generators already hard-coded, so\n * adopting the shared parser is not a behavior change for callers that omit\n * `limit`.\n */\nexport const DEFAULT_LIST_LIMIT = 50;\n\n/**\n * Largest page a generated list surface will serve.\n *\n * Matches the cap `MCPGenerator` already applied in-process, now enforced on\n * every generated surface rather than one of them.\n */\nexport const MAX_LIST_LIMIT = 1000;\n\n/**\n * A `limit`/`offset` value that cannot be honored.\n *\n * Extends `ValidationError` so the retry classifier never retries it, and\n * carries `status`/`publicMessage` so `normalizeTypedHttpError()` renders it as\n * a structured 400 instead of letting a caller typo become a 500.\n */\nexport class QueryBoundsError extends ValidationError {\n readonly status = 400;\n readonly publicMessage: string;\n\n constructor(\n message: string,\n code = 'INVALID_QUERY_BOUNDS',\n details?: Record<string, unknown>,\n ) {\n super(message, code, details);\n this.name = 'QueryBoundsError';\n this.publicMessage = message;\n }\n}\n\n/**\n * An `orderBy` term that cannot be honored (#2367).\n *\n * `orderBy` reaches SQL in the identifier position, and until this rail existed\n * it was checked only against `/^[a-zA-Z0-9_]+$/` — so an unknown column\n * produced a driver error and a *sensitive* column produced a working ordering\n * oracle: `?orderBy=api_secret&limit=1` reveals the extreme value of a secret\n * one request at a time, even though the column itself is never serialized.\n * `where` and `select` have rejected sensitive fields since #1540/#1902; this\n * is the same rail for the third identifier-position input.\n */\nexport class QueryOrderByError extends ValidationError {\n readonly status = 400;\n readonly publicMessage: string;\n\n constructor(\n message: string,\n publicMessage: string,\n code = 'INVALID_ORDER_BY',\n details?: Record<string, unknown>,\n ) {\n super(message, code, details);\n this.name = 'QueryOrderByError';\n this.publicMessage = publicMessage;\n }\n}\n\n/**\n * Options for {@link resolveListLimit} / {@link resolveListOffset}.\n */\nexport interface ListBoundOptions {\n /** Value used when the input is absent (`null`, `undefined`, or `''`). */\n defaultValue?: number;\n /** Upper bound; larger values are clamped down to it. Omit for none. */\n maxValue?: number;\n /** Parameter name used in the rejection message. */\n parameterName?: string;\n}\n\n/**\n * Parse one bound from untrusted input.\n *\n * Accepts a non-negative safe integer, or a string of digits (optionally\n * surrounded by whitespace). Everything else — `'abc'`, `'1.5'`, `'-1'`,\n * `'1e3'`, `NaN`, `Infinity`, booleans, objects — is a client error, because\n * silently substituting a default for a malformed bound hides the caller's bug\n * and returns a page they did not ask for.\n *\n * `0` is preserved rather than folded into the default: `limit=0` means \"no\n * rows\", which is what the REST surface already did and what the SvelteKit\n * surface's `|| 50` fallback got wrong.\n */\nfunction resolveListBound(raw: unknown, options: ListBoundOptions): number {\n const { defaultValue = 0, maxValue, parameterName = 'bound' } = options;\n\n if (raw === null || raw === undefined || raw === '') {\n return maxValue !== undefined\n ? Math.min(defaultValue, maxValue)\n : defaultValue;\n }\n\n let parsed: number;\n if (typeof raw === 'number') {\n parsed = raw;\n } else if (typeof raw === 'string') {\n const trimmed = raw.trim();\n // Strict digits only. `Number.parseInt` would accept '12abc' and\n // `Number()` would accept '1e3' and ' 0x10 '; both would then be\n // interpolated into a page size the caller never wrote.\n if (!/^\\d+$/.test(trimmed)) {\n throw new QueryBoundsError(\n `Invalid ${parameterName}: '${raw}' is not a non-negative integer.`,\n 'INVALID_QUERY_BOUNDS',\n { parameterName, value: raw },\n );\n }\n parsed = Number(trimmed);\n } else {\n throw new QueryBoundsError(\n `Invalid ${parameterName}: expected a non-negative integer, got ${typeof raw}.`,\n 'INVALID_QUERY_BOUNDS',\n { parameterName, value: raw },\n );\n }\n\n if (!Number.isSafeInteger(parsed) || parsed < 0) {\n throw new QueryBoundsError(\n `Invalid ${parameterName}: '${String(raw)}' is not a non-negative integer.`,\n 'INVALID_QUERY_BOUNDS',\n { parameterName, value: raw },\n );\n }\n\n return maxValue !== undefined ? Math.min(parsed, maxValue) : parsed;\n}\n\n/**\n * Resolve a page size from untrusted input: default when absent, rejected when\n * malformed, clamped when oversized.\n *\n * @throws {QueryBoundsError} when the input is not a non-negative integer\n */\nexport function resolveListLimit(\n raw: unknown,\n options: ListBoundOptions = {},\n): number {\n return resolveListBound(raw, {\n defaultValue: options.defaultValue ?? DEFAULT_LIST_LIMIT,\n maxValue: options.maxValue ?? MAX_LIST_LIMIT,\n parameterName: options.parameterName ?? 'limit',\n });\n}\n\n/**\n * Resolve a page offset from untrusted input.\n *\n * Unbounded above by default: an offset past the end of the table returns an\n * empty page, and capping it would silently serve the wrong page instead.\n *\n * @throws {QueryBoundsError} when the input is not a non-negative integer\n */\nexport function resolveListOffset(\n raw: unknown,\n options: ListBoundOptions = {},\n): number {\n return resolveListBound(raw, {\n defaultValue: options.defaultValue ?? 0,\n maxValue: options.maxValue,\n parameterName: options.parameterName ?? 'offset',\n });\n}\n\n/**\n * Deterministic default ordering for a generated list page.\n *\n * `LIMIT`/`OFFSET` without `ORDER BY` is not pagination: PostgreSQL may return\n * rows in any order and is free to choose a different one per query, so page 2\n * can repeat or skip rows from page 1. `created_at DESC` alone is not enough\n * either — rows sharing a timestamp still tie — so the primary key follows as a\n * total-order tiebreak.\n *\n * The index that makes this ordering cheap is #2363.\n */\nexport const DEFAULT_LIST_ORDER_BY: readonly string[] = [\n 'created_at DESC',\n 'id ASC',\n];\n\n/**\n * Deterministic default ordering for a model whose primary key may not be `id`.\n *\n * A class declaring `@field({ primaryKey: true })` on its own column has no\n * synthetic `id` column — schema generation omits `id`/`slug`/`context` for\n * custom-primary-key classes — so `ORDER BY ... id ASC` would name a column\n * that does not exist and fail the whole page. The tiebreak therefore follows\n * the declared key.\n *\n * @param primaryKeyField - the model's primary-key field name in SMRT (not\n * column) form; `collection.list()` maps it to the column\n */\nexport function buildDefaultListOrderBy(primaryKeyField = 'id'): string[] {\n return ['created_at DESC', `${primaryKeyField} ASC`];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,IAAa,qBAAqB;;;;;;;AAQlC,IAAa,iBAAiB;;;;;;;;AAS9B,IAAa,mBAAb,cAAsC,gBAAgB;CACpD,SAAkB;CAClB;CAEA,YACE,SACA,OAAO,wBACP,SACA;EACA,MAAM,SAAS,MAAM,OAAO;EAC5B,KAAK,OAAO;EACZ,KAAK,gBAAgB;CACvB;AACF;;;;;;;;;;;;AAaA,IAAa,oBAAb,cAAuC,gBAAgB;CACrD,SAAkB;CAClB;CAEA,YACE,SACA,eACA,OAAO,oBACP,SACA;EACA,MAAM,SAAS,MAAM,OAAO;EAC5B,KAAK,OAAO;EACZ,KAAK,gBAAgB;CACvB;AACF;;;;;;;;;;;;;;AA2BA,SAAS,iBAAiB,KAAc,SAAmC;CACzE,MAAM,EAAE,eAAe,GAAG,UAAU,gBAAgB,YAAY;CAEhE,IAAI,QAAQ,QAAQ,QAAQ,KAAA,KAAa,QAAQ,IAC/C,OAAO,aAAa,KAAA,IAChB,KAAK,IAAI,cAAc,QAAQ,IAC/B;CAGN,IAAI;CACJ,IAAI,OAAO,QAAQ,UACjB,SAAS;MACJ,IAAI,OAAO,QAAQ,UAAU;EAClC,MAAM,UAAU,IAAI,KAAK;EAIzB,IAAI,CAAC,QAAQ,KAAK,OAAO,GACvB,MAAM,IAAI,iBACR,WAAW,cAAc,KAAK,IAAI,mCAClC,wBACA;GAAE;GAAe,OAAO;EAAI,CAC9B;EAEF,SAAS,OAAO,OAAO;CACzB,OACE,MAAM,IAAI,iBACR,WAAW,cAAc,yCAAyC,OAAO,IAAI,IAC7E,wBACA;EAAE;EAAe,OAAO;CAAI,CAC9B;CAGF,IAAI,CAAC,OAAO,cAAc,MAAM,KAAK,SAAS,GAC5C,MAAM,IAAI,iBACR,WAAW,cAAc,KAAK,OAAO,GAAG,EAAE,mCAC1C,wBACA;EAAE;EAAe,OAAO;CAAI,CAC9B;CAGF,OAAO,aAAa,KAAA,IAAY,KAAK,IAAI,QAAQ,QAAQ,IAAI;AAC/D;;;;;;;AAQA,SAAgB,iBACd,KACA,UAA4B,CAAC,GACrB;CACR,OAAO,iBAAiB,KAAK;EAC3B,cAAc,QAAQ,gBAAA;EACtB,UAAU,QAAQ,YAAA;EAClB,eAAe,QAAQ,iBAAiB;CAC1C,CAAC;AACH;;;;;;;;;AAUA,SAAgB,kBACd,KACA,UAA4B,CAAC,GACrB;CACR,OAAO,iBAAiB,KAAK;EAC3B,cAAc,QAAQ,gBAAgB;EACtC,UAAU,QAAQ;EAClB,eAAe,QAAQ,iBAAiB;CAC1C,CAAC;AACH;;;;;;;;;;;;AAaA,IAAa,wBAA2C,CACtD,mBACA,QACF;;;;;;;;;;;;;AAcA,SAAgB,wBAAwB,kBAAkB,MAAgB;CACxE,OAAO,CAAC,mBAAmB,GAAG,gBAAgB,KAAK;AACrD"}
|
package/dist/registry/types.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { CollectionCacheConfig } from '../collection-cache';
|
|
|
4
4
|
import { FieldOptions } from '../decorators/index.js';
|
|
5
5
|
import { SmrtObject } from '../object';
|
|
6
6
|
import { FieldDefinition, FieldMeta, MethodDefinition, QualifiedClassName, SmartObjectManifest, SmrtVisibility, ValidationRule } from '../scanner/types.js';
|
|
7
|
-
import { SchemaDefinition } from '../schema/types.js';
|
|
7
|
+
import { DeclaredIndexDefinition, SchemaDefinition } from '../schema/types.js';
|
|
8
8
|
/**
|
|
9
9
|
* Type for any constructor function that extends SmrtObject.
|
|
10
10
|
* Used for WeakMap keys where we need to accept any subclass constructor.
|
|
@@ -267,6 +267,37 @@ export interface SmartObjectConfig {
|
|
|
267
267
|
* ```
|
|
268
268
|
*/
|
|
269
269
|
conflictColumns?: string[];
|
|
270
|
+
/**
|
|
271
|
+
* Extra indexes for this object's table (issue #2357).
|
|
272
|
+
*
|
|
273
|
+
* `@field({ indexed: true })` gives a single-column index and the generator
|
|
274
|
+
* auto-creates indexes for foreign keys, unique/conflict columns,
|
|
275
|
+
* `updated_at`, the STI discriminator and `tenant_id`. A list workload's
|
|
276
|
+
* access path is composite — filter column(s) first, sort column last — and
|
|
277
|
+
* nothing above can express it. Declared indexes are honoured on every schema
|
|
278
|
+
* path (build-time AST, runtime registry CTI/STI, manifest CTI/STI), so the
|
|
279
|
+
* same declaration behaves identically however the schema was derived.
|
|
280
|
+
*
|
|
281
|
+
* `columns` accepts SMRT field names or column names, in index order. Declare
|
|
282
|
+
* columns, not a direction: PostgreSQL scans a btree either way, so an
|
|
283
|
+
* ascending index also serves the matching `ORDER BY ... DESC` as an ordered
|
|
284
|
+
* scan without a sort step.
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```typescript
|
|
288
|
+
* // Serves: WHERE tenant_id = ? ... ORDER BY publish_date DESC LIMIT 10
|
|
289
|
+
* @smrt({
|
|
290
|
+
* indexes: [
|
|
291
|
+
* {
|
|
292
|
+
* name: 'contents_tenant_id_publish_date_idx',
|
|
293
|
+
* columns: ['tenantId', 'publish_date'],
|
|
294
|
+
* },
|
|
295
|
+
* ],
|
|
296
|
+
* })
|
|
297
|
+
* class Content extends SmrtObject {}
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
indexes?: DeclaredIndexDefinition[];
|
|
270
301
|
/**
|
|
271
302
|
* Opt-in read-through cache for collection reads (issue #1498).
|
|
272
303
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/registry/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EACV,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,cAAc,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/registry/types.ts"],"names":[],"mappings":"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"}
|
package/dist/registry.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { applyOneToManyChildAccessors } from "./child-accessors.js";
|
|
2
|
-
import { applyPendingDecoratorRegistrations } from "./decorators/compatibility.js";
|
|
3
2
|
import { ConfigurationError } from "./errors.js";
|
|
3
|
+
import { applyPendingDecoratorRegistrations } from "./decorators/compatibility.js";
|
|
4
4
|
import { clearRegistryDiagnostics, flushRegistryDiagnostics, getRegistryDiagnostics, recordRegistryDiagnostic } from "./registry/diagnostics.js";
|
|
5
5
|
import { createQualifiedName, isQualifiedName, parseQualifiedName } from "./utils/qualified-names.js";
|
|
6
6
|
import { cloneManifestSchemaColumns, discoverCachedManifestSync, getNodeBuiltins, loadExternalManifestSyncWithNode } from "./manifest/store.js";
|
package/dist/scanner/types.d.ts
CHANGED
|
@@ -181,6 +181,11 @@ export interface ManifestIndexDefinition {
|
|
|
181
181
|
*/
|
|
182
182
|
export interface ManifestSchema {
|
|
183
183
|
tableName: string;
|
|
184
|
+
/**
|
|
185
|
+
* Engine-neutral CREATE TABLE preview. Not executable as-is: no indexes,
|
|
186
|
+
* abstract SQL types. Consumers render `columns` + `indexes` through the
|
|
187
|
+
* engine DDL strategy (see `schema/manifest-schema.ts`, #2358).
|
|
188
|
+
*/
|
|
184
189
|
ddl: string;
|
|
185
190
|
columns: Record<string, ManifestColumnDefinition>;
|
|
186
191
|
indexes: ManifestIndexDefinition[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scanner/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scanner/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../src/scanner/types.ts"],"sourcesContent":["/**\n * Type definitions for AST scanning and manifest generation\n */\n\nimport type { SmartObjectConfig } from '../registry.js';\n\n/**\n * Qualified class name in format \"@package/name:ClassName\"\n * Example: \"@happyvertical/smrt-core:Product\"\n */\nexport type QualifiedClassName = `${string}:${string}`;\n\n/**\n * Static per-field UI hints authored via `@field({ ui })` (#2046).\n *\n * A pure presentation seed for the field-policy rail (epic #2045): it rides the\n * manifest under the field's `_meta.ui` (never promoted to a top-level\n * `FieldDefinition` key), reaches runtime at `field._meta.ui` via\n * `ObjectRegistry.getAllFields()`, and is emitted to the browser in generated\n * web-collection definitions. It has NO schema, persistence, or security\n * effect — `sensitive`/`readPermission` remain the security rail.\n */\nexport interface FieldUIHints {\n /**\n * Seed the field into the \"basic\" visibility tier (shown before the\n * advanced disclosure). Unmarked fields default per the cold-start rule:\n * an object with no basic markers renders everything basic; once any field\n * is marked, unmarked fields default to advanced.\n */\n basic?: boolean;\n /** Grouping key for form section/grouping (consumer-defined label). */\n group?: string;\n /** Relative sort order within the form/group (ascending). */\n order?: number;\n /**\n * Seed the field's policy as locked: org/user policy tiers may not\n * override it unless an org admin explicitly unlocks it.\n */\n locked?: boolean;\n}\n\n/**\n * Structured metadata attached to a field definition under `_meta`.\n *\n * Captures the field-helper options the scanner and schema/manifest\n * generators read off a field (`sqlType`, `nullable`, `__tenancy`, …). The\n * index signature keeps the bag open for forward-compatible keys without\n * forcing every consumer through `any`.\n */\nexport interface FieldMeta {\n /** Explicit SQL type override (e.g. 'UUID') applied during schema generation. */\n sqlType?: string;\n /** Storage type for cross-package reference ids ('text' forces TEXT). */\n idType?: 'uuid' | 'text';\n /** When true, the column is nullable regardless of `required`. */\n nullable?: boolean;\n /** Mirror of the field's required flag captured at registration. */\n required?: boolean;\n /** Default value carried in metadata for runtime-registry generation. */\n default?: unknown;\n /** Marks the field as the primary key column. */\n primaryKey?: boolean;\n /** Marks the column as unique. */\n unique?: boolean;\n /** Column description carried into generated schema. */\n description?: string;\n /** Static per-field UI hints authored via `@field({ ui })` (#2046). */\n ui?: FieldUIHints;\n /** Opt-in column/JSON-path indexing flag. */\n indexed?: boolean;\n /** Foreign-key delete action carried in metadata. */\n onDelete?: 'CASCADE' | 'SET NULL' | 'RESTRICT';\n /** Excludes the field from persistence when true. */\n transient?: boolean;\n /** Numeric/length validation bounds and pattern. */\n min?: number;\n max?: number;\n minLength?: number;\n maxLength?: number;\n /**\n * Validation regex. A string source, a `RegExp`, or — when a manifest was\n * JSON-serialized and a `RegExp` collapsed to `{}` — an opaque object. Read\n * sites must narrow before accessing `.source`.\n */\n pattern?: unknown;\n /** Tenancy metadata injected for tenant-scoped models. */\n __tenancy?: {\n isTenantIdField?: boolean;\n [key: string]: unknown;\n };\n /** Report-aggregate metadata injected by the report normalizer. */\n __report?: {\n kind?: string;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n/**\n * Controls how a class is exposed in manifests and across packages\n */\nexport type SmrtVisibility =\n | 'public' // Included in published manifest, available to all consumers\n | 'internal' // Package-only, excluded from published manifest\n | 'test'; // Test-only, never in any published manifest\n\nexport interface FieldDefinition {\n type:\n | 'text'\n | 'decimal'\n | 'boolean'\n | 'integer'\n | 'datetime'\n | 'json'\n | 'foreignKey'\n | 'crossPackageRef' // Cross-package reference — UUID id column by default, no DDL FK\n | 'oneToMany'\n | 'manyToMany'\n | 'meta'; // STI meta fields (_meta_type, _meta_data)\n required?: boolean;\n default?: unknown;\n min?: number;\n max?: number;\n maxLength?: number;\n minLength?: number;\n related?: string; // For foreignKey, crossPackageRef, oneToMany, manyToMany\n description?: string;\n _meta?: FieldMeta;\n transient?: boolean; // Field not persisted to database\n /**\n * Sensitive value (API secrets, credentials, tax IDs). Still persisted, but\n * excluded from `toPublicJSON()` (generated REST/MCP/SvelteKit responses) and\n * rejected as a `where` filter key.\n */\n sensitive?: boolean;\n /**\n * Read-only over generated write surfaces. Stripped from create/update\n * request bodies so callers cannot mass-assign it.\n */\n readonly?: boolean;\n /**\n * Permission slug required to include this field in public/read responses.\n * Omitted unless the serializer is given a resolved permission set that\n * includes this slug. `sensitive` still wins and hides the field for all\n * callers.\n */\n readPermission?: string;\n /**\n * Controls whether the field is included in JSON exports.\n * - `true`: Always exported (unless site explicitly excludes it)\n * - `false`: Never exported (cannot be overridden by site config)\n * - `undefined`: Uses site's fieldExportDefault setting\n */\n exported?: boolean;\n}\n\nexport interface MethodDefinition {\n name: string;\n async: boolean;\n parameters: Array<{\n name: string;\n type: string;\n optional: boolean;\n default?: unknown;\n }>;\n returnType: string;\n description?: string;\n isStatic: boolean;\n isPublic: boolean;\n}\n\n/**\n * Pre-generated schema column definition for manifest\n */\nexport interface ManifestColumnDefinition {\n type: string; // SQL type: TEXT, INTEGER, DECIMAL, BOOLEAN, DATETIME, JSON\n primaryKey?: boolean;\n /**\n * Non-DDL marker for SMRT-owned identifier/reference columns.\n */\n referenceKind?: 'id' | 'foreignKey' | 'crossPackageRef' | 'tenantId';\n notNull?: boolean;\n unique?: boolean;\n default?: unknown;\n}\n\n/**\n * Pre-generated schema index definition for manifest\n */\nexport interface ManifestIndexDefinition {\n name: string;\n columns: string[];\n unique?: boolean;\n where?: string;\n /**\n * Expression-based index target — when set, the DDL strategy renders the\n * index over a JSON path inside `column` (dialect-specific syntax).\n */\n jsonPath?: {\n column: string;\n path: string;\n };\n}\n\n/**\n * Pre-generated schema for efficient external package consumption\n * Generated at build time by ManifestGenerator, stored in manifest.json\n */\nexport interface ManifestSchema {\n tableName: string;\n ddl: string;\n columns: Record<string, ManifestColumnDefinition>;\n indexes: ManifestIndexDefinition[];\n version: string; // Hash of schema definition for migration tracking\n}\n\n/**\n * Validation rule type for pre-computed validators\n * These are serializable rules extracted from field definitions at build time,\n * eliminating the need to compile validator closures at runtime.\n */\nexport type ValidationRuleType =\n | 'required'\n | 'min'\n | 'max'\n | 'minLength'\n | 'maxLength'\n | 'pattern';\n\n/**\n * Pre-computed validation rule for a field\n * Generated at build time by ManifestGenerator, stored in manifest.json\n *\n * These rules are evaluated at runtime without creating closure functions,\n * significantly reducing CLI startup time for projects with many SMRT objects.\n */\nexport interface ValidationRule {\n /** Field name to validate */\n field: string;\n /** Type of validation rule */\n rule: ValidationRuleType;\n /** Value for the rule (number for min/max/minLength/maxLength, string for pattern) */\n value?: number | string;\n /** Field type for context (text, integer, decimal, etc.) */\n fieldType?: string;\n}\n\n// ── Agent manifest types ────────────────────────────────────────────────\n\n/**\n * Permission declared by an agent\n * Generated from uiSlots (manage:*) and CLI/MCP methods (execute:*)\n */\nexport interface AgentPermission {\n id: string;\n label: string;\n category: 'slot' | 'method';\n defaultGranted?: boolean;\n}\n\n/**\n * Feature declared by an agent\n */\nexport interface AgentFeature {\n id: string;\n label: string;\n description?: string;\n type: 'slot' | 'method';\n}\n\n/**\n * Menu item derived from agent uiSlots\n */\nexport interface AgentMenuItem {\n id: string;\n label: string;\n icon?: string;\n order: number;\n path: string;\n requiredPermission?: string;\n}\n\n/**\n * Component export declaration derived from package.json exports\n */\nexport interface AgentComponentDeclaration {\n exportPath: string;\n type: string;\n}\n\n/**\n * UI slot definition captured from static uiSlots on Agent subclasses\n */\nexport interface AgentUISlotManifest {\n id: string;\n label: string;\n description?: string;\n icon?: string;\n order?: number;\n disabled?: boolean;\n /** Durable owner for settings written through this slot. */\n scope?: 'agent' | 'persona';\n /** Optional fallback form contract for host applications. */\n settingsSchema?: {\n version: number;\n fields: Array<{\n id: string;\n label: string;\n type: 'string' | 'number' | 'boolean' | 'select' | 'textarea' | 'json';\n description?: string;\n required?: boolean;\n default?: unknown;\n placeholder?: string;\n options?: Array<{ value: string; label: string }>;\n min?: number;\n max?: number;\n }>;\n };\n}\n\n/**\n * Admin route declared by an agent via static adminRoutes\n * Consumed by vitePluginAgentRoutes to register admin routes with SvelteKit\n */\nexport interface AgentAdminRouteManifest {\n /** Route path relative to agent root (e.g., 'sources/[sourceId]') */\n path: string;\n /** Component export name from the agent's admin entry point */\n component: string;\n /** Optional: export name for server load function */\n load?: string;\n}\n\n/**\n * Auto-generated agent manifest section\n * Produced by the manifest build pipeline for any class with `agent` decorator config\n */\nexport interface AgentManifest {\n name: string;\n slug: string;\n icon?: string;\n tier: 'free' | 'standard' | 'premium';\n description?: string;\n uiSlots: Record<string, AgentUISlotManifest>;\n adminRoutes?: AgentAdminRouteManifest[];\n /** Default signal subscriptions declared by this agent */\n signalSubscriptions?: string[];\n permissions: AgentPermission[];\n features: AgentFeature[];\n menuItems: AgentMenuItem[];\n components: AgentComponentDeclaration[];\n}\n\n// ── Core manifest types ─────────────────────────────────────────────────\n\nexport interface SmartObjectDefinition {\n /**\n * Qualified name in format \"@package/name:ClassName\"\n * This is the PRIMARY KEY for manifest lookups.\n * Example: \"@happyvertical/smrt-core:Product\"\n *\n * Optional during transition - will be required in future versions.\n */\n qualifiedName?: QualifiedClassName;\n\n /**\n * Simple class name (PascalCase)\n * Example: \"Product\"\n */\n className: string;\n\n /**\n * Package name where this class is defined.\n * Example: \"@happyvertical/smrt-core\"\n *\n * Optional during transition - will be required in future versions.\n */\n packageName?: string;\n\n /**\n * Visibility control for manifest inclusion\n * - 'public': Included in published manifest (default)\n * - 'internal': Package-only, excluded from published manifest\n * - 'test': Test-only, never in any published manifest\n *\n * Defaults to 'public' if not specified.\n */\n visibility?: SmrtVisibility;\n\n /**\n * @deprecated Use qualifiedName instead. Kept for transition period.\n * Lowercase class name, formerly used as manifest key.\n */\n name: string;\n\n collection: string; // Pluralized name for endpoints\n filePath: string;\n packageVersion?: string; // Package version for external manifest loading\n importPath?: string; // Import path for dynamic loading (e.g., \"@pkg/objects\")\n modulePath?: string; // Relative module path within package\n exportName?: string; // Named export to use (defaults to className)\n collectionExportName?: string; // Collection class export name\n fields: Record<string, FieldDefinition>;\n methods: Record<string, MethodDefinition>;\n decoratorConfig: SmartObjectConfig;\n extends?: string; // Base class name (simple name, not qualified)\n extendsQualified?: string; // Base class qualified name\n extendsTypeArg?: string; // Generic type argument (e.g., \"Meeting\" from \"SmrtCollection<Meeting>\")\n tools?: Array<{\n type: 'function';\n function: {\n name: string;\n description?: string;\n parameters?: Record<string, unknown>;\n };\n }>;\n /**\n * Pre-generated schema for efficient external package consumption\n * Generated at build time by ManifestGenerator (smrt scan)\n *\n * When present, consumers can use this pre-computed schema directly\n * without calling generateSchema() at runtime, eliminating latency.\n */\n schema?: ManifestSchema;\n\n /**\n * Pre-computed validation rules for efficient runtime validation\n * Generated at build time by ManifestGenerator (smrt scan)\n *\n * When present, the registry uses these rules instead of compiling\n * validator closures at runtime, significantly reducing startup time.\n *\n * @see ValidationRule\n */\n validationRules?: ValidationRule[];\n\n /**\n * Static properties captured from the class definition\n * Currently used for `static uiSlots` on Agent subclasses\n */\n staticProperties?: Record<string, unknown>;\n\n /**\n * Auto-generated agent manifest\n * Only present for classes with `agent` in their decorator config\n * Generated at build time by ManifestGenerator fifth pass\n */\n agent?: AgentManifest;\n}\n\n/**\n * Fixed `timestamp` for every manifest that can reach build output.\n *\n * Manifests are inlined into bundles (`registerPackageManifest(JSON.parse(...))`),\n * so a wall-clock value changes the emitted bytes on every build. That changes\n * Vite's content hash, which changes `dist/`, which invalidates every\n * downstream package through `dependsOn: ['^build']` — one rebuilt package\n * churned 202 of 245 task hashes, and `typecheck` never reused a cache entry\n * across runs (#2223).\n *\n * Nothing reads the field: `getManifestTimestampsHash` invalidates on\n * filesystem mtimes, and `normalizeManifestForHash` deletes it before\n * comparing. A fixed value therefore costs no information.\n *\n * Genuine runtime caches that expire on elapsed time — the discovery cache in\n * `manifest/discover-smrt-packages.ts` — keep using the clock; they never\n * reach build output.\n */\nexport const MANIFEST_TIMESTAMP = 0;\n\n/**\n * Fixed `generatedAt` for knowledge artifacts emitted into `dist/`.\n *\n * Same reasoning as {@link MANIFEST_TIMESTAMP}: build output is compared\n * byte-for-byte, so it cannot carry the clock. The Unix epoch is used rather\n * than `0` because the field is an ISO-8601 string, and a parseable value\n * keeps any consumer that formats it working.\n *\n * The working copy under `.smrt/` keeps a real timestamp — it is useful to a\n * human there, and `preserveKnowledgeGeneratedAt` already stops it churning\n * across incremental rebuilds.\n */\nexport const DETERMINISTIC_GENERATED_AT = '1970-01-01T00:00:00.000Z';\n\nexport interface SmartObjectManifest {\n version: string;\n /** Always {@link MANIFEST_TIMESTAMP} for build-output manifests. */\n timestamp: number;\n packageName?: string; // Root package name (should be set for all new manifests)\n packageVersion?: string; // Root package version\n /**\n * Objects keyed by qualified name (e.g., \"@happyvertical/smrt-core:Product\")\n * Key is string for backward compatibility, but should be QualifiedClassName format.\n */\n objects: Record<string, SmartObjectDefinition>;\n moduleType?: string; // Module type identifier (e.g., \"smrt\") for package discovery\n smrtDependencies?: string[]; // Discovered SMRT packages from dependency tree\n}\n\nexport interface ScanResult {\n filePath: string;\n objects: SmartObjectDefinition[];\n errors: Array<{\n message: string;\n line?: number;\n column?: number;\n }>;\n}\n\nexport interface ScanOptions {\n includePrivateMethods?: boolean;\n includeStaticMethods?: boolean;\n followImports?: boolean;\n baseClasses?: string[]; // Classes to consider as SMRT base classes\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAodA,IAAa,qBAAqB;;;;;;;;;;;;;AAclC,IAAa,6BAA6B"}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../src/scanner/types.ts"],"sourcesContent":["/**\n * Type definitions for AST scanning and manifest generation\n */\n\nimport type { SmartObjectConfig } from '../registry.js';\n\n/**\n * Qualified class name in format \"@package/name:ClassName\"\n * Example: \"@happyvertical/smrt-core:Product\"\n */\nexport type QualifiedClassName = `${string}:${string}`;\n\n/**\n * Static per-field UI hints authored via `@field({ ui })` (#2046).\n *\n * A pure presentation seed for the field-policy rail (epic #2045): it rides the\n * manifest under the field's `_meta.ui` (never promoted to a top-level\n * `FieldDefinition` key), reaches runtime at `field._meta.ui` via\n * `ObjectRegistry.getAllFields()`, and is emitted to the browser in generated\n * web-collection definitions. It has NO schema, persistence, or security\n * effect — `sensitive`/`readPermission` remain the security rail.\n */\nexport interface FieldUIHints {\n /**\n * Seed the field into the \"basic\" visibility tier (shown before the\n * advanced disclosure). Unmarked fields default per the cold-start rule:\n * an object with no basic markers renders everything basic; once any field\n * is marked, unmarked fields default to advanced.\n */\n basic?: boolean;\n /** Grouping key for form section/grouping (consumer-defined label). */\n group?: string;\n /** Relative sort order within the form/group (ascending). */\n order?: number;\n /**\n * Seed the field's policy as locked: org/user policy tiers may not\n * override it unless an org admin explicitly unlocks it.\n */\n locked?: boolean;\n}\n\n/**\n * Structured metadata attached to a field definition under `_meta`.\n *\n * Captures the field-helper options the scanner and schema/manifest\n * generators read off a field (`sqlType`, `nullable`, `__tenancy`, …). The\n * index signature keeps the bag open for forward-compatible keys without\n * forcing every consumer through `any`.\n */\nexport interface FieldMeta {\n /** Explicit SQL type override (e.g. 'UUID') applied during schema generation. */\n sqlType?: string;\n /** Storage type for cross-package reference ids ('text' forces TEXT). */\n idType?: 'uuid' | 'text';\n /** When true, the column is nullable regardless of `required`. */\n nullable?: boolean;\n /** Mirror of the field's required flag captured at registration. */\n required?: boolean;\n /** Default value carried in metadata for runtime-registry generation. */\n default?: unknown;\n /** Marks the field as the primary key column. */\n primaryKey?: boolean;\n /** Marks the column as unique. */\n unique?: boolean;\n /** Column description carried into generated schema. */\n description?: string;\n /** Static per-field UI hints authored via `@field({ ui })` (#2046). */\n ui?: FieldUIHints;\n /** Opt-in column/JSON-path indexing flag. */\n indexed?: boolean;\n /** Foreign-key delete action carried in metadata. */\n onDelete?: 'CASCADE' | 'SET NULL' | 'RESTRICT';\n /** Excludes the field from persistence when true. */\n transient?: boolean;\n /** Numeric/length validation bounds and pattern. */\n min?: number;\n max?: number;\n minLength?: number;\n maxLength?: number;\n /**\n * Validation regex. A string source, a `RegExp`, or — when a manifest was\n * JSON-serialized and a `RegExp` collapsed to `{}` — an opaque object. Read\n * sites must narrow before accessing `.source`.\n */\n pattern?: unknown;\n /** Tenancy metadata injected for tenant-scoped models. */\n __tenancy?: {\n isTenantIdField?: boolean;\n [key: string]: unknown;\n };\n /** Report-aggregate metadata injected by the report normalizer. */\n __report?: {\n kind?: string;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\n/**\n * Controls how a class is exposed in manifests and across packages\n */\nexport type SmrtVisibility =\n | 'public' // Included in published manifest, available to all consumers\n | 'internal' // Package-only, excluded from published manifest\n | 'test'; // Test-only, never in any published manifest\n\nexport interface FieldDefinition {\n type:\n | 'text'\n | 'decimal'\n | 'boolean'\n | 'integer'\n | 'datetime'\n | 'json'\n | 'foreignKey'\n | 'crossPackageRef' // Cross-package reference — UUID id column by default, no DDL FK\n | 'oneToMany'\n | 'manyToMany'\n | 'meta'; // STI meta fields (_meta_type, _meta_data)\n required?: boolean;\n default?: unknown;\n min?: number;\n max?: number;\n maxLength?: number;\n minLength?: number;\n related?: string; // For foreignKey, crossPackageRef, oneToMany, manyToMany\n description?: string;\n _meta?: FieldMeta;\n transient?: boolean; // Field not persisted to database\n /**\n * Sensitive value (API secrets, credentials, tax IDs). Still persisted, but\n * excluded from `toPublicJSON()` (generated REST/MCP/SvelteKit responses) and\n * rejected as a `where` filter key.\n */\n sensitive?: boolean;\n /**\n * Read-only over generated write surfaces. Stripped from create/update\n * request bodies so callers cannot mass-assign it.\n */\n readonly?: boolean;\n /**\n * Permission slug required to include this field in public/read responses.\n * Omitted unless the serializer is given a resolved permission set that\n * includes this slug. `sensitive` still wins and hides the field for all\n * callers.\n */\n readPermission?: string;\n /**\n * Controls whether the field is included in JSON exports.\n * - `true`: Always exported (unless site explicitly excludes it)\n * - `false`: Never exported (cannot be overridden by site config)\n * - `undefined`: Uses site's fieldExportDefault setting\n */\n exported?: boolean;\n}\n\nexport interface MethodDefinition {\n name: string;\n async: boolean;\n parameters: Array<{\n name: string;\n type: string;\n optional: boolean;\n default?: unknown;\n }>;\n returnType: string;\n description?: string;\n isStatic: boolean;\n isPublic: boolean;\n}\n\n/**\n * Pre-generated schema column definition for manifest\n */\nexport interface ManifestColumnDefinition {\n type: string; // SQL type: TEXT, INTEGER, DECIMAL, BOOLEAN, DATETIME, JSON\n primaryKey?: boolean;\n /**\n * Non-DDL marker for SMRT-owned identifier/reference columns.\n */\n referenceKind?: 'id' | 'foreignKey' | 'crossPackageRef' | 'tenantId';\n notNull?: boolean;\n unique?: boolean;\n default?: unknown;\n}\n\n/**\n * Pre-generated schema index definition for manifest\n */\nexport interface ManifestIndexDefinition {\n name: string;\n columns: string[];\n unique?: boolean;\n where?: string;\n /**\n * Expression-based index target — when set, the DDL strategy renders the\n * index over a JSON path inside `column` (dialect-specific syntax).\n */\n jsonPath?: {\n column: string;\n path: string;\n };\n}\n\n/**\n * Pre-generated schema for efficient external package consumption\n * Generated at build time by ManifestGenerator, stored in manifest.json\n */\nexport interface ManifestSchema {\n tableName: string;\n /**\n * Engine-neutral CREATE TABLE preview. Not executable as-is: no indexes,\n * abstract SQL types. Consumers render `columns` + `indexes` through the\n * engine DDL strategy (see `schema/manifest-schema.ts`, #2358).\n */\n ddl: string;\n columns: Record<string, ManifestColumnDefinition>;\n indexes: ManifestIndexDefinition[];\n version: string; // Hash of schema definition for migration tracking\n}\n\n/**\n * Validation rule type for pre-computed validators\n * These are serializable rules extracted from field definitions at build time,\n * eliminating the need to compile validator closures at runtime.\n */\nexport type ValidationRuleType =\n | 'required'\n | 'min'\n | 'max'\n | 'minLength'\n | 'maxLength'\n | 'pattern';\n\n/**\n * Pre-computed validation rule for a field\n * Generated at build time by ManifestGenerator, stored in manifest.json\n *\n * These rules are evaluated at runtime without creating closure functions,\n * significantly reducing CLI startup time for projects with many SMRT objects.\n */\nexport interface ValidationRule {\n /** Field name to validate */\n field: string;\n /** Type of validation rule */\n rule: ValidationRuleType;\n /** Value for the rule (number for min/max/minLength/maxLength, string for pattern) */\n value?: number | string;\n /** Field type for context (text, integer, decimal, etc.) */\n fieldType?: string;\n}\n\n// ── Agent manifest types ────────────────────────────────────────────────\n\n/**\n * Permission declared by an agent\n * Generated from uiSlots (manage:*) and CLI/MCP methods (execute:*)\n */\nexport interface AgentPermission {\n id: string;\n label: string;\n category: 'slot' | 'method';\n defaultGranted?: boolean;\n}\n\n/**\n * Feature declared by an agent\n */\nexport interface AgentFeature {\n id: string;\n label: string;\n description?: string;\n type: 'slot' | 'method';\n}\n\n/**\n * Menu item derived from agent uiSlots\n */\nexport interface AgentMenuItem {\n id: string;\n label: string;\n icon?: string;\n order: number;\n path: string;\n requiredPermission?: string;\n}\n\n/**\n * Component export declaration derived from package.json exports\n */\nexport interface AgentComponentDeclaration {\n exportPath: string;\n type: string;\n}\n\n/**\n * UI slot definition captured from static uiSlots on Agent subclasses\n */\nexport interface AgentUISlotManifest {\n id: string;\n label: string;\n description?: string;\n icon?: string;\n order?: number;\n disabled?: boolean;\n /** Durable owner for settings written through this slot. */\n scope?: 'agent' | 'persona';\n /** Optional fallback form contract for host applications. */\n settingsSchema?: {\n version: number;\n fields: Array<{\n id: string;\n label: string;\n type: 'string' | 'number' | 'boolean' | 'select' | 'textarea' | 'json';\n description?: string;\n required?: boolean;\n default?: unknown;\n placeholder?: string;\n options?: Array<{ value: string; label: string }>;\n min?: number;\n max?: number;\n }>;\n };\n}\n\n/**\n * Admin route declared by an agent via static adminRoutes\n * Consumed by vitePluginAgentRoutes to register admin routes with SvelteKit\n */\nexport interface AgentAdminRouteManifest {\n /** Route path relative to agent root (e.g., 'sources/[sourceId]') */\n path: string;\n /** Component export name from the agent's admin entry point */\n component: string;\n /** Optional: export name for server load function */\n load?: string;\n}\n\n/**\n * Auto-generated agent manifest section\n * Produced by the manifest build pipeline for any class with `agent` decorator config\n */\nexport interface AgentManifest {\n name: string;\n slug: string;\n icon?: string;\n tier: 'free' | 'standard' | 'premium';\n description?: string;\n uiSlots: Record<string, AgentUISlotManifest>;\n adminRoutes?: AgentAdminRouteManifest[];\n /** Default signal subscriptions declared by this agent */\n signalSubscriptions?: string[];\n permissions: AgentPermission[];\n features: AgentFeature[];\n menuItems: AgentMenuItem[];\n components: AgentComponentDeclaration[];\n}\n\n// ── Core manifest types ─────────────────────────────────────────────────\n\nexport interface SmartObjectDefinition {\n /**\n * Qualified name in format \"@package/name:ClassName\"\n * This is the PRIMARY KEY for manifest lookups.\n * Example: \"@happyvertical/smrt-core:Product\"\n *\n * Optional during transition - will be required in future versions.\n */\n qualifiedName?: QualifiedClassName;\n\n /**\n * Simple class name (PascalCase)\n * Example: \"Product\"\n */\n className: string;\n\n /**\n * Package name where this class is defined.\n * Example: \"@happyvertical/smrt-core\"\n *\n * Optional during transition - will be required in future versions.\n */\n packageName?: string;\n\n /**\n * Visibility control for manifest inclusion\n * - 'public': Included in published manifest (default)\n * - 'internal': Package-only, excluded from published manifest\n * - 'test': Test-only, never in any published manifest\n *\n * Defaults to 'public' if not specified.\n */\n visibility?: SmrtVisibility;\n\n /**\n * @deprecated Use qualifiedName instead. Kept for transition period.\n * Lowercase class name, formerly used as manifest key.\n */\n name: string;\n\n collection: string; // Pluralized name for endpoints\n filePath: string;\n packageVersion?: string; // Package version for external manifest loading\n importPath?: string; // Import path for dynamic loading (e.g., \"@pkg/objects\")\n modulePath?: string; // Relative module path within package\n exportName?: string; // Named export to use (defaults to className)\n collectionExportName?: string; // Collection class export name\n fields: Record<string, FieldDefinition>;\n methods: Record<string, MethodDefinition>;\n decoratorConfig: SmartObjectConfig;\n extends?: string; // Base class name (simple name, not qualified)\n extendsQualified?: string; // Base class qualified name\n extendsTypeArg?: string; // Generic type argument (e.g., \"Meeting\" from \"SmrtCollection<Meeting>\")\n tools?: Array<{\n type: 'function';\n function: {\n name: string;\n description?: string;\n parameters?: Record<string, unknown>;\n };\n }>;\n /**\n * Pre-generated schema for efficient external package consumption\n * Generated at build time by ManifestGenerator (smrt scan)\n *\n * When present, consumers can use this pre-computed schema directly\n * without calling generateSchema() at runtime, eliminating latency.\n */\n schema?: ManifestSchema;\n\n /**\n * Pre-computed validation rules for efficient runtime validation\n * Generated at build time by ManifestGenerator (smrt scan)\n *\n * When present, the registry uses these rules instead of compiling\n * validator closures at runtime, significantly reducing startup time.\n *\n * @see ValidationRule\n */\n validationRules?: ValidationRule[];\n\n /**\n * Static properties captured from the class definition\n * Currently used for `static uiSlots` on Agent subclasses\n */\n staticProperties?: Record<string, unknown>;\n\n /**\n * Auto-generated agent manifest\n * Only present for classes with `agent` in their decorator config\n * Generated at build time by ManifestGenerator fifth pass\n */\n agent?: AgentManifest;\n}\n\n/**\n * Fixed `timestamp` for every manifest that can reach build output.\n *\n * Manifests are inlined into bundles (`registerPackageManifest(JSON.parse(...))`),\n * so a wall-clock value changes the emitted bytes on every build. That changes\n * Vite's content hash, which changes `dist/`, which invalidates every\n * downstream package through `dependsOn: ['^build']` — one rebuilt package\n * churned 202 of 245 task hashes, and `typecheck` never reused a cache entry\n * across runs (#2223).\n *\n * Nothing reads the field: `getManifestTimestampsHash` invalidates on\n * filesystem mtimes, and `normalizeManifestForHash` deletes it before\n * comparing. A fixed value therefore costs no information.\n *\n * Genuine runtime caches that expire on elapsed time — the discovery cache in\n * `manifest/discover-smrt-packages.ts` — keep using the clock; they never\n * reach build output.\n */\nexport const MANIFEST_TIMESTAMP = 0;\n\n/**\n * Fixed `generatedAt` for knowledge artifacts emitted into `dist/`.\n *\n * Same reasoning as {@link MANIFEST_TIMESTAMP}: build output is compared\n * byte-for-byte, so it cannot carry the clock. The Unix epoch is used rather\n * than `0` because the field is an ISO-8601 string, and a parseable value\n * keeps any consumer that formats it working.\n *\n * The working copy under `.smrt/` keeps a real timestamp — it is useful to a\n * human there, and `preserveKnowledgeGeneratedAt` already stops it churning\n * across incremental rebuilds.\n */\nexport const DETERMINISTIC_GENERATED_AT = '1970-01-01T00:00:00.000Z';\n\nexport interface SmartObjectManifest {\n version: string;\n /** Always {@link MANIFEST_TIMESTAMP} for build-output manifests. */\n timestamp: number;\n packageName?: string; // Root package name (should be set for all new manifests)\n packageVersion?: string; // Root package version\n /**\n * Objects keyed by qualified name (e.g., \"@happyvertical/smrt-core:Product\")\n * Key is string for backward compatibility, but should be QualifiedClassName format.\n */\n objects: Record<string, SmartObjectDefinition>;\n moduleType?: string; // Module type identifier (e.g., \"smrt\") for package discovery\n smrtDependencies?: string[]; // Discovered SMRT packages from dependency tree\n}\n\nexport interface ScanResult {\n filePath: string;\n objects: SmartObjectDefinition[];\n errors: Array<{\n message: string;\n line?: number;\n column?: number;\n }>;\n}\n\nexport interface ScanOptions {\n includePrivateMethods?: boolean;\n includeStaticMethods?: boolean;\n followImports?: boolean;\n baseClasses?: string[]; // Classes to consider as SMRT base classes\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAydA,IAAa,qBAAqB;;;;;;;;;;;;;AAclC,IAAa,6BAA6B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-strategy.d.ts","sourceRoot":"","sources":["../../../src/schema/ddl/base-strategy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA4B9D;;;;;GAKG;AACH,8BAAsB,eAAgB,YAAW,WAAW;IAC1D,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAEzC;;OAEG;IACH,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM;IAuBrD;;;;OAIG;IACH,wBAAwB,CACtB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,gBAAgB,GAC1B,MAAM;
|
|
1
|
+
{"version":3,"file":"base-strategy.d.ts","sourceRoot":"","sources":["../../../src/schema/ddl/base-strategy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA4B9D;;;;;GAKG;AACH,8BAAsB,eAAgB,YAAW,WAAW;IAC1D,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAEzC;;OAEG;IACH,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM;IAuBrD;;;;OAIG;IACH,wBAAwB,CACtB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,gBAAgB,GAC1B,MAAM;IA4CT;;;OAGG;IACH,SAAS,CAAC,+BAA+B,CACvC,OAAO,EAAE,eAAe,EAAE,GACzB,MAAM,EAAE;IA8BX;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE;IAwDnD;;;;;OAKG;IACH,SAAS,CAAC,6BAA6B,CACrC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,MAAM;IAKT;;;OAGG;IACH,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE;IAsBpD;;;OAGG;IACH,SAAS,CAAC,wBAAwB,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,iBAAiB,GACzB,MAAM;IAcT;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM;IA2BlC;;;;;;;;;OASG;IACH,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM;IAS7D;;;OAGG;IACH,SAAS,CAAC,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;IAItD;;;OAGG;IACH,gBAAgB,IAAI,OAAO;IAI3B;;;OAGG;IACH,oBAAoB,IAAI,OAAO;CAGhC"}
|
|
@@ -53,8 +53,8 @@ var BaseDDLStrategy = class {
|
|
|
53
53
|
*/
|
|
54
54
|
generateColumnDefinition(columnName, columnDef) {
|
|
55
55
|
const parts = [quoteIdentifier(columnName), this.mapType(columnDef.type)];
|
|
56
|
-
if (columnDef.primaryKey) parts.push("PRIMARY KEY");
|
|
57
|
-
if (columnDef.notNull
|
|
56
|
+
if (columnDef.primaryKey) parts.push("PRIMARY KEY", "NOT NULL");
|
|
57
|
+
else if (columnDef.notNull) parts.push("NOT NULL");
|
|
58
58
|
if (columnDef.unique && !columnDef.primaryKey) parts.push("UNIQUE");
|
|
59
59
|
if (columnDef.defaultValue !== void 0) {
|
|
60
60
|
const formatted = this.formatDefaultValue(columnDef.defaultValue, columnDef.type);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-strategy.js","names":[],"sources":["../../../src/schema/ddl/base-strategy.ts"],"sourcesContent":["/**\n * Base DDL Strategy - Shared logic for all database engines\n *\n * Provides common DDL generation logic that engine-specific strategies\n * can override for their particular requirements.\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport {\n formatDefaultValue as formatDefaultValueShared,\n isSafeIdentifier,\n isSafeIdentifierPath,\n quoteIdentifier,\n quoteStringLiteral,\n} from '../sql-identifiers.js';\nimport type {\n ColumnDefinition,\n IndexDefinition,\n SchemaDefinition,\n SQLDataType,\n TriggerDefinition,\n} from '../types.js';\nimport type { DatabaseEngine, DDLStrategy } from './types.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Validate the column + JSON path used to build a JSON-path index expression.\n *\n * The path segment is embedded as a SQL string literal inside a dialect\n * function/operator (`json_extract(\"col\", '$.path')` / `\"col\"->>'path'`), and\n * the column as a delimited identifier. We escape both, but also reject paths\n * or columns that aren't simple (dotted) identifiers so a malformed `@meta`\n * field name can't smuggle structure into the expression even after escaping.\n * These names are developer-controlled build-time inputs, so an invalid one is\n * a programming error and throwing is the safest, loudest outcome.\n */\nfunction assertSafeJsonPathTarget(jsonColumn: string, path: string): void {\n if (!isSafeIdentifier(jsonColumn)) {\n throw new Error(\n `[DDL] Unsafe JSON-path index column \"${jsonColumn}\": must be a simple identifier`,\n );\n }\n if (!isSafeIdentifierPath(path)) {\n throw new Error(\n `[DDL] Unsafe JSON-path index path \"${path}\": must be a simple (dotted) identifier`,\n );\n }\n}\n\n/**\n * Abstract base class for DDL strategies\n *\n * Implements common DDL generation patterns. Engine-specific strategies\n * extend this class and override methods as needed.\n */\nexport abstract class BaseDDLStrategy implements DDLStrategy {\n abstract readonly engine: DatabaseEngine;\n\n /**\n * Generate CREATE TABLE statement\n */\n generateCreateTable(schema: SchemaDefinition): string {\n const { tableName, columns, indexes = [] } = schema;\n\n let sql = `CREATE TABLE IF NOT EXISTS ${quoteIdentifier(tableName)} (\\n`;\n\n // Generate column definitions\n const columnDefs: string[] = [];\n for (const [columnName, columnDef] of Object.entries(columns)) {\n columnDefs.push(this.generateColumnDefinition(columnName, columnDef));\n }\n\n // Add inline UNIQUE constraints for engines that require them\n if (this.requiresInlineUnique() && indexes.length > 0) {\n const uniqueConstraints = this.generateInlineUniqueConstraints(indexes);\n columnDefs.push(...uniqueConstraints);\n }\n\n sql += columnDefs.map((def) => ` ${def}`).join(',\\n');\n sql += '\\n);';\n\n return sql;\n }\n\n /**\n * Generate a single column definition\n *\n * Public so SchemaManager can reuse it for ALTER TABLE ADD COLUMN.\n */\n generateColumnDefinition(\n columnName: string,\n columnDef: ColumnDefinition,\n ): string {\n const parts: string[] = [\n quoteIdentifier(columnName),\n this.mapType(columnDef.type),\n ];\n\n // Primary key\n if (columnDef.primaryKey) {\n parts.push('PRIMARY KEY');\n }\n\n // NOT NULL (skip for primary key - it's implicit)\n if (columnDef.notNull && !columnDef.primaryKey) {\n parts.push('NOT NULL');\n }\n\n // Column-level UNIQUE is already inline and must be preserved for every\n // engine. Some published manifests express single-column uniqueness only\n // on the column definition (without a duplicate IndexDefinition), so\n // suppressing it for DuckDB/JSON would silently weaken the schema.\n if (columnDef.unique && !columnDef.primaryKey) {\n parts.push('UNIQUE');\n }\n\n // DEFAULT value\n if (columnDef.defaultValue !== undefined) {\n const formatted = this.formatDefaultValue(\n columnDef.defaultValue,\n columnDef.type,\n );\n parts.push(`DEFAULT ${formatted}`);\n }\n\n // CHECK constraint\n if (columnDef.check) {\n parts.push(`CHECK (${columnDef.check})`);\n }\n\n return parts.join(' ');\n }\n\n /**\n * Generate inline UNIQUE constraints for composite indexes\n * Used by engines that require inline UNIQUE for UPSERT to work (DuckDB)\n */\n protected generateInlineUniqueConstraints(\n indexes: IndexDefinition[],\n ): string[] {\n const constraints: string[] = [];\n\n if (!indexes || !Array.isArray(indexes)) {\n return constraints;\n }\n\n for (const index of indexes) {\n // Skip malformed index entries\n if (!index?.columns || !Array.isArray(index.columns)) {\n continue;\n }\n\n // Partial and expression-backed unique indexes are not valid generic\n // ON CONFLICT(column, ...) targets and cannot be represented as an\n // inline column UNIQUE constraint without changing their semantics.\n if (\n index.unique &&\n !index.where &&\n !index.jsonPath &&\n index.columns.length > 0\n ) {\n const columns = index.columns.map((c) => quoteIdentifier(c)).join(', ');\n constraints.push(`UNIQUE(${columns})`);\n }\n }\n\n return constraints;\n }\n\n /**\n * Generate CREATE INDEX statements\n * Override in engine-specific strategies if needed\n */\n generateIndexes(schema: SchemaDefinition): string[] {\n const { tableName, indexes = [] } = schema;\n const statements: string[] = [];\n\n if (!indexes || indexes.length === 0) {\n return statements;\n }\n\n for (const index of indexes) {\n // Narrow the jsonPath target up-front so the formatter call doesn't\n // need optional-chained args (and so the malformed-entry check has a\n // single source of truth).\n const jsonPath =\n index?.jsonPath?.column && index.jsonPath.path ? index.jsonPath : null;\n if (\n !index ||\n (!jsonPath &&\n (!index.columns ||\n !Array.isArray(index.columns) ||\n index.columns.length === 0))\n ) {\n logger.warn(`[DDL] Skipping malformed index: ${JSON.stringify(index)}`);\n continue;\n }\n\n // Skip UNIQUE indexes if engine requires them inline\n if (index.unique && this.requiresInlineUnique()) {\n continue;\n }\n\n const indexType = index.unique ? 'UNIQUE INDEX' : 'INDEX';\n\n // JSON-path indexes use a dialect-specific expression\n const target = jsonPath\n ? `(${this.formatJsonPathIndexExpression(\n jsonPath.column,\n jsonPath.path,\n )})`\n : index.columns.map((c) => quoteIdentifier(c)).join(', ');\n\n let sql = `CREATE ${indexType} IF NOT EXISTS ${quoteIdentifier(\n index.name,\n )} ON ${quoteIdentifier(tableName)} (${target})`;\n\n // Partial index condition\n if (index.where) {\n sql += ` WHERE ${index.where}`;\n }\n\n sql += ';';\n statements.push(sql);\n }\n\n return statements;\n }\n\n /**\n * Render the SQL expression used to index a JSON path inside a JSONB column.\n * Subclasses override for dialect-specific syntax.\n *\n * Default (ANSI-ish): `<jsonColumn>->>'<path>'` — works on Postgres.\n */\n protected formatJsonPathIndexExpression(\n jsonColumn: string,\n path: string,\n ): string {\n assertSafeJsonPathTarget(jsonColumn, path);\n return `${quoteIdentifier(jsonColumn)}->>${quoteStringLiteral(path)}`;\n }\n\n /**\n * Generate CREATE TRIGGER statements\n * Override in engine-specific strategies - DuckDB returns empty\n */\n generateTriggers(schema: SchemaDefinition): string[] {\n if (!this.supportsTriggers()) {\n return [];\n }\n\n const { tableName, triggers = [] } = schema;\n const statements: string[] = [];\n\n if (!triggers || triggers.length === 0) {\n return statements;\n }\n\n for (const trigger of triggers) {\n const sql = this.generateTriggerStatement(tableName, trigger);\n if (sql) {\n statements.push(sql);\n }\n }\n\n return statements;\n }\n\n /**\n * Generate a single trigger statement\n * Can be overridden for engine-specific trigger syntax\n */\n protected generateTriggerStatement(\n tableName: string,\n trigger: TriggerDefinition,\n ): string {\n // Default SQLite-style trigger syntax\n let sql = `CREATE TRIGGER IF NOT EXISTS ${quoteIdentifier(trigger.name)}\\n`;\n sql += `${trigger.when} ${trigger.event} ON ${quoteIdentifier(tableName)}\\n`;\n\n if (trigger.condition) {\n sql += `WHEN ${trigger.condition}\\n`;\n }\n\n sql += `BEGIN\\n${trigger.body}\\nEND;`;\n\n return sql;\n }\n\n /**\n * Map abstract SQL type to engine-specific type\n * Default implementation - override for engine-specific types\n */\n mapType(type: SQLDataType): string {\n // Default mapping works for most engines\n switch (type) {\n case 'TEXT':\n return 'TEXT';\n case 'INTEGER':\n return 'INTEGER';\n case 'REAL':\n return 'REAL';\n case 'BLOB':\n return 'BLOB';\n case 'BOOLEAN':\n return 'BOOLEAN';\n case 'JSON':\n return 'JSON';\n case 'TIMESTAMP':\n return 'TIMESTAMP';\n case 'UUID':\n // Fallback for engines without a native uuid type (e.g. SQLite):\n // store as TEXT. PostgreSQL/DuckDB override this with their native\n // uuid type. (R11)\n return 'TEXT';\n default:\n return 'TEXT';\n }\n }\n\n /**\n * Format default value for SQL.\n *\n * Delegates to the shared, injection-safe `formatDefaultValue`\n * (`schema/sql-identifiers.ts`) so every DDL path uses one set of rules:\n * an allowlist of SQL keyword/function defaults (not \"contains `(`\"),\n * type-driven literal quoting, and no folding of the string `\"null\"` into\n * the SQL NULL keyword. Boolean rendering is bridged through\n * `formatBooleanDefault` so engine overrides (SQLite → 0/1) still apply.\n */\n formatDefaultValue(value: unknown, type: SQLDataType): string {\n return formatDefaultValueShared(value, type, {\n booleanLiterals: [\n this.formatBooleanDefault(true),\n this.formatBooleanDefault(false),\n ],\n });\n }\n\n /**\n * Format boolean default\n * Override for engines that use INTEGER (SQLite)\n */\n protected formatBooleanDefault(value: boolean): string {\n return value ? 'TRUE' : 'FALSE';\n }\n\n /**\n * Whether this engine supports triggers\n * Override in DuckDB strategy to return false\n */\n supportsTriggers(): boolean {\n return true;\n }\n\n /**\n * Whether UNIQUE constraints must be inline for UPSERT\n * Override in DuckDB strategy to return true\n */\n requiresInlineUnique(): boolean {\n return false;\n }\n}\n"],"mappings":";;;;;;;;;AAwBA,IAAM,SAAS,aAAa,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;;AAa7C,SAAS,yBAAyB,YAAoB,MAAoB;CACxE,IAAI,CAAC,iBAAiB,UAAU,GAC9B,MAAM,IAAI,MACR,wCAAwC,WAAW,+BACrD;CAEF,IAAI,CAAC,qBAAqB,IAAI,GAC5B,MAAM,IAAI,MACR,sCAAsC,KAAK,wCAC7C;AAEJ;;;;;;;AAQA,IAAsB,kBAAtB,MAA6D;;;;CAM3D,oBAAoB,QAAkC;EACpD,MAAM,EAAE,WAAW,SAAS,UAAU,CAAC,MAAM;EAE7C,IAAI,MAAM,8BAA8B,gBAAgB,SAAS,EAAE;EAGnE,MAAM,aAAuB,CAAC;EAC9B,KAAK,MAAM,CAAC,YAAY,cAAc,OAAO,QAAQ,OAAO,GAC1D,WAAW,KAAK,KAAK,yBAAyB,YAAY,SAAS,CAAC;EAItE,IAAI,KAAK,qBAAqB,KAAK,QAAQ,SAAS,GAAG;GACrD,MAAM,oBAAoB,KAAK,gCAAgC,OAAO;GACtE,WAAW,KAAK,GAAG,iBAAiB;EACtC;EAEA,OAAO,WAAW,KAAK,QAAQ,KAAK,KAAK,CAAC,CAAC,KAAK,KAAK;EACrD,OAAO;EAEP,OAAO;CACT;;;;;;CAOA,yBACE,YACA,WACQ;EACR,MAAM,QAAkB,CACtB,gBAAgB,UAAU,GAC1B,KAAK,QAAQ,UAAU,IAAI,CAC7B;EAGA,IAAI,UAAU,YACZ,MAAM,KAAK,aAAa;EAI1B,IAAI,UAAU,WAAW,CAAC,UAAU,YAClC,MAAM,KAAK,UAAU;EAOvB,IAAI,UAAU,UAAU,CAAC,UAAU,YACjC,MAAM,KAAK,QAAQ;EAIrB,IAAI,UAAU,iBAAiB,KAAA,GAAW;GACxC,MAAM,YAAY,KAAK,mBACrB,UAAU,cACV,UAAU,IACZ;GACA,MAAM,KAAK,WAAW,WAAW;EACnC;EAGA,IAAI,UAAU,OACZ,MAAM,KAAK,UAAU,UAAU,MAAM,EAAE;EAGzC,OAAO,MAAM,KAAK,GAAG;CACvB;;;;;CAMA,gCACE,SACU;EACV,MAAM,cAAwB,CAAC;EAE/B,IAAI,CAAC,WAAW,CAAC,MAAM,QAAQ,OAAO,GACpC,OAAO;EAGT,KAAK,MAAM,SAAS,SAAS;GAE3B,IAAI,CAAC,OAAO,WAAW,CAAC,MAAM,QAAQ,MAAM,OAAO,GACjD;GAMF,IACE,MAAM,UACN,CAAC,MAAM,SACP,CAAC,MAAM,YACP,MAAM,QAAQ,SAAS,GACvB;IACA,MAAM,UAAU,MAAM,QAAQ,KAAK,MAAM,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;IACtE,YAAY,KAAK,UAAU,QAAQ,EAAE;GACvC;EACF;EAEA,OAAO;CACT;;;;;CAMA,gBAAgB,QAAoC;EAClD,MAAM,EAAE,WAAW,UAAU,CAAC,MAAM;EACpC,MAAM,aAAuB,CAAC;EAE9B,IAAI,CAAC,WAAW,QAAQ,WAAW,GACjC,OAAO;EAGT,KAAK,MAAM,SAAS,SAAS;GAI3B,MAAM,WACJ,OAAO,UAAU,UAAU,MAAM,SAAS,OAAO,MAAM,WAAW;GACpE,IACE,CAAC,SACA,CAAC,aACC,CAAC,MAAM,WACN,CAAC,MAAM,QAAQ,MAAM,OAAO,KAC5B,MAAM,QAAQ,WAAW,IAC7B;IACA,OAAO,KAAK,mCAAmC,KAAK,UAAU,KAAK,GAAG;IACtE;GACF;GAGA,IAAI,MAAM,UAAU,KAAK,qBAAqB,GAC5C;GAGF,MAAM,YAAY,MAAM,SAAS,iBAAiB;GAGlD,MAAM,SAAS,WACX,IAAI,KAAK,8BACP,SAAS,QACT,SAAS,IACX,EAAE,KACF,MAAM,QAAQ,KAAK,MAAM,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;GAE1D,IAAI,MAAM,UAAU,UAAU,iBAAiB,gBAC7C,MAAM,IACR,EAAE,MAAM,gBAAgB,SAAS,EAAE,IAAI,OAAO;GAG9C,IAAI,MAAM,OACR,OAAO,UAAU,MAAM;GAGzB,OAAO;GACP,WAAW,KAAK,GAAG;EACrB;EAEA,OAAO;CACT;;;;;;;CAQA,8BACE,YACA,MACQ;EACR,yBAAyB,YAAY,IAAI;EACzC,OAAO,GAAG,gBAAgB,UAAU,EAAE,KAAK,mBAAmB,IAAI;CACpE;;;;;CAMA,iBAAiB,QAAoC;EACnD,IAAI,CAAC,KAAK,iBAAiB,GACzB,OAAO,CAAC;EAGV,MAAM,EAAE,WAAW,WAAW,CAAC,MAAM;EACrC,MAAM,aAAuB,CAAC;EAE9B,IAAI,CAAC,YAAY,SAAS,WAAW,GACnC,OAAO;EAGT,KAAK,MAAM,WAAW,UAAU;GAC9B,MAAM,MAAM,KAAK,yBAAyB,WAAW,OAAO;GAC5D,IAAI,KACF,WAAW,KAAK,GAAG;EAEvB;EAEA,OAAO;CACT;;;;;CAMA,yBACE,WACA,SACQ;EAER,IAAI,MAAM,gCAAgC,gBAAgB,QAAQ,IAAI,EAAE;EACxE,OAAO,GAAG,QAAQ,KAAK,GAAG,QAAQ,MAAM,MAAM,gBAAgB,SAAS,EAAE;EAEzE,IAAI,QAAQ,WACV,OAAO,QAAQ,QAAQ,UAAU;EAGnC,OAAO,UAAU,QAAQ,KAAK;EAE9B,OAAO;CACT;;;;;CAMA,QAAQ,MAA2B;EAEjC,QAAQ,MAAR;GACE,KAAK,QACH,OAAO;GACT,KAAK,WACH,OAAO;GACT,KAAK,QACH,OAAO;GACT,KAAK,QACH,OAAO;GACT,KAAK,WACH,OAAO;GACT,KAAK,QACH,OAAO;GACT,KAAK,aACH,OAAO;GACT,KAAK,QAIH,OAAO;GACT,SACE,OAAO;EACX;CACF;;;;;;;;;;;CAYA,mBAAmB,OAAgB,MAA2B;EAC5D,OAAO,mBAAyB,OAAO,MAAM,EAC3C,iBAAiB,CACf,KAAK,qBAAqB,IAAI,GAC9B,KAAK,qBAAqB,KAAK,CACjC,EACF,CAAC;CACH;;;;;CAMA,qBAA+B,OAAwB;EACrD,OAAO,QAAQ,SAAS;CAC1B;;;;;CAMA,mBAA4B;EAC1B,OAAO;CACT;;;;;CAMA,uBAAgC;EAC9B,OAAO;CACT;AACF"}
|
|
1
|
+
{"version":3,"file":"base-strategy.js","names":[],"sources":["../../../src/schema/ddl/base-strategy.ts"],"sourcesContent":["/**\n * Base DDL Strategy - Shared logic for all database engines\n *\n * Provides common DDL generation logic that engine-specific strategies\n * can override for their particular requirements.\n */\n\nimport { createLogger } from '@happyvertical/logger';\nimport {\n formatDefaultValue as formatDefaultValueShared,\n isSafeIdentifier,\n isSafeIdentifierPath,\n quoteIdentifier,\n quoteStringLiteral,\n} from '../sql-identifiers.js';\nimport type {\n ColumnDefinition,\n IndexDefinition,\n SchemaDefinition,\n SQLDataType,\n TriggerDefinition,\n} from '../types.js';\nimport type { DatabaseEngine, DDLStrategy } from './types.js';\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Validate the column + JSON path used to build a JSON-path index expression.\n *\n * The path segment is embedded as a SQL string literal inside a dialect\n * function/operator (`json_extract(\"col\", '$.path')` / `\"col\"->>'path'`), and\n * the column as a delimited identifier. We escape both, but also reject paths\n * or columns that aren't simple (dotted) identifiers so a malformed `@meta`\n * field name can't smuggle structure into the expression even after escaping.\n * These names are developer-controlled build-time inputs, so an invalid one is\n * a programming error and throwing is the safest, loudest outcome.\n */\nfunction assertSafeJsonPathTarget(jsonColumn: string, path: string): void {\n if (!isSafeIdentifier(jsonColumn)) {\n throw new Error(\n `[DDL] Unsafe JSON-path index column \"${jsonColumn}\": must be a simple identifier`,\n );\n }\n if (!isSafeIdentifierPath(path)) {\n throw new Error(\n `[DDL] Unsafe JSON-path index path \"${path}\": must be a simple (dotted) identifier`,\n );\n }\n}\n\n/**\n * Abstract base class for DDL strategies\n *\n * Implements common DDL generation patterns. Engine-specific strategies\n * extend this class and override methods as needed.\n */\nexport abstract class BaseDDLStrategy implements DDLStrategy {\n abstract readonly engine: DatabaseEngine;\n\n /**\n * Generate CREATE TABLE statement\n */\n generateCreateTable(schema: SchemaDefinition): string {\n const { tableName, columns, indexes = [] } = schema;\n\n let sql = `CREATE TABLE IF NOT EXISTS ${quoteIdentifier(tableName)} (\\n`;\n\n // Generate column definitions\n const columnDefs: string[] = [];\n for (const [columnName, columnDef] of Object.entries(columns)) {\n columnDefs.push(this.generateColumnDefinition(columnName, columnDef));\n }\n\n // Add inline UNIQUE constraints for engines that require them\n if (this.requiresInlineUnique() && indexes.length > 0) {\n const uniqueConstraints = this.generateInlineUniqueConstraints(indexes);\n columnDefs.push(...uniqueConstraints);\n }\n\n sql += columnDefs.map((def) => ` ${def}`).join(',\\n');\n sql += '\\n);';\n\n return sql;\n }\n\n /**\n * Generate a single column definition\n *\n * Public so SchemaManager can reuse it for ALTER TABLE ADD COLUMN.\n */\n generateColumnDefinition(\n columnName: string,\n columnDef: ColumnDefinition,\n ): string {\n const parts: string[] = [\n quoteIdentifier(columnName),\n this.mapType(columnDef.type),\n ];\n\n // Primary key. NOT NULL is emitted explicitly as well: SQLite's legacy\n // behaviour lets a non-INTEGER PRIMARY KEY column hold NULL, so a bare\n // `\"id\" TEXT PRIMARY KEY` accepts NULL ids there (#2358). PostgreSQL and\n // DuckDB already imply NOT NULL for a primary key; the explicit clause is\n // redundant but valid on every engine, and matches the engine-neutral\n // `SchemaGenerator.generateSQL()` output for SMRT-generated id columns\n // (which always carry `notNull: true`).\n if (columnDef.primaryKey) {\n parts.push('PRIMARY KEY', 'NOT NULL');\n } else if (columnDef.notNull) {\n parts.push('NOT NULL');\n }\n\n // Column-level UNIQUE is already inline and must be preserved for every\n // engine. Some published manifests express single-column uniqueness only\n // on the column definition (without a duplicate IndexDefinition), so\n // suppressing it for DuckDB/JSON would silently weaken the schema.\n if (columnDef.unique && !columnDef.primaryKey) {\n parts.push('UNIQUE');\n }\n\n // DEFAULT value\n if (columnDef.defaultValue !== undefined) {\n const formatted = this.formatDefaultValue(\n columnDef.defaultValue,\n columnDef.type,\n );\n parts.push(`DEFAULT ${formatted}`);\n }\n\n // CHECK constraint\n if (columnDef.check) {\n parts.push(`CHECK (${columnDef.check})`);\n }\n\n return parts.join(' ');\n }\n\n /**\n * Generate inline UNIQUE constraints for composite indexes\n * Used by engines that require inline UNIQUE for UPSERT to work (DuckDB)\n */\n protected generateInlineUniqueConstraints(\n indexes: IndexDefinition[],\n ): string[] {\n const constraints: string[] = [];\n\n if (!indexes || !Array.isArray(indexes)) {\n return constraints;\n }\n\n for (const index of indexes) {\n // Skip malformed index entries\n if (!index?.columns || !Array.isArray(index.columns)) {\n continue;\n }\n\n // Partial and expression-backed unique indexes are not valid generic\n // ON CONFLICT(column, ...) targets and cannot be represented as an\n // inline column UNIQUE constraint without changing their semantics.\n if (\n index.unique &&\n !index.where &&\n !index.jsonPath &&\n index.columns.length > 0\n ) {\n const columns = index.columns.map((c) => quoteIdentifier(c)).join(', ');\n constraints.push(`UNIQUE(${columns})`);\n }\n }\n\n return constraints;\n }\n\n /**\n * Generate CREATE INDEX statements\n * Override in engine-specific strategies if needed\n */\n generateIndexes(schema: SchemaDefinition): string[] {\n const { tableName, indexes = [] } = schema;\n const statements: string[] = [];\n\n if (!indexes || indexes.length === 0) {\n return statements;\n }\n\n for (const index of indexes) {\n // Narrow the jsonPath target up-front so the formatter call doesn't\n // need optional-chained args (and so the malformed-entry check has a\n // single source of truth).\n const jsonPath =\n index?.jsonPath?.column && index.jsonPath.path ? index.jsonPath : null;\n if (\n !index ||\n (!jsonPath &&\n (!index.columns ||\n !Array.isArray(index.columns) ||\n index.columns.length === 0))\n ) {\n logger.warn(`[DDL] Skipping malformed index: ${JSON.stringify(index)}`);\n continue;\n }\n\n // Skip UNIQUE indexes if engine requires them inline\n if (index.unique && this.requiresInlineUnique()) {\n continue;\n }\n\n const indexType = index.unique ? 'UNIQUE INDEX' : 'INDEX';\n\n // JSON-path indexes use a dialect-specific expression\n const target = jsonPath\n ? `(${this.formatJsonPathIndexExpression(\n jsonPath.column,\n jsonPath.path,\n )})`\n : index.columns.map((c) => quoteIdentifier(c)).join(', ');\n\n let sql = `CREATE ${indexType} IF NOT EXISTS ${quoteIdentifier(\n index.name,\n )} ON ${quoteIdentifier(tableName)} (${target})`;\n\n // Partial index condition\n if (index.where) {\n sql += ` WHERE ${index.where}`;\n }\n\n sql += ';';\n statements.push(sql);\n }\n\n return statements;\n }\n\n /**\n * Render the SQL expression used to index a JSON path inside a JSONB column.\n * Subclasses override for dialect-specific syntax.\n *\n * Default (ANSI-ish): `<jsonColumn>->>'<path>'` — works on Postgres.\n */\n protected formatJsonPathIndexExpression(\n jsonColumn: string,\n path: string,\n ): string {\n assertSafeJsonPathTarget(jsonColumn, path);\n return `${quoteIdentifier(jsonColumn)}->>${quoteStringLiteral(path)}`;\n }\n\n /**\n * Generate CREATE TRIGGER statements\n * Override in engine-specific strategies - DuckDB returns empty\n */\n generateTriggers(schema: SchemaDefinition): string[] {\n if (!this.supportsTriggers()) {\n return [];\n }\n\n const { tableName, triggers = [] } = schema;\n const statements: string[] = [];\n\n if (!triggers || triggers.length === 0) {\n return statements;\n }\n\n for (const trigger of triggers) {\n const sql = this.generateTriggerStatement(tableName, trigger);\n if (sql) {\n statements.push(sql);\n }\n }\n\n return statements;\n }\n\n /**\n * Generate a single trigger statement\n * Can be overridden for engine-specific trigger syntax\n */\n protected generateTriggerStatement(\n tableName: string,\n trigger: TriggerDefinition,\n ): string {\n // Default SQLite-style trigger syntax\n let sql = `CREATE TRIGGER IF NOT EXISTS ${quoteIdentifier(trigger.name)}\\n`;\n sql += `${trigger.when} ${trigger.event} ON ${quoteIdentifier(tableName)}\\n`;\n\n if (trigger.condition) {\n sql += `WHEN ${trigger.condition}\\n`;\n }\n\n sql += `BEGIN\\n${trigger.body}\\nEND;`;\n\n return sql;\n }\n\n /**\n * Map abstract SQL type to engine-specific type\n * Default implementation - override for engine-specific types\n */\n mapType(type: SQLDataType): string {\n // Default mapping works for most engines\n switch (type) {\n case 'TEXT':\n return 'TEXT';\n case 'INTEGER':\n return 'INTEGER';\n case 'REAL':\n return 'REAL';\n case 'BLOB':\n return 'BLOB';\n case 'BOOLEAN':\n return 'BOOLEAN';\n case 'JSON':\n return 'JSON';\n case 'TIMESTAMP':\n return 'TIMESTAMP';\n case 'UUID':\n // Fallback for engines without a native uuid type (e.g. SQLite):\n // store as TEXT. PostgreSQL/DuckDB override this with their native\n // uuid type. (R11)\n return 'TEXT';\n default:\n return 'TEXT';\n }\n }\n\n /**\n * Format default value for SQL.\n *\n * Delegates to the shared, injection-safe `formatDefaultValue`\n * (`schema/sql-identifiers.ts`) so every DDL path uses one set of rules:\n * an allowlist of SQL keyword/function defaults (not \"contains `(`\"),\n * type-driven literal quoting, and no folding of the string `\"null\"` into\n * the SQL NULL keyword. Boolean rendering is bridged through\n * `formatBooleanDefault` so engine overrides (SQLite → 0/1) still apply.\n */\n formatDefaultValue(value: unknown, type: SQLDataType): string {\n return formatDefaultValueShared(value, type, {\n booleanLiterals: [\n this.formatBooleanDefault(true),\n this.formatBooleanDefault(false),\n ],\n });\n }\n\n /**\n * Format boolean default\n * Override for engines that use INTEGER (SQLite)\n */\n protected formatBooleanDefault(value: boolean): string {\n return value ? 'TRUE' : 'FALSE';\n }\n\n /**\n * Whether this engine supports triggers\n * Override in DuckDB strategy to return false\n */\n supportsTriggers(): boolean {\n return true;\n }\n\n /**\n * Whether UNIQUE constraints must be inline for UPSERT\n * Override in DuckDB strategy to return true\n */\n requiresInlineUnique(): boolean {\n return false;\n }\n}\n"],"mappings":"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"}
|