@ogygie/generate 0.33.0 → 0.34.1
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.
|
@@ -3182,10 +3182,6 @@ function orderPlanOf(operation, schemas, resourceFields) {
|
|
|
3182
3182
|
const tuples = typeof operation.orderBy[0] === "string" ? [operation.orderBy] : operation.orderBy;
|
|
3183
3183
|
return { enumOrder: null, tuples: tuples.map(([field, direction]) => ({ field, direction })) };
|
|
3184
3184
|
}
|
|
3185
|
-
function tenantOf(plan) {
|
|
3186
|
-
if (plan.tenant === null) throw new Error("generation plan: this emitter needs a tenant column (target.tenancy column) \u2014 a target without tenant is emitted by the mssql emitters");
|
|
3187
|
-
return plan.tenant;
|
|
3188
|
-
}
|
|
3189
3185
|
function schemaNameOfModel(model, schemas, except) {
|
|
3190
3186
|
const wanted = JSON.stringify({ ...model, optional: false, nullable: model.nullable, examples: [] });
|
|
3191
3187
|
for (const [name, entry] of Object.entries(schemas)) {
|
|
@@ -4051,7 +4047,7 @@ function drizzleTableLines(table, builders, tablesByName) {
|
|
|
4051
4047
|
function drizzleViewLines(view, builders) {
|
|
4052
4048
|
for (const column of view.columns) builders.add(builderOf(column));
|
|
4053
4049
|
return [
|
|
4054
|
-
`/** READ-ONLY mapping of the view ${view.name} (hole ${view.id}, D32): the SQL lives in the migration, this table shape is what
|
|
4050
|
+
`/** READ-ONLY mapping of the view ${view.name} (hole ${view.id}, D32): the SQL lives in the migration, this table shape is what the repository's facade reads; nothing is ever written through it. */`,
|
|
4055
4051
|
`export const ${view.tsName} = pgTable(${quote(view.name)}, {`,
|
|
4056
4052
|
...view.columns.map((column) => ` ${column.key}: ${column.drizzle},`),
|
|
4057
4053
|
"});",
|
|
@@ -4061,7 +4057,7 @@ function drizzleViewLines(view, builders) {
|
|
|
4061
4057
|
function drizzleSharedLines(table, builders) {
|
|
4062
4058
|
for (const column of table.columns) builders.add(builderOf(column));
|
|
4063
4059
|
return [
|
|
4064
|
-
`/** READ-ONLY mapping of the shared table ${table.sqlName} (D60): a table of the product outside this feature, read by its aggregate holes through
|
|
4060
|
+
`/** READ-ONLY mapping of the shared table ${table.sqlName} (D60): a table of the product outside this feature, read by its aggregate holes through the repository's facade; never created nor written here. */`,
|
|
4065
4061
|
`export const ${table.tsName} = pgTable(${quote(table.sqlName)}, {`,
|
|
4066
4062
|
...table.columns.map((column) => ` ${column.key}: ${column.drizzle},`),
|
|
4067
4063
|
"});",
|
|
@@ -4114,7 +4110,7 @@ function emitDbSchema(plan) {
|
|
|
4114
4110
|
for (const table of plan.sharedTables) sections.push("", ...drizzleSharedLines(table, builders));
|
|
4115
4111
|
const needsSql = tables.some((table) => table.uniques.some((unique) => unique.where !== null));
|
|
4116
4112
|
const intent = wrap(
|
|
4117
|
-
`Drizzle tables owned by the ${plan.featureId} feature, derived from ${plan.resource.schemaName} (${plan.specPath}, section G\xE9n\xE9ration): tenant-scoped by ${
|
|
4113
|
+
`Drizzle tables owned by the ${plan.featureId} feature, derived from ${plan.resource.schemaName} (${plan.specPath}, section G\xE9n\xE9ration): ${plan.tenant === null ? "without tenant column (target.tenancy none, D33: the product is single-tenant, the repository reads whole tables through plainDb)" : `tenant-scoped by ${plan.tenant.column} (TS key \`${plan.tenant.columnKey}\`, the column tenantDb injects and filters)`}.${plan.key === null ? "" : ` The business key ${plan.key.field} is unique per tenant (${plan.key.uniqueName}), the target of every slot and reference foreign key.`}${plan.slots.length === 0 ? "" : ` Slot tables: ${plan.slots.map((slot) => slot.table.sqlName).join(", ")} (cascade with the resource row).`}${plan.references.some((reference) => reference.table !== null) ? ` Reference tables: ${plan.references.flatMap((reference) => reference.table === null ? [] : [reference.table.sqlName]).join(", ")} (a referenced row cannot be deleted).` : ""}${views.length === 0 ? "" : ` Views ${views.map((view) => view.name).join(", ")} are read-only mappings: their SQL is in the migration.`}${plan.appendOnly === null ? "" : ` The append-only key (${plan.appendOnly.key.join(", ")}) is unique among CURRENT rows (superseded_by is null).`} SQL migration: ${plan.migrationPath}.`
|
|
4118
4114
|
);
|
|
4119
4115
|
return fileOf(
|
|
4120
4116
|
tsGeneratedHeader(plan.generatorVersion),
|
|
@@ -4142,6 +4138,8 @@ function createTableStatements(table) {
|
|
|
4142
4138
|
for (const unique of table.uniques.filter((candidate) => candidate.where !== null)) {
|
|
4143
4139
|
statements.push(`create unique index ${quote(unique.name)} on ${quote(table.sqlName)} (${unique.columns.map(quote).join(", ")}) where ${unique.where ?? ""};`);
|
|
4144
4140
|
}
|
|
4141
|
+
const tenantColumn = table.columns.find((column) => column.model === null && column.key !== "id");
|
|
4142
|
+
if (tenantColumn === void 0) return statements;
|
|
4145
4143
|
statements.push(
|
|
4146
4144
|
"",
|
|
4147
4145
|
`alter table ${quote(table.sqlName)} enable row level security;`,
|
|
@@ -4160,7 +4158,7 @@ function emitMigration(plan, existingMigration = null) {
|
|
|
4160
4158
|
const bodies = viewBodiesOf(existingMigration);
|
|
4161
4159
|
const adopted = tablesOf(plan).filter((candidate) => candidate.mode === "adopted");
|
|
4162
4160
|
const intent = wrap(
|
|
4163
|
-
`${plan.featureId} feature: the ${plan.table.sqlName} table${tables.length > 1 ? ` and ${tables.slice(1).map((table) => table.sqlName).join(", ")}` : ""}, tenant-scoped by ${
|
|
4161
|
+
`${plan.featureId} feature: the ${plan.table.sqlName} table${tables.length > 1 ? ` and ${tables.slice(1).map((table) => table.sqlName).join(", ")}` : ""}, ${plan.tenant === null ? "without tenant column (target.tenancy none, D33)" : `tenant-scoped by ${plan.tenant.column}`} (derived from ${plan.resource.schemaName}, ${plan.specPath}).${adopted.length === 0 ? "" : ` ${adopted.map((table) => table.sqlName).join(", ")} ${adopted.length > 1 ? "are ADOPTED tables" : "is an ADOPTED table"} (D36): declared in the block, created by the product, altered here within the closed list only.`} ${plan.tenant === null ? "No tenant column, no row-level security: the product is single-tenant (D33)" : `Same rails as the socle: foreign key to ${plan.tenant.table}, Row-Level Security on every table (AGENTS.md \xA7Multi-tenant 3 \u2014 second rampart, tenantDb remains the first)`}${plan.appendOnly === null ? "" : ", plus the append-only motif: a partial unique index on the current rows and a DEFERRABLE superseded_by foreign key, so the old row is marked before the new one is inserted"}${views.length === 0 ? "." : `. The views ${views.map((view) => view.name).join(", ")} are HOLES (D32): their SQL stands between the @hole markers below, written by a human, kept at every regeneration; everything else in this file is generated.`}`
|
|
4164
4162
|
).map((line, index) => `-- ${index === 0 ? "@intent " : ""}${line}`);
|
|
4165
4163
|
const statements = [];
|
|
4166
4164
|
for (const table of tables) statements.push(...statements.length === 0 ? [] : [""], ...createTableStatements(table));
|
|
@@ -6898,6 +6896,9 @@ function emitBehaviorTests(plan) {
|
|
|
6898
6896
|
}
|
|
6899
6897
|
|
|
6900
6898
|
// src/emit/repository.ts
|
|
6899
|
+
function writtenTypeOf(plan, newType) {
|
|
6900
|
+
return plan.tenant === null ? newType : `Omit<${newType}, ${quote(plan.tenant.columnKey)}>`;
|
|
6901
|
+
}
|
|
6901
6902
|
function comparatorLines(plan, operation) {
|
|
6902
6903
|
const order = operation.order;
|
|
6903
6904
|
if (order === null) return [" return 0;"];
|
|
@@ -7036,7 +7037,7 @@ function insertFunctionLines2(plan, operation) {
|
|
|
7036
7037
|
const signature = signatureParts(plan);
|
|
7037
7038
|
const derivedParameter = derived.length === 0 ? "" : `, derived: Pick<${plan.resource.typeName}, ${derived.map(quote).join(" | ")}>`;
|
|
7038
7039
|
const valuesLines = [
|
|
7039
|
-
` const values:
|
|
7040
|
+
` const values: ${writtenTypeOf(plan, plan.table.newType)} = {`,
|
|
7040
7041
|
" id,",
|
|
7041
7042
|
...inputFieldsPresent.map((field) => ` ${field}: input.${field},`),
|
|
7042
7043
|
...derived.map((field) => ` ${field}: derived.${field},`),
|
|
@@ -7146,7 +7147,7 @@ function insertFunctionLines2(plan, operation) {
|
|
|
7146
7147
|
" 409,",
|
|
7147
7148
|
" );",
|
|
7148
7149
|
" }",
|
|
7149
|
-
` const marking: Partial
|
|
7150
|
+
` const marking: Partial<${writtenTypeOf(plan, plan.table.newType)}> = { supersededBy: id };`,
|
|
7150
7151
|
` await db.update(${table}).set(marking).where(eq(${table}.id, old.id));`,
|
|
7151
7152
|
" } else {",
|
|
7152
7153
|
` const [existing] = await db`,
|
|
@@ -7238,7 +7239,7 @@ function importFunctionLines(plan, operation) {
|
|
|
7238
7239
|
}
|
|
7239
7240
|
lines.push(
|
|
7240
7241
|
" for (const { row } of rows) {",
|
|
7241
|
-
` const values:
|
|
7242
|
+
` const values: ${writtenTypeOf(plan, plan.table.newType)} = {`,
|
|
7242
7243
|
" id: crypto.randomUUID(),",
|
|
7243
7244
|
...valueFields.map((field) => ` ${field}: row.${field},`),
|
|
7244
7245
|
...appendOnly === null ? [] : [" supersedes: null,", " supersededBy: null,"],
|
|
@@ -7275,7 +7276,7 @@ function updateFunctionLines2(plan, operation) {
|
|
|
7275
7276
|
`/** ${operation.id} \u2014 update by key (D28): the fields sent are written, the key never changes${plan.signed === null ? "" : ", the signature is renewed (D31)"}. */`,
|
|
7276
7277
|
`export async function update${plan.resource.typeName}ByKey(ctx: ${plan.context.typeName}, key: ${plan.resource.typeName}[${quote(plan.key.field)}], input: ${operation.inputType}${signature.parameter}): Promise<${plan.table.rowType}> {`,
|
|
7277
7278
|
` const row = await load${plan.resource.typeName}ByKey(ctx, key, ${quote(operation.notFound ?? "")});`,
|
|
7278
|
-
` const patch: Partial
|
|
7279
|
+
` const patch: Partial<${writtenTypeOf(plan, plan.table.newType)}> = {`,
|
|
7279
7280
|
...fields.map((field) => ` ...(input.${field} === undefined ? {} : { ${field}: input.${field} }),`),
|
|
7280
7281
|
...signature.values,
|
|
7281
7282
|
" };",
|
|
@@ -7312,11 +7313,11 @@ function setOrClearFunctionLines2(plan, operation) {
|
|
|
7312
7313
|
" }",
|
|
7313
7314
|
...idempotent ? [` if (existing !== undefined && existing.${slot.value} === value) return "unchanged";`] : [],
|
|
7314
7315
|
" if (existing !== undefined) {",
|
|
7315
|
-
` const patch: Partial
|
|
7316
|
+
` const patch: Partial<${writtenTypeOf(plan, slot.table.newType)}> = { ${slot.value}: value${signature.values.length === 0 ? "" : `, ${plan.signed?.by ?? ""}: signature.by, ${plan.signed?.at ?? ""}: signature.at`} };`,
|
|
7316
7317
|
` await db.update(${table}).set(patch).where(${whereExisting});`,
|
|
7317
7318
|
` return "set";`,
|
|
7318
7319
|
" }",
|
|
7319
|
-
` const values:
|
|
7320
|
+
` const values: ${writtenTypeOf(plan, slot.table.newType)} = {`,
|
|
7320
7321
|
...slot.table.hasId ? [" id: crypto.randomUUID(),"] : [],
|
|
7321
7322
|
` ${slot.parentKey}: parent.${plan.key.field},`,
|
|
7322
7323
|
` ${slot.key}: slotKey,`,
|
|
@@ -7383,7 +7384,7 @@ function referenceLines2(plan, reference) {
|
|
|
7383
7384
|
"",
|
|
7384
7385
|
`/** One ${reference.name} row pointing at a resource key \u2014 what a test arranges to prove \xAB ligne r\xE9f\xE9renc\xE9e \xBB. */`,
|
|
7385
7386
|
`export async function insert${typeName}(ctx: ${plan.context.typeName}, values: Pick<${reference.table.newType}, ${writtenColumns2.map(quote).join(" | ")}>): Promise<${reference.table.rowType}> {`,
|
|
7386
|
-
` const inserted:
|
|
7387
|
+
` const inserted: ${writtenTypeOf(plan, reference.table.newType)} = { ...values };`,
|
|
7387
7388
|
` const [row] = await tenantDb(ctx).insert(${reference.table.tsName}).values(inserted).returning();`,
|
|
7388
7389
|
" if (row === undefined) throwOgygieError(insertReturnedNothing());",
|
|
7389
7390
|
" return row;",
|
|
@@ -7411,7 +7412,7 @@ function arrangeLines2(plan, target) {
|
|
|
7411
7412
|
`export async function arrange${target.typeName}Rows(ctx: ${plan.context.typeName}, rows: readonly ${target.withId ? `Omit<${target.typeName}, "id">` : target.typeName}[]): Promise<${target.rowType}[]> {`,
|
|
7412
7413
|
` const inserted: ${target.rowType}[] = [];`,
|
|
7413
7414
|
" for (const row of rows) {",
|
|
7414
|
-
` const values:
|
|
7415
|
+
` const values: ${writtenTypeOf(plan, valuesType)} = {`,
|
|
7415
7416
|
...target.withId ? [" id: crypto.randomUUID(),"] : [],
|
|
7416
7417
|
...target.fields.filter((field) => !(target.withId && field.name === "id")).map((field) => ` ${field.name}: ${insertExpressionOf(field)},`),
|
|
7417
7418
|
" };",
|
|
@@ -7476,18 +7477,21 @@ function emitRepository(plan) {
|
|
|
7476
7477
|
if (setOrClear !== void 0) sections.push("", ...setOrClearFunctionLines2(plan, setOrClear));
|
|
7477
7478
|
if (deleteOperation !== void 0) sections.push("", ...deleteFunctionLines2(plan, deleteOperation));
|
|
7478
7479
|
if (importOperation !== void 0) sections.push("", ...importFunctionLines(plan, importOperation));
|
|
7480
|
+
const noTenant = plan.tenant === null;
|
|
7481
|
+
const handleType = noTenant ? plan.databasePort?.typeName ?? "Database" : plan.context.typeName;
|
|
7482
|
+
const finalSections = noTenant ? sections.map((line) => line.replace(/\btenantDb\(ctx\)/gu, "plainDb(db)").replace(/\bctx\b/gu, "db").replaceAll(`db: ${plan.context.typeName}`, `db: ${handleType}`)) : sections;
|
|
7479
7483
|
return fileOf(
|
|
7480
7484
|
tsGeneratedHeader(plan.generatorVersion),
|
|
7481
7485
|
intentBlock(
|
|
7482
7486
|
wrap(
|
|
7483
|
-
`Persistence of the ${plan.featureId} feature \u2014 the only file of the feature allowed to touch the database, always through tenantDb: the tenant column is injected on insert and filtered on every read, never written by hand (AGENTS.md \xA7Multi-tenant).${plan.appendOnly === null ? "" : ` The append-only motif appendOnlySupersedes on (${plan.appendOnly.key.join(", ")}): current rows per key, supersede by marking the old row BEFORE inserting the new one.`}${plan.importMotif === null ? "" : " The all-or-nothing import: one transaction or nothing."}${plan.key === null ? "" : ` The keyed writes of D28 address a row by ${plan.key.field} and answer the operation's 404 otherwise.`}${plan.unique === null ? "" : ` uniqueKey: 409 ${plan.unique.error} on a taken key.`}${plan.referenced === null ? "" : ` refuseWhenReferenced: 409 ${plan.referenced.error} while a ${plan.referenced.reference.name} row points at the row.`}${plan.signed === null ? "" : ` signedWrite: ${plan.signed.by} and ${plan.signed.at} on every write.`}${views.length === 0 ? "" : ` The views ${views.map((view) => view.name).join(", ")} are read through their read-only mappings (D32).`} Derived from ${plan.specPath}.`
|
|
7487
|
+
`Persistence of the ${plan.featureId} feature \u2014 the only file of the feature allowed to touch the database, ${noTenant ? "always through plainDb: the product is single-tenant (target.tenancy none, D33), the whole table is read and written through the one facade, never a raw query builder" : "always through tenantDb: the tenant column is injected on insert and filtered on every read, never written by hand (AGENTS.md \xA7Multi-tenant)"}.${plan.appendOnly === null ? "" : ` The append-only motif appendOnlySupersedes on (${plan.appendOnly.key.join(", ")}): current rows per key, supersede by marking the old row BEFORE inserting the new one.`}${plan.importMotif === null ? "" : " The all-or-nothing import: one transaction or nothing."}${plan.key === null ? "" : ` The keyed writes of D28 address a row by ${plan.key.field} and answer the operation's 404 otherwise.`}${plan.unique === null ? "" : ` uniqueKey: 409 ${plan.unique.error} on a taken key.`}${plan.referenced === null ? "" : ` refuseWhenReferenced: 409 ${plan.referenced.error} while a ${plan.referenced.reference.name} row points at the row.`}${plan.signed === null ? "" : ` signedWrite: ${plan.signed.by} and ${plan.signed.at} on every write.`}${views.length === 0 ? "" : ` The views ${views.map((view) => view.name).join(", ")} are read through their read-only mappings (D32).`} Derived from ${plan.specPath}.`
|
|
7484
7488
|
)
|
|
7485
7489
|
),
|
|
7486
7490
|
drizzleImports.size === 0 ? null : `import { ${[...drizzleImports].sort().join(", ")} } from "drizzle-orm";`,
|
|
7487
7491
|
'import type { Clock } from "@ogygie/core/clock";',
|
|
7488
7492
|
'import { throwOgygieError } from "@ogygie/core/errors";',
|
|
7489
|
-
'import { tenantDb } from "@ogygie/core/tenant";',
|
|
7490
|
-
`import type { ${plan.context.typeName} } from ${quote(plan.context.importPath)};`,
|
|
7493
|
+
noTenant ? 'import { plainDb } from "@ogygie/core/tenant";' : 'import { tenantDb } from "@ogygie/core/tenant";',
|
|
7494
|
+
noTenant ? `import type { ${handleType} } from ${quote(plan.databasePort?.importPath ?? "../../db.js")};` : `import type { ${plan.context.typeName} } from ${quote(plan.context.importPath)};`,
|
|
7491
7495
|
"import {",
|
|
7492
7496
|
...tableImports.map((line) => ` ${line},`),
|
|
7493
7497
|
'} from "./db.schema.gen.js";',
|
|
@@ -7522,7 +7526,7 @@ function emitRepository(plan) {
|
|
|
7522
7526
|
` suggestedFix: "Check the migration ${plan.migrationFileName} was applied to this database.",`,
|
|
7523
7527
|
" };",
|
|
7524
7528
|
"}",
|
|
7525
|
-
...
|
|
7529
|
+
...finalSections
|
|
7526
7530
|
);
|
|
7527
7531
|
}
|
|
7528
7532
|
|
|
@@ -11847,9 +11851,23 @@ async function fillLogicHoles(project, featureId, argv, out, deps) {
|
|
|
11847
11851
|
}
|
|
11848
11852
|
});
|
|
11849
11853
|
const summary = await fillFeature(inputs, fillDeps, wiring.options);
|
|
11854
|
+
for (const path of refreshHoleDocs(project.root, folder, plan, loadHolesLibrary(wiring.libraryDir))) out.log(` r\xE9\xE9crite ${path}`);
|
|
11850
11855
|
report(wiring, summary, { unit: "trou", human: "HUMAIN (todo)" });
|
|
11851
11856
|
return summary.unfilled === 0 ? 0 : 1;
|
|
11852
11857
|
}
|
|
11858
|
+
function refreshHoleDocs(projectRoot, folder, plan, library) {
|
|
11859
|
+
const changed = [];
|
|
11860
|
+
for (const hole of plan.holes) {
|
|
11861
|
+
const relativePath = `${folder}/holes/${hole.id}.gen.md`;
|
|
11862
|
+
const path = join6(projectRoot, relativePath);
|
|
11863
|
+
const content = emitHoleDoc(plan, hole, library);
|
|
11864
|
+
if (existsSync5(path) && readFileSync6(path, "utf8") === content) continue;
|
|
11865
|
+
mkdirSync3(join6(projectRoot, folder, "holes"), { recursive: true });
|
|
11866
|
+
writeFileSync3(path, content, "utf8");
|
|
11867
|
+
changed.push(relativePath);
|
|
11868
|
+
}
|
|
11869
|
+
return changed;
|
|
11870
|
+
}
|
|
11853
11871
|
function viewContextOf(projectRoot, plan, view) {
|
|
11854
11872
|
const docPath = join6(projectRoot, plan.folder, "holes", `${view.hole.id}.gen.md`);
|
|
11855
11873
|
const doc = existsSync5(docPath) ? readFileSync6(docPath, "utf8") : `# ${view.hole.id}`;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type FeaturePlan } from "../emit/plan.js";
|
|
1
2
|
import type { CustomViewPlan, ScreenPlan } from "../emit/screen-plan.js";
|
|
2
3
|
import { type HoleLibraryEntry } from "../hole-shape.js";
|
|
3
4
|
import { type FillOptions } from "../fill/fill.js";
|
|
@@ -46,6 +47,8 @@ export interface FillCommandDeps {
|
|
|
46
47
|
}
|
|
47
48
|
/** An entry recorded in the library: a new file, or the provenance of an existing one extended. */
|
|
48
49
|
export declare function recordLibraryEntry(libraryDir: string, entry: HoleLibraryEntry): "created" | "extended" | "unchanged";
|
|
50
|
+
/** Re-emits the `holes/<id>.gen.md` of a feature against the library as it stands; answers the repo-relative paths it changed. */
|
|
51
|
+
export declare function refreshHoleDocs(projectRoot: string, folder: string, plan: FeaturePlan, library: readonly HoleLibraryEntry[]): string[];
|
|
49
52
|
/** The context a view candidate is drawn on: the view's hole doc, then the product's pattern catalogue when the repo keeps one (D53). */
|
|
50
53
|
export declare function viewContextOf(projectRoot: string, plan: ScreenPlan, view: CustomViewPlan): string;
|
|
51
54
|
export declare function runFillCommand(project: GenerateProject, featureId: string | undefined, argv: readonly string[], out: CommandOutput, deps?: FillCommandDeps): Promise<number>;
|
package/dist/cli/run.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -193,7 +193,7 @@ import {
|
|
|
193
193
|
viewCandidateTextOf,
|
|
194
194
|
viewExampleTestName,
|
|
195
195
|
vocabularyOf
|
|
196
|
-
} from "./chunk-
|
|
196
|
+
} from "./chunk-VPJEACPK.js";
|
|
197
197
|
|
|
198
198
|
// src/prompt-card.ts
|
|
199
199
|
var phrase = (caseKey) => caseKey.replace(/^with:/u, "avec ").replace(/^without:/u, "sans ");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ogygie/generate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.1",
|
|
4
4
|
"description": "Ogygie generator: reads the `# Génération` block of a spec and its schemas.ts, derives everything deterministic without a model (routes, pipeline, database, factories, tests, screens, previews), fills the typed holes of logic.ts by library, draw and escalation, and draws the first schemas.ts of a new feature — judged by the gates. Sixth package of the lockstep (D55).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@ogygie/core": "0.
|
|
32
|
+
"@ogygie/core": "0.34.1",
|
|
33
33
|
"tsx": "^4.20.0",
|
|
34
34
|
"yaml": "^2.9.0",
|
|
35
35
|
"zod": "^4.0.0"
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@lingui/babel-plugin-lingui-macro": "^5.9.5",
|
|
39
39
|
"@lingui/core": "^5.9.5",
|
|
40
40
|
"@lingui/react": "^5.9.5",
|
|
41
|
-
"@ogygie/ui": "0.
|
|
41
|
+
"@ogygie/ui": "0.34.1",
|
|
42
42
|
"@starter/api": "0.1.0",
|
|
43
43
|
"@tanstack/react-query": "^5.102.2",
|
|
44
44
|
"@tanstack/react-router": "^1.170.32",
|