@snolla/data 0.0.0-stage → 1.0.7
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/dist/actor.d.ts +28 -0
- package/dist/actor.js +63 -0
- package/dist/audit.d.ts +36 -0
- package/dist/audit.js +198 -0
- package/dist/dataProvider.d.ts +41 -0
- package/dist/dataProvider.js +148 -0
- package/dist/dataSource.d.ts +4 -0
- package/dist/dataSource.js +65 -0
- package/dist/dbProvider.d.ts +1261 -0
- package/dist/dbProvider.js +1898 -0
- package/dist/freeze.d.ts +29 -0
- package/dist/freeze.js +69 -0
- package/dist/guard.d.ts +53 -0
- package/dist/guard.js +397 -0
- package/dist/insert.d.ts +9 -0
- package/dist/insert.js +44 -0
- package/dist/migrations/siteid.d.mts +738 -0
- package/dist/migrations/siteid.mjs +512 -0
- package/dist/publish.d.ts +1 -0
- package/dist/publish.js +1 -0
- package/dist/schema/dsl.d.ts +64 -0
- package/dist/schema/dsl.js +28 -0
- package/dist/schema/generate.d.mts +14 -0
- package/dist/schema/generate.mjs +282 -0
- package/dist/schema/generated/ddl.d.ts +7 -0
- package/dist/schema/generated/ddl.js +11 -0
- package/dist/schema/generated/kysely-types.d.ts +1988 -0
- package/dist/schema/generated/kysely-types.js +5 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +7 -0
- package/dist/schema/provision.d.mts +11 -0
- package/dist/schema/provision.mjs +111 -0
- package/dist/schema/tables.d.ts +2 -0
- package/dist/schema/tables.js +3301 -0
- package/dist/scripts/canon-audit.d.mts +25 -0
- package/dist/scripts/canon-audit.mjs +213 -0
- package/dist/scripts/canon-smoke.d.mts +1 -0
- package/dist/scripts/canon-smoke.mjs +44 -0
- package/dist/scripts/dialect-ddl-stand.d.mts +1 -0
- package/dist/scripts/dialect-ddl-stand.mjs +136 -0
- package/dist/scripts/owner-spec-check.d.mts +1 -0
- package/dist/scripts/owner-spec-check.mjs +166 -0
- package/dist/scripts/owners/owner-resolve-spec.json +540 -0
- package/dist/scripts/owners-audit.d.mts +60 -0
- package/dist/scripts/owners-audit.mjs +443 -0
- package/dist/scripts/owners-fixture.d.mts +20 -0
- package/dist/scripts/owners-fixture.mjs +192 -0
- package/dist/scripts/schema-lengths-audit.d.mts +22 -0
- package/dist/scripts/schema-lengths-audit.mjs +146 -0
- package/dist/scripts/siteid-migrate.d.mts +7 -0
- package/dist/scripts/siteid-migrate.mjs +260 -0
- package/dist/scripts/tenant-invariant-audit.d.mts +1 -0
- package/dist/scripts/tenant-invariant-audit.mjs +34 -0
- package/dist/singleMode.d.ts +5 -0
- package/dist/singleMode.js +23 -0
- package/dist/sqliteDialect.d.ts +6 -0
- package/dist/sqliteDialect.js +92 -0
- package/dist/templateDefs.d.ts +38 -0
- package/dist/templateDefs.js +163 -0
- package/dist/test/fixtures/broken-driver/index.d.ts +3 -0
- package/dist/test/fixtures/broken-driver/index.js +5 -0
- package/dist/test/support/dialect-stand.d.ts +37 -0
- package/dist/test/support/dialect-stand.js +162 -0
- package/dist/test/support/render-parity.d.ts +44 -0
- package/dist/test/support/render-parity.js +262 -0
- package/package.json +50 -5
- package/README.md +0 -3
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
// The render-parity harness (task:3824, plan:50 Q7, requirements:66 п.7): the
|
|
2
|
+
// plumbing that decides whether the same engine renders the same bytes from a
|
|
3
|
+
// different DSN.
|
|
4
|
+
//
|
|
5
|
+
// Not a test file and not a runner: capture / normalize / diff / report are pure
|
|
6
|
+
// enough to be unit-tested, and the same functions are what the cutover runbook
|
|
7
|
+
// (task:3828) will wrap in a CLI. Nothing here boots an engine or opens a
|
|
8
|
+
// database — an engine reaches the harness as an origin (a base URL), which is
|
|
9
|
+
// what keeps "run it against any target DSN" true.
|
|
10
|
+
//
|
|
11
|
+
// const pages = await loadPageSet();
|
|
12
|
+
// const from = await captureSite({ origin: baseline, pages });
|
|
13
|
+
// const to = await captureSite({ origin: target, pages });
|
|
14
|
+
// const diffs = diffSnapshots(from, to);
|
|
15
|
+
// if (diffs.length) throw new Error(formatReport({ baseline, target, diffs }));
|
|
16
|
+
import { readFile } from 'node:fs/promises';
|
|
17
|
+
/** The fixed capture kinds (plan:50 Q7.1); a page set must match this exactly. */
|
|
18
|
+
export const PAGE_KINDS = [
|
|
19
|
+
'home',
|
|
20
|
+
'catalog',
|
|
21
|
+
'catalog-pagination',
|
|
22
|
+
'product',
|
|
23
|
+
'post',
|
|
24
|
+
'page',
|
|
25
|
+
'sitemap',
|
|
26
|
+
'robots',
|
|
27
|
+
'redirect',
|
|
28
|
+
'redirect',
|
|
29
|
+
];
|
|
30
|
+
const DEFAULT_PAGE_SET = new URL('../fixtures/render-parity/pages.json', import.meta.url);
|
|
31
|
+
/**
|
|
32
|
+
* Loads a page set — the shipped fixture by default, or an explicit file (a site
|
|
33
|
+
* passes its own real URLs, e.g. «Стайер»'s catalog paths, via TEST_RENDER_PAGES).
|
|
34
|
+
* The set is a fixed denominator: it must match PAGE_KINDS exactly and may not
|
|
35
|
+
* repeat a name or a path, so a silently shrinking set can never silently weaken
|
|
36
|
+
* the check.
|
|
37
|
+
*/
|
|
38
|
+
export const loadPageSet = async (source = undefined) => {
|
|
39
|
+
const raw = source === undefined
|
|
40
|
+
? JSON.parse(await readFile(DEFAULT_PAGE_SET, 'utf8'))
|
|
41
|
+
: typeof source === 'string' || source instanceof URL
|
|
42
|
+
? JSON.parse(await readFile(source, 'utf8'))
|
|
43
|
+
: source;
|
|
44
|
+
const pages = Array.isArray(raw) ? raw : raw.pages;
|
|
45
|
+
if (!Array.isArray(pages) || !pages.length)
|
|
46
|
+
throw new Error('page set: no pages');
|
|
47
|
+
for (const page of pages) {
|
|
48
|
+
if (!page || typeof page.name !== 'string' || typeof page.path !== 'string' || typeof page.kind !== 'string') {
|
|
49
|
+
throw new Error('page set: every page needs { name, kind, path }');
|
|
50
|
+
}
|
|
51
|
+
if (!PAGE_KINDS.includes(page.kind))
|
|
52
|
+
throw new Error(`page set: unknown kind "${page.kind}"`);
|
|
53
|
+
if (!page.path.startsWith('/') || page.path.startsWith('//') || page.path.includes('..')) {
|
|
54
|
+
throw new Error(`page set: "${page.name}" path must be an origin-relative path`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (new Set(pages.map((page) => page.name)).size !== pages.length)
|
|
58
|
+
throw new Error('page set: duplicated name');
|
|
59
|
+
if (new Set(pages.map((page) => page.path)).size !== pages.length)
|
|
60
|
+
throw new Error('page set: duplicated path');
|
|
61
|
+
if (pages.length !== PAGE_KINDS.length || pages.filter((page) => page.kind === 'redirect').length !== 2) {
|
|
62
|
+
throw new Error(`page set: kinds must be exactly the ${PAGE_KINDS.length} Q7 captures (redirect ×2)`);
|
|
63
|
+
}
|
|
64
|
+
for (const kind of PAGE_KINDS) {
|
|
65
|
+
if (!pages.some((page) => page.kind === kind))
|
|
66
|
+
throw new Error(`page set: kind "${kind}" is not captured`);
|
|
67
|
+
}
|
|
68
|
+
return pages;
|
|
69
|
+
};
|
|
70
|
+
// Cache-busting suffixes the two engines add differently (`?v=`, `?ver=`, `?cb=`,
|
|
71
|
+
// `?t=`, `?_=`) — noise for parity, never content. Matched only as whole query
|
|
72
|
+
// parameter names so `?width=` or `?video=` survive.
|
|
73
|
+
const CACHE_BUST = /([?&])(?:v|ver|cb|t|_)=[^"'&<>#\s]*/g;
|
|
74
|
+
/** Query-string leftovers once the cache-busting parameters are gone (`/a.css?` → `/a.css`). */
|
|
75
|
+
const tidyQuery = (text) => text
|
|
76
|
+
.replace(/\?&/g, '?')
|
|
77
|
+
.replace(/&&+/g, '&')
|
|
78
|
+
.replace(/[?&](?=["'<>\s]|#|$)/g, '');
|
|
79
|
+
/** Drops cache-busting parameters from one URL. */
|
|
80
|
+
export const stripCacheBust = (url) => tidyQuery(url.replace(CACHE_BUST, '$1'));
|
|
81
|
+
const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
82
|
+
/**
|
|
83
|
+
* The served origin is noise; a foreign one is content. Boundary-aware, so an
|
|
84
|
+
* origin that merely prefixes another (`:3000` vs `:30001`) is left alone. An
|
|
85
|
+
* origin embedded inside a *foreign* URL's query is still relativized — accepted:
|
|
86
|
+
* it costs a diff excerpt, not a silent pass (the pair of engines is the same
|
|
87
|
+
* codebase, so a foreign-URL-embedding query is not where parity breaks).
|
|
88
|
+
*/
|
|
89
|
+
const relativizeOrigin = (text, origin) => text.replace(new RegExp(`${escapeRegExp(origin)}(?=[/?#"'<>\s]|$)`, 'g'), '');
|
|
90
|
+
/** HTML tags whose attributes are order-noise; comments, doctype and closing tags are left alone. */
|
|
91
|
+
const TAG = /<(\/?)([a-zA-Z][^\s/>]*)((?:"[^"]*"|'[^']*'|[^>"'])*)>/g;
|
|
92
|
+
const ATTRIBUTE = /([^\s=/>]+)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s>]+))?/g;
|
|
93
|
+
/** Codepoint order, not `localeCompare`: attribute order must not depend on the machine's locale. */
|
|
94
|
+
const byCodepoint = (left, right) => (left < right ? -1 : left > right ? 1 : 0);
|
|
95
|
+
const orderAttributes = (body) => body.replace(TAG, (match, close, tag, attrs) => {
|
|
96
|
+
if (!attrs.trim())
|
|
97
|
+
return `<${close}${tag}>`;
|
|
98
|
+
const selfClosing = /\/\s*$/.test(attrs);
|
|
99
|
+
const pairs = [];
|
|
100
|
+
for (const found of attrs.matchAll(ATTRIBUTE))
|
|
101
|
+
pairs.push(found[2] ? `${found[1]}=${found[2]}` : found[1]);
|
|
102
|
+
pairs.sort(byCodepoint);
|
|
103
|
+
return `<${close}${tag} ${pairs.join(' ')}${selfClosing ? '/' : ''}>`;
|
|
104
|
+
});
|
|
105
|
+
const collapseWhitespace = (text) => text
|
|
106
|
+
.split('\n')
|
|
107
|
+
.map((line) => line.replace(/[^\S\n]+/g, ' ').trim())
|
|
108
|
+
.filter((line) => line.length > 0)
|
|
109
|
+
.join('\n');
|
|
110
|
+
/** Markup segment: URL noise and cache-busting go, whitespace collapses, attributes order (HTML only). */
|
|
111
|
+
const normalizeSegment = (text, { origin, order }) => {
|
|
112
|
+
let out = origin ? relativizeOrigin(text, origin) : text;
|
|
113
|
+
out = tidyQuery(out.replace(CACHE_BUST, '$1'));
|
|
114
|
+
out = collapseWhitespace(out);
|
|
115
|
+
return order ? orderAttributes(out) : out;
|
|
116
|
+
};
|
|
117
|
+
// Raw-text elements: attribute reordering inside a script body would corrupt code,
|
|
118
|
+
// and whitespace inside pre/textarea is content. Only script/style bodies get the
|
|
119
|
+
// whitespace collapse (the two engines render the same templates, so a difference
|
|
120
|
+
// in inline JS string whitespace is not what parity is about).
|
|
121
|
+
const RAW_ELEMENT = /<(script|style|pre|textarea)\b[^>]*>[\s\S]*?<\/\1\s*>/gi;
|
|
122
|
+
const VERBATIM = new Set(['pre', 'textarea']);
|
|
123
|
+
const normalizeRawElement = (match, tag, { origin, order }) => match.replace(new RegExp(`(<${tag}\\b[^>]*>)([\\s\\S]*)(</${tag}\\s*>)`, 'i'), (whole, open, body, close) => `${normalizeSegment(open, { origin, order })}\n${collapseWhitespace(body)}\n${close}`);
|
|
124
|
+
/**
|
|
125
|
+
* Normalizes one rendered body for the diff (plan:50 Q7.2): absolute URLs of the
|
|
126
|
+
* served origin become relative, cache-busting suffixes go, attributes are
|
|
127
|
+
* ordered, whitespace is collapsed line-wise with blank lines dropped.
|
|
128
|
+
*
|
|
129
|
+
* Only markup (HTML/XML) is URL-normalized: robots.txt is content, and a
|
|
130
|
+
* `Disallow: /a?t=1` line must survive verbatim. XML keeps attribute order —
|
|
131
|
+
* `xmlns` is not noise.
|
|
132
|
+
*/
|
|
133
|
+
export const normalizeText = (text, { origin, contentType = '' } = {}) => {
|
|
134
|
+
const base = origin ? origin.replace(/\/+$/, '') : '';
|
|
135
|
+
const type = String(contentType);
|
|
136
|
+
const markup = type === '' || /(html|xml)/i.test(type);
|
|
137
|
+
const order = /html/i.test(type);
|
|
138
|
+
let out = String(text).replace(/^\uFEFF/, '').replace(/\r\n?/g, '\n');
|
|
139
|
+
if (!markup)
|
|
140
|
+
return collapseWhitespace(out);
|
|
141
|
+
const pieces = [];
|
|
142
|
+
let cursor = 0;
|
|
143
|
+
out.replace(RAW_ELEMENT, (match, tag, offset) => {
|
|
144
|
+
pieces.push(normalizeSegment(out.slice(cursor, offset), { origin: base, order }));
|
|
145
|
+
pieces.push(VERBATIM.has(tag.toLowerCase())
|
|
146
|
+
? match
|
|
147
|
+
: normalizeRawElement(match, tag, { origin: base, order }));
|
|
148
|
+
cursor = offset + match.length;
|
|
149
|
+
return match;
|
|
150
|
+
});
|
|
151
|
+
pieces.push(normalizeSegment(out.slice(cursor), { origin: base, order }));
|
|
152
|
+
return pieces.filter((piece) => piece !== '').join('\n');
|
|
153
|
+
};
|
|
154
|
+
/** `normalizeText` for markup — the common case. */
|
|
155
|
+
export const normalizeHtml = (html, { origin } = {}) => normalizeText(html, { origin, contentType: 'text/html' });
|
|
156
|
+
/** A redirect target is content, but its origin is not: same-origin → relative. */
|
|
157
|
+
const normalizeLocation = (location, origin) => {
|
|
158
|
+
if (!location)
|
|
159
|
+
return null;
|
|
160
|
+
const base = origin.replace(/\/+$/, '');
|
|
161
|
+
return location.startsWith(base) ? location.slice(base.length) || '/' : location;
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Snapshots a fixed page set from a running engine. Redirects are recorded, not
|
|
165
|
+
* followed (`redirect: 'manual'`): a 301 whose target drifts is exactly the kind
|
|
166
|
+
* of regression this harness exists to see. A page that does not answer at all is
|
|
167
|
+
* recorded with `status: null` and its error — a failed capture must reach the
|
|
168
|
+
* report, never abort the run without a page name.
|
|
169
|
+
*/
|
|
170
|
+
export const captureSite = async ({ origin, pages = undefined, fetchImpl = fetch, timeoutMs = 30000 }) => {
|
|
171
|
+
const base = origin.replace(/\/+$/, '');
|
|
172
|
+
const set = pages ?? (await loadPageSet());
|
|
173
|
+
const captured = [];
|
|
174
|
+
for (const page of set) {
|
|
175
|
+
try {
|
|
176
|
+
const response = await fetchImpl(`${base}${page.path}`, {
|
|
177
|
+
redirect: 'manual',
|
|
178
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
179
|
+
});
|
|
180
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
181
|
+
const location = response.headers.get('location');
|
|
182
|
+
captured.push({
|
|
183
|
+
name: page.name,
|
|
184
|
+
kind: page.kind,
|
|
185
|
+
path: page.path,
|
|
186
|
+
status: response.status,
|
|
187
|
+
location: normalizeLocation(location, base),
|
|
188
|
+
error: null,
|
|
189
|
+
body: normalizeText(await response.text(), { origin: base, contentType }),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
captured.push({
|
|
194
|
+
name: page.name,
|
|
195
|
+
kind: page.kind,
|
|
196
|
+
path: page.path,
|
|
197
|
+
status: null,
|
|
198
|
+
location: null,
|
|
199
|
+
error: String(error?.message ?? error),
|
|
200
|
+
body: '',
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return { origin: base, pages: captured };
|
|
205
|
+
};
|
|
206
|
+
const splitLines = (body) => (body === '' ? [] : body.split('\n'));
|
|
207
|
+
/** First differing lines, capped — the evidence a human reads, not a full dump. */
|
|
208
|
+
const bodyDiff = (baselineBody, targetBody, { max = 3 } = {}) => {
|
|
209
|
+
const from = splitLines(baselineBody);
|
|
210
|
+
const to = splitLines(targetBody);
|
|
211
|
+
const lines = [];
|
|
212
|
+
const length = Math.max(from.length, to.length);
|
|
213
|
+
for (let index = 0; index < length && lines.length < max; index++) {
|
|
214
|
+
if (from[index] === to[index])
|
|
215
|
+
continue;
|
|
216
|
+
lines.push(`line ${index + 1}:`, ` - ${from[index] ?? '<missing>'}`, ` + ${to[index] ?? '<missing>'}`);
|
|
217
|
+
}
|
|
218
|
+
return lines;
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Compares two captures by page name. Returns mismatches only: `[]` means the
|
|
222
|
+
* render is identical. Kinds are `diff` (status, redirect target, failure or body
|
|
223
|
+
* moved), `missing` (baseline page the target did not serve) or `extra`.
|
|
224
|
+
*/
|
|
225
|
+
export const diffSnapshots = (baseline, target) => {
|
|
226
|
+
const byName = (snapshot) => new Map(snapshot.pages.map((page) => [page.name, page]));
|
|
227
|
+
const from = byName(baseline);
|
|
228
|
+
const to = byName(target);
|
|
229
|
+
const diffs = [];
|
|
230
|
+
for (const [name, left] of from) {
|
|
231
|
+
const right = to.get(name);
|
|
232
|
+
if (!right) {
|
|
233
|
+
diffs.push({ name, kind: 'missing', path: left.path, lines: [`${left.path}: not served by the target`] });
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
const lines = [];
|
|
237
|
+
if (left.status !== right.status)
|
|
238
|
+
lines.push(`status: ${left.status ?? 'failed'} → ${right.status ?? 'failed'}`);
|
|
239
|
+
if ((left.error ?? null) !== (right.error ?? null))
|
|
240
|
+
lines.push(`error: ${left.error ?? '-'} → ${right.error ?? '-'}`);
|
|
241
|
+
if (left.location !== right.location)
|
|
242
|
+
lines.push(`location: ${left.location ?? '-'} → ${right.location ?? '-'}`);
|
|
243
|
+
if (left.body !== right.body)
|
|
244
|
+
lines.push(...bodyDiff(left.body, right.body));
|
|
245
|
+
if (lines.length)
|
|
246
|
+
diffs.push({ name, kind: 'diff', path: left.path, lines });
|
|
247
|
+
}
|
|
248
|
+
for (const [name, right] of to) {
|
|
249
|
+
if (from.has(name))
|
|
250
|
+
continue;
|
|
251
|
+
diffs.push({ name, kind: 'extra', path: right.path, lines: [`${right.path}: served only by the target`] });
|
|
252
|
+
}
|
|
253
|
+
return diffs;
|
|
254
|
+
};
|
|
255
|
+
/** The report a cutover (task:3828) attaches to its window: pass or the evidence. */
|
|
256
|
+
export const formatReport = ({ baseline, target, diffs }) => {
|
|
257
|
+
const head = [`render-parity: ${baseline} → ${target}`];
|
|
258
|
+
if (!diffs.length)
|
|
259
|
+
return [...head, 'IDENTICAL: every captured page matches after normalization.'].join('\n');
|
|
260
|
+
const body = diffs.map((diff) => [`### ${diff.name} (${diff.path}) — ${diff.kind}`, ...diff.lines.map((line) => ` ${line}`)]);
|
|
261
|
+
return [...head, `${diffs.length} page(s) differ from the baseline:`, ...body.flat()].join('\n');
|
|
262
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,51 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@snolla/data",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.7",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"config": "^3.3.3",
|
|
8
|
+
"kysely": "^0.29"
|
|
9
|
+
},
|
|
10
|
+
"gitHead": "5124dc5293ec47420def6a96f80976e1ed3f998a",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc -p tsconfig.build.json",
|
|
13
|
+
"prepare": "yarn build",
|
|
14
|
+
"test": "node --test test/*.test.js",
|
|
15
|
+
"owners:audit": "node scripts/owners-audit.mjs",
|
|
16
|
+
"owners:audit:mssql": "node scripts/owners-audit.mjs --source=mssql --compare",
|
|
17
|
+
"owners:spec": "node scripts/owner-spec-check.mjs",
|
|
18
|
+
"canon:audit": "node scripts/canon-audit.mjs"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
"./audit.ts": "./dist/audit.js",
|
|
22
|
+
"./dataProvider.js": "./dist/dataProvider.js",
|
|
23
|
+
"./dataSource.js": "./dist/dataSource.js",
|
|
24
|
+
"./dbProvider.js": "./dist/dbProvider.js",
|
|
25
|
+
"./freeze.ts": "./dist/freeze.js",
|
|
26
|
+
"./guard.ts": "./dist/guard.js",
|
|
27
|
+
"./insert.ts": "./dist/insert.js",
|
|
28
|
+
"./singleMode.ts": "./dist/singleMode.js",
|
|
29
|
+
"./sqliteDialect.js": "./dist/sqliteDialect.js",
|
|
30
|
+
"./templateDefs.js": "./dist/templateDefs.js",
|
|
31
|
+
"./schema/index.ts": "./dist/schema/index.js",
|
|
32
|
+
"./schema/generate.mjs": "./dist/schema/generate.mjs",
|
|
33
|
+
"./schema/provision.mjs": "./dist/schema/provision.mjs",
|
|
34
|
+
"./schema/generated/kysely-types": "./dist/schema/generated/kysely-types.js",
|
|
35
|
+
"./test/support/dialect-stand.js": "./dist/test/support/dialect-stand.js",
|
|
36
|
+
"./package.json": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"!dist/**/*.map"
|
|
41
|
+
],
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"typescript": "^5.9.3"
|
|
44
|
+
},
|
|
45
|
+
"optionalDependencies": {
|
|
46
|
+
"mysql2": "^3.24.6",
|
|
47
|
+
"pg": "^8.23.1",
|
|
48
|
+
"tarn": "^3.1.2",
|
|
49
|
+
"tedious": "^9.2.1"
|
|
50
|
+
}
|
|
51
|
+
}
|
package/README.md
DELETED