@supatype/cli 0.3.2 → 0.3.3
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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +163 -161
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +77 -0
- package/dist/augmentation-generator.d.ts.map +1 -1
- package/dist/augmentation-generator.js +70 -15
- package/dist/augmentation-generator.js.map +1 -1
- package/dist/cli-version-embedded.js +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +3 -3
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +29 -19
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/seed.d.ts +27 -1
- package/dist/commands/seed.d.ts.map +1 -1
- package/dist/commands/seed.js +206 -33
- package/dist/commands/seed.js.map +1 -1
- package/dist/engine-client.d.ts +1 -0
- package/dist/engine-client.d.ts.map +1 -1
- package/dist/engine-client.js +47 -2
- package/dist/engine-client.js.map +1 -1
- package/dist/engine-floor.d.ts +27 -4
- package/dist/engine-floor.d.ts.map +1 -1
- package/dist/engine-floor.js +90 -9
- package/dist/engine-floor.js.map +1 -1
- package/dist/gitignore.d.ts.map +1 -1
- package/dist/gitignore.js +7 -0
- package/dist/gitignore.js.map +1 -1
- package/dist/hooks-generator.d.ts.map +1 -1
- package/dist/hooks-generator.js +18 -3
- package/dist/hooks-generator.js.map +1 -1
- package/dist/seed-connection.d.ts +60 -0
- package/dist/seed-connection.d.ts.map +1 -0
- package/dist/seed-connection.js +90 -0
- package/dist/seed-connection.js.map +1 -0
- package/dist/seed-ir.d.ts +66 -0
- package/dist/seed-ir.d.ts.map +1 -0
- package/dist/seed-ir.js +265 -0
- package/dist/seed-ir.js.map +1 -0
- package/dist/seed-runner.d.ts +44 -0
- package/dist/seed-runner.d.ts.map +1 -0
- package/dist/seed-runner.js +83 -0
- package/dist/seed-runner.js.map +1 -0
- package/dist/seed.d.ts +345 -0
- package/dist/seed.d.ts.map +1 -1
- package/dist/seed.js +138 -0
- package/dist/seed.js.map +1 -1
- package/dist/self-host-compose.d.ts.map +1 -1
- package/dist/self-host-compose.js +14 -8
- package/dist/self-host-compose.js.map +1 -1
- package/dist/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor.js +73 -0
- package/dist/type-extractor.js.map +1 -1
- package/dist/type-generation.d.ts +29 -0
- package/dist/type-generation.d.ts.map +1 -1
- package/dist/type-generation.js +52 -0
- package/dist/type-generation.js.map +1 -1
- package/package.json +2 -2
- package/src/augmentation-generator.ts +73 -14
- package/src/cli-version-embedded.ts +1 -1
- package/src/commands/generate.ts +7 -3
- package/src/commands/init.ts +31 -21
- package/src/commands/seed.ts +294 -44
- package/src/engine-client.ts +52 -3
- package/src/engine-floor.ts +100 -9
- package/src/gitignore.ts +7 -0
- package/src/hooks-generator.ts +21 -6
- package/src/seed-connection.ts +146 -0
- package/src/seed-ir.ts +311 -0
- package/src/seed-runner.ts +109 -0
- package/src/seed.ts +408 -0
- package/src/self-host-compose.ts +14 -8
- package/src/type-extractor.ts +101 -0
- package/src/type-generation.ts +64 -0
- package/tests/access-composition.test.ts +123 -0
- package/tests/augmentation-generator.test.ts +149 -9
- package/tests/engine-floor.test.ts +93 -0
- package/tests/fixtures/seed_golden_ir.json +186 -0
- package/tests/runtime-contract.test.ts +31 -6
- package/tests/seed-connection.test.ts +158 -0
- package/tests/seed-ir.test.ts +436 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run one seed module and take the document it described.
|
|
3
|
+
*
|
|
4
|
+
* In a child process, through tsx, which is how this CLI already evaluates a project's
|
|
5
|
+
* TypeScript. Two reasons beyond consistency: a seed is the user's code and should not share
|
|
6
|
+
* a process with the tool running it, and the same route works for the standalone binary,
|
|
7
|
+
* which interprets TypeScript itself rather than resolving tsx from a `node_modules` it does
|
|
8
|
+
* not have.
|
|
9
|
+
*
|
|
10
|
+
* The document comes back through a file rather than stdout, because a seed is allowed to
|
|
11
|
+
* print. Mixing its output into the channel carrying the document would mean a `log()` call
|
|
12
|
+
* could corrupt the IR.
|
|
13
|
+
*/
|
|
14
|
+
import type { SeedConfig, SeedIr } from "./seed.js";
|
|
15
|
+
/** What a seed module turned out to be. */
|
|
16
|
+
export type Collected = {
|
|
17
|
+
shape: "collected";
|
|
18
|
+
ir: SeedIr;
|
|
19
|
+
config: SeedConfig;
|
|
20
|
+
} | {
|
|
21
|
+
/**
|
|
22
|
+
* The old contract: no default export, so importing it did the work.
|
|
23
|
+
*
|
|
24
|
+
* Every existing project is this shape and keeps working. Nothing here removes it.
|
|
25
|
+
*/
|
|
26
|
+
shape: "legacy";
|
|
27
|
+
};
|
|
28
|
+
export interface CollectOptions {
|
|
29
|
+
cwd: string;
|
|
30
|
+
/** The generated builder, for the manifest and the schema fingerprint. */
|
|
31
|
+
builderPath: string;
|
|
32
|
+
environment?: string | undefined;
|
|
33
|
+
}
|
|
34
|
+
export declare class SeedCollectionFailed extends Error {
|
|
35
|
+
readonly file: string;
|
|
36
|
+
readonly output: string;
|
|
37
|
+
constructor(file: string, output: string);
|
|
38
|
+
}
|
|
39
|
+
/** Import `file`, run its default export against a collector, and return what it described. */
|
|
40
|
+
export declare function collectSeed(file: string, options: CollectOptions): {
|
|
41
|
+
result: Collected;
|
|
42
|
+
stdout: string;
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=seed-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed-runner.d.ts","sourceRoot":"","sources":["../src/seed-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAEnD,2CAA2C;AAC3C,MAAM,MAAM,SAAS,GACjB;IACE,KAAK,EAAE,WAAW,CAAA;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,UAAU,CAAA;CACnB,GACD;IACE;;;;OAIG;IACH,KAAK,EAAE,QAAQ,CAAA;CAChB,CAAA;AAEL,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACjC;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM;gBADd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM;CAK1B;AAED,+FAA+F;AAC/F,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAcxG"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run one seed module and take the document it described.
|
|
3
|
+
*
|
|
4
|
+
* In a child process, through tsx, which is how this CLI already evaluates a project's
|
|
5
|
+
* TypeScript. Two reasons beyond consistency: a seed is the user's code and should not share
|
|
6
|
+
* a process with the tool running it, and the same route works for the standalone binary,
|
|
7
|
+
* which interprets TypeScript itself rather than resolving tsx from a `node_modules` it does
|
|
8
|
+
* not have.
|
|
9
|
+
*
|
|
10
|
+
* The document comes back through a file rather than stdout, because a seed is allowed to
|
|
11
|
+
* print. Mixing its output into the channel carrying the document would mean a `log()` call
|
|
12
|
+
* could corrupt the IR.
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
15
|
+
import { tmpdir } from "node:os";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { pathToFileURL } from "node:url";
|
|
18
|
+
import { evalTsSnippet } from "./tsx-runner.js";
|
|
19
|
+
export class SeedCollectionFailed extends Error {
|
|
20
|
+
file;
|
|
21
|
+
output;
|
|
22
|
+
constructor(file, output) {
|
|
23
|
+
super(`${file} failed while it was being read:\n${output}`);
|
|
24
|
+
this.file = file;
|
|
25
|
+
this.output = output;
|
|
26
|
+
this.name = "SeedCollectionFailed";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Import `file`, run its default export against a collector, and return what it described. */
|
|
30
|
+
export function collectSeed(file, options) {
|
|
31
|
+
const scratch = mkdtempSync(join(tmpdir(), "supatype-seed-"));
|
|
32
|
+
const outPath = join(scratch, "ir.json");
|
|
33
|
+
try {
|
|
34
|
+
const run = evalTsSnippet(snippet(file, outPath, options), { cwd: options.cwd });
|
|
35
|
+
if (run.exitCode !== 0 || !existsSync(outPath)) {
|
|
36
|
+
throw new SeedCollectionFailed(file, [run.stdout, run.stderr].filter(Boolean).join("\n").trim());
|
|
37
|
+
}
|
|
38
|
+
const result = JSON.parse(readFileSync(outPath, "utf8"));
|
|
39
|
+
return { result, stdout: run.stdout };
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The program that runs in the child.
|
|
47
|
+
*
|
|
48
|
+
* Every path is interpolated as a JSON string rather than pasted in, because a Windows path
|
|
49
|
+
* is full of backslashes and a project directory is allowed to contain a quote.
|
|
50
|
+
*/
|
|
51
|
+
function snippet(file, outPath, options) {
|
|
52
|
+
const url = (path) => JSON.stringify(pathToFileURL(path).href);
|
|
53
|
+
return `
|
|
54
|
+
import { writeFileSync } from "node:fs"
|
|
55
|
+
import { SeedCollector } from "./seed-ir.js"
|
|
56
|
+
import { expr } from "./seed.js"
|
|
57
|
+
|
|
58
|
+
const builder = await import(${url(options.builderPath)})
|
|
59
|
+
const module = await import(${url(file)})
|
|
60
|
+
|
|
61
|
+
if (typeof module.default !== "function") {
|
|
62
|
+
// Importing it is what ran it, which is the old contract working exactly as it did.
|
|
63
|
+
writeFileSync(${JSON.stringify(outPath)}, JSON.stringify({ shape: "legacy" }))
|
|
64
|
+
} else {
|
|
65
|
+
const collector = new SeedCollector(builder.schemaFingerprint, builder.seedModels)
|
|
66
|
+
await module.default({
|
|
67
|
+
db: collector.db(),
|
|
68
|
+
expr,
|
|
69
|
+
log: (message) => { console.log(message) },
|
|
70
|
+
environment: ${options.environment === undefined ? "undefined" : JSON.stringify(options.environment)},
|
|
71
|
+
})
|
|
72
|
+
writeFileSync(
|
|
73
|
+
${JSON.stringify(outPath)},
|
|
74
|
+
JSON.stringify({
|
|
75
|
+
shape: "collected",
|
|
76
|
+
ir: collector.finish().ir,
|
|
77
|
+
config: module.config ?? {},
|
|
78
|
+
}),
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=seed-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed-runner.js","sourceRoot":"","sources":["../src/seed-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AA0B/C,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAElC;IACA;IAFX,YACW,IAAY,EACZ,MAAc;QAEvB,KAAK,CAAC,GAAG,IAAI,qCAAqC,MAAM,EAAE,CAAC,CAAA;QAHlD,SAAI,GAAJ,IAAI,CAAQ;QACZ,WAAM,GAAN,MAAM,CAAQ;QAGvB,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAA;IACpC,CAAC;CACF;AAED,+FAA+F;AAC/F,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,OAAuB;IAC/D,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAA;IAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;IAExC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;QAChF,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,oBAAoB,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QAClG,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAc,CAAA;QACrE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAA;IACvC,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACnD,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,OAAO,CAAC,IAAY,EAAE,OAAe,EAAE,OAAuB;IACrE,MAAM,GAAG,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAA;IAC9E,OAAO;;;;;+BAKsB,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC;8BACzB,GAAG,CAAC,IAAI,CAAC;;;;kBAIrB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;;mBAOtB,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC;;;MAGlG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;;;;;;;;CAQ5B,CAAA;AACD,CAAC"}
|
package/dist/seed.d.ts
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a project's seed file imports.
|
|
3
|
+
*
|
|
4
|
+
* Two contracts live here. `sql()` is the old one: the author opens a connection, writes
|
|
5
|
+
* statements and closes it. It is unchanged and still supported, because every existing
|
|
6
|
+
* project uses it.
|
|
7
|
+
*
|
|
8
|
+
* The rest is the new one. A seed exports a function, the runner hands it a `db` typed from
|
|
9
|
+
* the project's schema, and the calls it makes are **collected, not executed**: they become
|
|
10
|
+
* a seed IR document that the engine validates, orders, batches and runs in one
|
|
11
|
+
* transaction.
|
|
12
|
+
*
|
|
13
|
+
* **Nothing here connects to a database, and nothing here builds SQL.** That is the point of
|
|
14
|
+
* the split: the hard parts, ordering a foreign-key graph, batching, mapping a Postgres
|
|
15
|
+
* error back to the schema, are written once in the engine rather than once per language.
|
|
16
|
+
* This file is the part that has to exist per language, and it is deliberately small enough
|
|
17
|
+
* to be worth writing seven times.
|
|
18
|
+
*/
|
|
1
19
|
import pg from "pg";
|
|
2
20
|
export interface SeedSql {
|
|
3
21
|
(strings: TemplateStringsArray, ...values: unknown[]): Promise<pg.QueryResult>;
|
|
@@ -5,4 +23,331 @@ export interface SeedSql {
|
|
|
5
23
|
}
|
|
6
24
|
/** Lightweight tagged-template SQL helper for project `seed.ts` scripts. */
|
|
7
25
|
export declare function sql(connectionString: string): SeedSql;
|
|
26
|
+
/**
|
|
27
|
+
* A value the database computes, rather than one the seed hardcodes.
|
|
28
|
+
*
|
|
29
|
+
* The same operand set the schema's access rules use, serialised the same way. Not a second
|
|
30
|
+
* vocabulary: forking one for seeds would need a second validator and a second SQL
|
|
31
|
+
* renderer, and would re-litigate decisions the engine has already made and documented.
|
|
32
|
+
*/
|
|
33
|
+
export type Operand<C extends string = string> = {
|
|
34
|
+
kind: "literal";
|
|
35
|
+
value: LiteralValue;
|
|
36
|
+
} | {
|
|
37
|
+
kind: "column";
|
|
38
|
+
name: C;
|
|
39
|
+
} | {
|
|
40
|
+
kind: "now";
|
|
41
|
+
} | {
|
|
42
|
+
kind: "startOf";
|
|
43
|
+
unit: TruncUnit;
|
|
44
|
+
} | {
|
|
45
|
+
kind: "ago";
|
|
46
|
+
amount: number;
|
|
47
|
+
unit: TimeUnit;
|
|
48
|
+
} | {
|
|
49
|
+
kind: "fromNow";
|
|
50
|
+
amount: number;
|
|
51
|
+
unit: TimeUnit;
|
|
52
|
+
} | {
|
|
53
|
+
kind: "after";
|
|
54
|
+
base: Operand<C>;
|
|
55
|
+
interval: IntervalSpec;
|
|
56
|
+
} | {
|
|
57
|
+
kind: "before";
|
|
58
|
+
base: Operand<C>;
|
|
59
|
+
interval: IntervalSpec;
|
|
60
|
+
};
|
|
61
|
+
export type LiteralValue = string | number | boolean;
|
|
62
|
+
export type TruncUnit = "day" | "week" | "month" | "year";
|
|
63
|
+
export type TimeUnit = "seconds" | "minutes" | "hours" | "days" | "weeks" | "months" | "years";
|
|
64
|
+
/**
|
|
65
|
+
* A span of time, in any combination of units.
|
|
66
|
+
*
|
|
67
|
+
* Multi-unit because a fixture calendar wants "thirty days from now at 09:00", which a
|
|
68
|
+
* single `{ amount, unit }` cannot say. Components are non-negative: the direction lives in
|
|
69
|
+
* the operand's name, so that `ago` reads as itself rather than as a double negative.
|
|
70
|
+
*/
|
|
71
|
+
export interface IntervalSpec {
|
|
72
|
+
years?: number;
|
|
73
|
+
months?: number;
|
|
74
|
+
weeks?: number;
|
|
75
|
+
days?: number;
|
|
76
|
+
hours?: number;
|
|
77
|
+
minutes?: number;
|
|
78
|
+
seconds?: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A time the database evaluates.
|
|
82
|
+
*
|
|
83
|
+
* Its own type so a generated builder can accept it on date-like columns and nowhere else:
|
|
84
|
+
* `expr.now()` assigned to a title does not compile.
|
|
85
|
+
*/
|
|
86
|
+
export type TimeExpr = Extract<Operand, {
|
|
87
|
+
kind: "now" | "startOf" | "ago" | "fromNow" | "after" | "before";
|
|
88
|
+
}>;
|
|
89
|
+
/**
|
|
90
|
+
* The column's own default.
|
|
91
|
+
*
|
|
92
|
+
* Distinct from leaving the field out. Omission means "do not write this column", which on
|
|
93
|
+
* the update half of an upsert keeps the existing value; this means "put it back to the
|
|
94
|
+
* default". Both are wanted and only one can be spelled by absence.
|
|
95
|
+
*/
|
|
96
|
+
export interface DefaultExpr {
|
|
97
|
+
readonly $default: true;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Values the database computes.
|
|
101
|
+
*
|
|
102
|
+
* Deliberately database-side rather than computed here. A client-computed `daysFromNow(30)`
|
|
103
|
+
* produces a different instant on every run, so a builder emitting it could never reproduce
|
|
104
|
+
* a checked-in fixture; and one IR applied to several environments at different times would
|
|
105
|
+
* give every one of them the same hardcoded instant, which for a fixture calendar is never
|
|
106
|
+
* what people mean.
|
|
107
|
+
*/
|
|
108
|
+
export declare const expr: {
|
|
109
|
+
/** `now()`, optionally shifted forward. */
|
|
110
|
+
readonly now: (after?: IntervalSpec) => TimeExpr;
|
|
111
|
+
/** `now()` shifted back. */
|
|
112
|
+
readonly ago: (before: IntervalSpec) => TimeExpr;
|
|
113
|
+
/** The start of the current day, week, month or year, optionally shifted forward. */
|
|
114
|
+
readonly startOf: (unit: TruncUnit, after?: IntervalSpec) => TimeExpr;
|
|
115
|
+
/** The start of a period, shifted back. */
|
|
116
|
+
readonly startOfBefore: (unit: TruncUnit, amount: IntervalSpec) => TimeExpr;
|
|
117
|
+
/** The column's own default. */
|
|
118
|
+
readonly default: () => DefaultExpr;
|
|
119
|
+
};
|
|
120
|
+
export type CompareOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "like";
|
|
121
|
+
/**
|
|
122
|
+
* A condition on rows, in the schema's own rule language.
|
|
123
|
+
*
|
|
124
|
+
* The engine already parses, validates and compiles this tree for every RLS policy it
|
|
125
|
+
* writes, so a seed condition is that tree scoped to a model rather than anything new. A
|
|
126
|
+
* person who has written `Eq<"status", Literal<"published">>` in their schema already knows
|
|
127
|
+
* this language.
|
|
128
|
+
*/
|
|
129
|
+
export type Predicate<C extends string = string> = {
|
|
130
|
+
type: "compare";
|
|
131
|
+
left: Operand<C>;
|
|
132
|
+
op: CompareOp;
|
|
133
|
+
right: Operand<C>;
|
|
134
|
+
} | {
|
|
135
|
+
type: "any";
|
|
136
|
+
rules: Predicate<C>[];
|
|
137
|
+
} | {
|
|
138
|
+
type: "all";
|
|
139
|
+
rules: Predicate<C>[];
|
|
140
|
+
} | {
|
|
141
|
+
type: "not";
|
|
142
|
+
rule: Predicate<C>;
|
|
143
|
+
} | {
|
|
144
|
+
type: "nullCheck";
|
|
145
|
+
operand: Operand<C>;
|
|
146
|
+
isNull: boolean;
|
|
147
|
+
} | {
|
|
148
|
+
type: "in";
|
|
149
|
+
column: C;
|
|
150
|
+
source: {
|
|
151
|
+
kind: "literal";
|
|
152
|
+
values: LiteralValue[];
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
export declare const eq: <C extends string>(column: C, value: LiteralValue) => Predicate<C>;
|
|
156
|
+
export declare const neq: <C extends string>(column: C, value: LiteralValue) => Predicate<C>;
|
|
157
|
+
export declare const gt: <C extends string>(column: C, value: LiteralValue) => Predicate<C>;
|
|
158
|
+
export declare const gte: <C extends string>(column: C, value: LiteralValue) => Predicate<C>;
|
|
159
|
+
export declare const lt: <C extends string>(column: C, value: LiteralValue) => Predicate<C>;
|
|
160
|
+
export declare const lte: <C extends string>(column: C, value: LiteralValue) => Predicate<C>;
|
|
161
|
+
export declare const like: <C extends string>(column: C, pattern: string) => Predicate<C>;
|
|
162
|
+
export declare const isNull: <C extends string>(column: C) => Predicate<C>;
|
|
163
|
+
export declare const notNull: <C extends string>(column: C) => Predicate<C>;
|
|
164
|
+
/** Every rule must hold. */
|
|
165
|
+
export declare const and: <C extends string>(...rules: Predicate<C>[]) => Predicate<C>;
|
|
166
|
+
/** Any one rule holding is enough. */
|
|
167
|
+
export declare const or: <C extends string>(...rules: Predicate<C>[]) => Predicate<C>;
|
|
168
|
+
export declare const not: <C extends string>(rule: Predicate<C>) => Predicate<C>;
|
|
169
|
+
/**
|
|
170
|
+
* The column's value is one of these.
|
|
171
|
+
*
|
|
172
|
+
* `oneOf` rather than `in`, which is a reserved word and cannot be an identifier.
|
|
173
|
+
*/
|
|
174
|
+
export declare const oneOf: <C extends string>(column: C, values: readonly LiteralValue[]) => Predicate<C>;
|
|
175
|
+
/** A value produced by an earlier operation in the same document. */
|
|
176
|
+
export interface RefValue {
|
|
177
|
+
readonly $ref: string;
|
|
178
|
+
}
|
|
179
|
+
/** An exact decimal, kept as text because JSON has no decimal type. */
|
|
180
|
+
export interface NumericValue {
|
|
181
|
+
readonly $numeric: string;
|
|
182
|
+
}
|
|
183
|
+
export type SeedValue = string | number | boolean | null | readonly SeedValue[] | RefValue | NumericValue | DefaultExpr | Operand | {
|
|
184
|
+
readonly [key: string]: SeedValue | undefined;
|
|
185
|
+
};
|
|
186
|
+
export type SeedData = Record<string, SeedValue>;
|
|
187
|
+
export type SeedOperation = {
|
|
188
|
+
op: "create";
|
|
189
|
+
model: string;
|
|
190
|
+
id?: string;
|
|
191
|
+
data: SeedData;
|
|
192
|
+
} | {
|
|
193
|
+
op: "createMany";
|
|
194
|
+
model: string;
|
|
195
|
+
rows: SeedData[];
|
|
196
|
+
} | {
|
|
197
|
+
op: "upsert";
|
|
198
|
+
model: string;
|
|
199
|
+
id?: string;
|
|
200
|
+
where: SeedData;
|
|
201
|
+
data: SeedData;
|
|
202
|
+
} | {
|
|
203
|
+
op: "sql";
|
|
204
|
+
text: string;
|
|
205
|
+
params?: SeedValue[];
|
|
206
|
+
} | {
|
|
207
|
+
op: "group";
|
|
208
|
+
if?: SeedCondition;
|
|
209
|
+
operations: SeedOperation[];
|
|
210
|
+
};
|
|
211
|
+
export type SeedCondition = {
|
|
212
|
+
kind: "exists";
|
|
213
|
+
model: string;
|
|
214
|
+
where?: Predicate;
|
|
215
|
+
} | {
|
|
216
|
+
kind: "notExists";
|
|
217
|
+
model: string;
|
|
218
|
+
where?: Predicate;
|
|
219
|
+
} | {
|
|
220
|
+
kind: "environment";
|
|
221
|
+
name: string;
|
|
222
|
+
};
|
|
223
|
+
/** One seed document, as the engine reads it. */
|
|
224
|
+
export interface SeedIr {
|
|
225
|
+
irVersion: 1;
|
|
226
|
+
schemaFingerprint: string;
|
|
227
|
+
operations: SeedOperation[];
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* What the runtime needs to know about a model and cannot tell from a value.
|
|
231
|
+
*
|
|
232
|
+
* Written by the generator, read by the collector. Three facts, each of which changes how a
|
|
233
|
+
* value is encoded and none of which is visible at runtime: which columns are exact
|
|
234
|
+
* decimals, which hold a time, and which fields are relations to what.
|
|
235
|
+
*/
|
|
236
|
+
export interface ModelManifest {
|
|
237
|
+
model: string;
|
|
238
|
+
table: string;
|
|
239
|
+
/** Columns where a number would lose precision, so the value travels as an exact decimal. */
|
|
240
|
+
numeric: readonly string[];
|
|
241
|
+
/** Columns that hold an instant, so a `Date` is rendered as one. */
|
|
242
|
+
temporal: readonly string[];
|
|
243
|
+
relations: Readonly<Record<string, {
|
|
244
|
+
kind: RelationKind;
|
|
245
|
+
target: string;
|
|
246
|
+
}>>;
|
|
247
|
+
}
|
|
248
|
+
export type RelationKind = "belongsTo" | "hasOne" | "hasMany" | "manyToMany";
|
|
249
|
+
/** What a model exposes on `db`. */
|
|
250
|
+
export interface ModelApi<TCreate, TWhere, TRef> {
|
|
251
|
+
/** Insert one row, and hand back something later operations can point at. */
|
|
252
|
+
create(data: TCreate, options?: {
|
|
253
|
+
id?: string;
|
|
254
|
+
}): TRef;
|
|
255
|
+
/**
|
|
256
|
+
* Insert many rows of one model in one statement.
|
|
257
|
+
*
|
|
258
|
+
* Not sugar for repeated `create`: a per-row API is how a seed of a few thousand rows
|
|
259
|
+
* becomes a few thousand round trips.
|
|
260
|
+
*/
|
|
261
|
+
createMany(rows: readonly TCreate[]): void;
|
|
262
|
+
/**
|
|
263
|
+
* Insert, or update the row the `where` columns already identify.
|
|
264
|
+
*
|
|
265
|
+
* The primary operation for a seed, because seeds get re-run and idempotency is the thing
|
|
266
|
+
* every hand-written one gets wrong.
|
|
267
|
+
*/
|
|
268
|
+
upsert(args: {
|
|
269
|
+
where: TWhere;
|
|
270
|
+
data: TCreate;
|
|
271
|
+
id?: string;
|
|
272
|
+
}): TRef;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Filled in by the generated builder, through declaration merging.
|
|
276
|
+
*
|
|
277
|
+
* Empty here so the runtime compiles on its own, and so a project that has not run
|
|
278
|
+
* `supatype generate` yet gets a loosely typed `db` rather than a module that does not
|
|
279
|
+
* resolve.
|
|
280
|
+
*/
|
|
281
|
+
export interface SupatypeSeedRegistry {
|
|
282
|
+
/** Never set. Present so the interface is not empty, which some lint rules refuse. */
|
|
283
|
+
readonly __generated?: never;
|
|
284
|
+
}
|
|
285
|
+
type FallbackModel = ModelApi<SeedData, SeedData, Record<string, RefValue>>;
|
|
286
|
+
type RegisteredModels = SupatypeSeedRegistry extends {
|
|
287
|
+
models: infer M;
|
|
288
|
+
} ? M : Record<string, FallbackModel>;
|
|
289
|
+
type RegisteredCondition = SupatypeSeedRegistry extends {
|
|
290
|
+
condition: infer C;
|
|
291
|
+
} ? C : SeedConditionInput;
|
|
292
|
+
/** The condition surface, before a generated builder narrows it to this schema's models. */
|
|
293
|
+
export type SeedConditionInput = {
|
|
294
|
+
exists: {
|
|
295
|
+
model: string;
|
|
296
|
+
where?: Predicate;
|
|
297
|
+
};
|
|
298
|
+
} | {
|
|
299
|
+
notExists: {
|
|
300
|
+
model: string;
|
|
301
|
+
where?: Predicate;
|
|
302
|
+
};
|
|
303
|
+
} | {
|
|
304
|
+
environment: string;
|
|
305
|
+
};
|
|
306
|
+
export type SeedDb = RegisteredModels & {
|
|
307
|
+
/**
|
|
308
|
+
* Run a block only when the database says so.
|
|
309
|
+
*
|
|
310
|
+
* Plain `if` already works for anything decided from the program's own inputs, and should
|
|
311
|
+
* be preferred. This is for the one thing plain `if` cannot do: branch on database state,
|
|
312
|
+
* which the builder cannot read because it never connects. The condition travels in the
|
|
313
|
+
* IR and the engine evaluates it at this position, inside the transaction.
|
|
314
|
+
*/
|
|
315
|
+
$if(condition: RegisteredCondition, body: () => void): void;
|
|
316
|
+
/**
|
|
317
|
+
* A raw statement, in the same transaction and the same order as everything else.
|
|
318
|
+
*
|
|
319
|
+
* Inside the IR rather than offered as a side channel, so a seed that mixes typed
|
|
320
|
+
* operations and raw SQL still runs as one thing instead of the author opening a second
|
|
321
|
+
* connection the engine knows nothing about.
|
|
322
|
+
*/
|
|
323
|
+
$sql(text: string, params?: readonly SeedValue[]): void;
|
|
324
|
+
};
|
|
325
|
+
/** What the runner hands a seed's default export. */
|
|
326
|
+
export interface SeedContext {
|
|
327
|
+
db: SeedDb;
|
|
328
|
+
expr: typeof expr;
|
|
329
|
+
/** Print a line, through the runner's own output rather than straight to stdout. */
|
|
330
|
+
log: (message: string) => void;
|
|
331
|
+
/** The environment this run targets, when the runner was told one. */
|
|
332
|
+
environment?: string | undefined;
|
|
333
|
+
}
|
|
334
|
+
/** What a seed file may ask of the runner. */
|
|
335
|
+
export interface SeedConfig {
|
|
336
|
+
/** Run this document in a transaction. Default true, and rarely worth changing. */
|
|
337
|
+
transaction?: boolean;
|
|
338
|
+
/**
|
|
339
|
+
* Apply this document at most once per environment.
|
|
340
|
+
*
|
|
341
|
+
* For a genuine one-time backfill rather than a fixture. Off by default, because seeds
|
|
342
|
+
* are idempotent upserts by design and skipping one because it ran before would turn
|
|
343
|
+
* every seed file into a one-shot migration.
|
|
344
|
+
*/
|
|
345
|
+
runOnce?: boolean;
|
|
346
|
+
}
|
|
347
|
+
/** The shape a seed module exports. */
|
|
348
|
+
export interface SeedModule {
|
|
349
|
+
default?: (context: SeedContext) => void | Promise<void>;
|
|
350
|
+
config?: SeedConfig;
|
|
351
|
+
}
|
|
352
|
+
export {};
|
|
8
353
|
//# sourceMappingURL=seed.d.ts.map
|
package/dist/seed.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,MAAM,WAAW,OAAO;IACtB,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC,CAAA;IAC9E,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACrB;AAED,4EAA4E;AAC5E,wBAAgB,GAAG,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAkCrD"}
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"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"}
|
package/dist/seed.js
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a project's seed file imports.
|
|
3
|
+
*
|
|
4
|
+
* Two contracts live here. `sql()` is the old one: the author opens a connection, writes
|
|
5
|
+
* statements and closes it. It is unchanged and still supported, because every existing
|
|
6
|
+
* project uses it.
|
|
7
|
+
*
|
|
8
|
+
* The rest is the new one. A seed exports a function, the runner hands it a `db` typed from
|
|
9
|
+
* the project's schema, and the calls it makes are **collected, not executed**: they become
|
|
10
|
+
* a seed IR document that the engine validates, orders, batches and runs in one
|
|
11
|
+
* transaction.
|
|
12
|
+
*
|
|
13
|
+
* **Nothing here connects to a database, and nothing here builds SQL.** That is the point of
|
|
14
|
+
* the split: the hard parts, ordering a foreign-key graph, batching, mapping a Postgres
|
|
15
|
+
* error back to the schema, are written once in the engine rather than once per language.
|
|
16
|
+
* This file is the part that has to exist per language, and it is deliberately small enough
|
|
17
|
+
* to be worth writing seven times.
|
|
18
|
+
*/
|
|
1
19
|
import pg from "pg";
|
|
2
20
|
/** Lightweight tagged-template SQL helper for project `seed.ts` scripts. */
|
|
3
21
|
export function sql(connectionString) {
|
|
@@ -29,4 +47,124 @@ export function sql(connectionString) {
|
|
|
29
47
|
},
|
|
30
48
|
});
|
|
31
49
|
}
|
|
50
|
+
const DEFAULT_EXPR = { $default: true };
|
|
51
|
+
const INTERVAL_UNITS = [
|
|
52
|
+
"years",
|
|
53
|
+
"months",
|
|
54
|
+
"weeks",
|
|
55
|
+
"days",
|
|
56
|
+
"hours",
|
|
57
|
+
"minutes",
|
|
58
|
+
"seconds",
|
|
59
|
+
];
|
|
60
|
+
/**
|
|
61
|
+
* Drop the units nobody asked for, so two equal intervals serialise the same way.
|
|
62
|
+
*
|
|
63
|
+
* A negative or fractional component is refused rather than carried. The engine's interval
|
|
64
|
+
* components are whole and unsigned, so one that is not fails to read as an operand, falls
|
|
65
|
+
* through to being a plain value, and reaches the database as JSON text in a date column.
|
|
66
|
+
* That surfaced as `invalid input syntax for type timestamp with time zone`, naming neither
|
|
67
|
+
* the field nor the real mistake. Here it names both, at the call that made it.
|
|
68
|
+
*/
|
|
69
|
+
function interval(spec) {
|
|
70
|
+
const out = {};
|
|
71
|
+
for (const unit of INTERVAL_UNITS) {
|
|
72
|
+
const value = spec[unit];
|
|
73
|
+
if (value === undefined || value === 0)
|
|
74
|
+
continue;
|
|
75
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
76
|
+
throw new TypeError(`An interval's \`${unit}\` must be a whole number and not negative, and this is ${value}. ` +
|
|
77
|
+
"The direction is in the name: use `ago` or `before` to go backwards.");
|
|
78
|
+
}
|
|
79
|
+
out[unit] = value;
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
function shifted(base, spec, ahead) {
|
|
84
|
+
if (spec === undefined)
|
|
85
|
+
return base;
|
|
86
|
+
const amount = interval(spec);
|
|
87
|
+
if (Object.keys(amount).length === 0)
|
|
88
|
+
return base;
|
|
89
|
+
return ahead
|
|
90
|
+
? { kind: "after", base, interval: amount }
|
|
91
|
+
: { kind: "before", base, interval: amount };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Values the database computes.
|
|
95
|
+
*
|
|
96
|
+
* Deliberately database-side rather than computed here. A client-computed `daysFromNow(30)`
|
|
97
|
+
* produces a different instant on every run, so a builder emitting it could never reproduce
|
|
98
|
+
* a checked-in fixture; and one IR applied to several environments at different times would
|
|
99
|
+
* give every one of them the same hardcoded instant, which for a fixture calendar is never
|
|
100
|
+
* what people mean.
|
|
101
|
+
*/
|
|
102
|
+
export const expr = {
|
|
103
|
+
/** `now()`, optionally shifted forward. */
|
|
104
|
+
now(after) {
|
|
105
|
+
return shifted({ kind: "now" }, after, true);
|
|
106
|
+
},
|
|
107
|
+
/** `now()` shifted back. */
|
|
108
|
+
ago(before) {
|
|
109
|
+
return shifted({ kind: "now" }, before, false);
|
|
110
|
+
},
|
|
111
|
+
/** The start of the current day, week, month or year, optionally shifted forward. */
|
|
112
|
+
startOf(unit, after) {
|
|
113
|
+
return shifted({ kind: "startOf", unit }, after, true);
|
|
114
|
+
},
|
|
115
|
+
/** The start of a period, shifted back. */
|
|
116
|
+
startOfBefore(unit, amount) {
|
|
117
|
+
return shifted({ kind: "startOf", unit }, amount, false);
|
|
118
|
+
},
|
|
119
|
+
/** The column's own default. */
|
|
120
|
+
default() {
|
|
121
|
+
return DEFAULT_EXPR;
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
function compare(column, op, value) {
|
|
125
|
+
return {
|
|
126
|
+
type: "compare",
|
|
127
|
+
left: { kind: "column", name: column },
|
|
128
|
+
op,
|
|
129
|
+
right: { kind: "literal", value },
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export const eq = (column, value) => compare(column, "eq", value);
|
|
133
|
+
export const neq = (column, value) => compare(column, "neq", value);
|
|
134
|
+
export const gt = (column, value) => compare(column, "gt", value);
|
|
135
|
+
export const gte = (column, value) => compare(column, "gte", value);
|
|
136
|
+
export const lt = (column, value) => compare(column, "lt", value);
|
|
137
|
+
export const lte = (column, value) => compare(column, "lte", value);
|
|
138
|
+
export const like = (column, pattern) => compare(column, "like", pattern);
|
|
139
|
+
export const isNull = (column) => ({
|
|
140
|
+
type: "nullCheck",
|
|
141
|
+
operand: { kind: "column", name: column },
|
|
142
|
+
isNull: true,
|
|
143
|
+
});
|
|
144
|
+
export const notNull = (column) => ({
|
|
145
|
+
type: "nullCheck",
|
|
146
|
+
operand: { kind: "column", name: column },
|
|
147
|
+
isNull: false,
|
|
148
|
+
});
|
|
149
|
+
/** Every rule must hold. */
|
|
150
|
+
export const and = (...rules) => ({
|
|
151
|
+
type: "all",
|
|
152
|
+
rules,
|
|
153
|
+
});
|
|
154
|
+
/** Any one rule holding is enough. */
|
|
155
|
+
export const or = (...rules) => ({
|
|
156
|
+
type: "any",
|
|
157
|
+
rules,
|
|
158
|
+
});
|
|
159
|
+
export const not = (rule) => ({ type: "not", rule });
|
|
160
|
+
/**
|
|
161
|
+
* The column's value is one of these.
|
|
162
|
+
*
|
|
163
|
+
* `oneOf` rather than `in`, which is a reserved word and cannot be an identifier.
|
|
164
|
+
*/
|
|
165
|
+
export const oneOf = (column, values) => ({
|
|
166
|
+
type: "in",
|
|
167
|
+
column,
|
|
168
|
+
source: { kind: "literal", values: [...values] },
|
|
169
|
+
});
|
|
32
170
|
//# sourceMappingURL=seed.js.map
|
package/dist/seed.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAOnB,4EAA4E;AAC5E,MAAM,UAAU,GAAG,CAAC,gBAAwB;IAC1C,MAAM,MAAM,GAAG,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAA;IAClD,IAAI,SAAS,GAAG,KAAK,CAAA;IAErB,MAAM,eAAe,GAAG,KAAK,IAAmB,EAAE;QAChD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,MAAM,CAAC,OAAO,EAAE,CAAA;YACtB,SAAS,GAAG,IAAI,CAAA;QAClB,CAAC;IACH,CAAC,CAAA;IAED,MAAM,GAAG,GAAG,KAAK,EACf,OAA6B,EAC7B,GAAG,MAAiB,EACK,EAAE;QAC3B,MAAM,eAAe,EAAE,CAAA;QACvB,IAAI,IAAI,GAAG,EAAE,CAAA;QACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,CAAA;YAClB,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;gBACtB,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA;YACrB,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACnC,CAAC,CAAA;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE;QACxB,GAAG,EAAE,KAAK,IAAmB,EAAE;YAC7B,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,MAAM,CAAC,GAAG,EAAE,CAAA;gBAClB,SAAS,GAAG,KAAK,CAAA;YACnB,CAAC;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"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"}
|