@mandujs/core 0.54.12 → 0.54.13

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.
Files changed (76) hide show
  1. package/package.json +9 -1
  2. package/scripts/postinstall-lock.ts +153 -153
  3. package/src/a11y/run-audit.ts +15 -15
  4. package/src/agent/__tests__/context.test.ts +49 -1
  5. package/src/agent/context.ts +535 -535
  6. package/src/agent/index.ts +6 -6
  7. package/src/agent/plan.ts +282 -282
  8. package/src/agent/repair.ts +171 -171
  9. package/src/agent/sync.ts +200 -200
  10. package/src/agent/types.ts +8 -0
  11. package/src/agent/verify.ts +100 -2
  12. package/src/brain/doctor/analyzer.ts +7 -7
  13. package/src/bundler/__tests__/build-runner.ts +5 -4
  14. package/src/bundler/__tests__/cold-start.test.ts +60 -60
  15. package/src/bundler/__tests__/css.test.ts +20 -20
  16. package/src/bundler/analyzer.ts +15 -15
  17. package/src/bundler/build.test.ts +66 -15
  18. package/src/bundler/build.ts +165 -103
  19. package/src/bundler/css.ts +42 -42
  20. package/src/bundler/manifest-schema.ts +21 -21
  21. package/src/bundler/plugins/__tests__/block-generated-imports.test.ts +13 -13
  22. package/src/bundler/plugins/block-generated-imports.ts +13 -13
  23. package/src/bundler/types.ts +31 -31
  24. package/src/client/island.ts +79 -79
  25. package/src/config/validate.ts +1 -1
  26. package/src/contract/schema.ts +7 -0
  27. package/src/deploy/inference/context.ts +82 -82
  28. package/src/devtools/client/components/panel/islands-panel.tsx +16 -16
  29. package/src/devtools/client/components/panel/panel-container.tsx +1 -1
  30. package/src/error/formatter.ts +10 -1
  31. package/src/experimental/index.ts +10 -0
  32. package/src/filling/context.ts +17 -17
  33. package/src/filling/filling.ts +22 -1
  34. package/src/filling/index.ts +15 -1
  35. package/src/generator/generate.ts +30 -30
  36. package/src/generator/index.ts +3 -3
  37. package/src/generator/templates.ts +210 -210
  38. package/src/guard/check.ts +9 -9
  39. package/src/guard/config-guard.ts +13 -13
  40. package/src/guard/fs-routes-policy.ts +51 -51
  41. package/src/guard/index.ts +11 -11
  42. package/src/index.ts +0 -10
  43. package/src/internal/index.ts +25 -0
  44. package/src/kitchen/api/file-api.ts +11 -11
  45. package/src/report/index.ts +1 -1
  46. package/src/resource/__tests__/generator.test.ts +6 -6
  47. package/src/resource/__tests__/schema.test.ts +14 -14
  48. package/src/resource/ddl/__tests__/emit.test.ts +165 -165
  49. package/src/resource/ddl/emit.ts +146 -146
  50. package/src/resource/generator-schema.ts +11 -11
  51. package/src/resource/generators/slot.ts +72 -72
  52. package/src/resource/schema.ts +21 -21
  53. package/src/router/client-entry.test.ts +69 -33
  54. package/src/router/client-entry.ts +134 -74
  55. package/src/router/fs-routes.ts +24 -22
  56. package/src/router/fs-scanner.ts +21 -17
  57. package/src/router/fs-types.ts +8 -5
  58. package/src/runtime/__tests__/devtools-adapter.test.ts +68 -68
  59. package/src/runtime/__tests__/observability-lifecycle.test.ts +103 -103
  60. package/src/runtime/__tests__/page-render-response.test.ts +103 -103
  61. package/src/runtime/__tests__/request-middleware.test.ts +70 -70
  62. package/src/runtime/devtools-adapter.ts +68 -68
  63. package/src/runtime/escape.ts +34 -34
  64. package/src/runtime/image-feature.ts +15 -0
  65. package/src/runtime/observability-lifecycle.ts +290 -290
  66. package/src/runtime/page-render-response.ts +106 -106
  67. package/src/runtime/rate-limit.ts +231 -0
  68. package/src/runtime/request-middleware.ts +31 -31
  69. package/src/runtime/scheduler-lifecycle.ts +64 -0
  70. package/src/runtime/server.ts +27 -295
  71. package/src/runtime/ssr.ts +59 -59
  72. package/src/runtime/static-files.ts +289 -289
  73. package/src/runtime/streaming-ssr.ts +22 -22
  74. package/src/spec/schema.ts +4 -3
  75. package/src/watcher/__tests__/watcher.test.ts +59 -59
  76. package/src/watcher/watcher.ts +61 -61
package/src/index.ts CHANGED
@@ -22,34 +22,24 @@ export const __MANDU_CORE_VERSION__: string = (() => {
22
22
  })();
23
23
 
24
24
  export * from "./spec";
25
- export * from "./agent";
26
25
  export * from "./runtime";
27
- export * from "./generator";
28
26
  export * from "./guard";
29
27
  export * from "./report";
30
28
  export * from "./filling";
31
- export * from "./change";
32
29
  export * from "./errors";
33
30
  export * from "./logging";
34
31
  export * from "./slot";
35
- export * from "./bundler";
36
32
  export * from "./contract";
37
33
  export * from "./openapi";
38
- export * from "./brain";
39
- export * from "./watcher";
40
34
  export * from "./router";
41
35
  export * from "./config";
42
- export * from "./lockfile";
43
36
  export * from "./utils";
44
37
  export * from "./seo";
45
38
  export * from "./island";
46
39
  export * from "./intent";
47
- export * from "./devtools";
48
- export * from "./paths";
49
40
  export * from "./observability";
50
41
  export * from "./resource";
51
42
  export * from "./types";
52
- export * from "./kitchen";
53
43
  export { runHook } from "./plugins";
54
44
  export type { ManduPlugin, ManduHooks } from "./plugins";
55
45
 
@@ -0,0 +1,25 @@
1
+ export * as bundler from "../bundler";
2
+ export * as change from "../change";
3
+ export * as generator from "../generator";
4
+ export * as lockfile from "../lockfile";
5
+ export * as paths from "../paths";
6
+ export * as report from "../report";
7
+ export * as spec from "../spec";
8
+ export * as utils from "../utils";
9
+ export * as watcher from "../watcher";
10
+
11
+ export * as runtimeCache from "../runtime/cache";
12
+ export * as runtimeRouter from "../runtime/router";
13
+ export * as runtimeServer from "../runtime/server";
14
+ export * as runtimeFastRefreshTypes from "../runtime/fast-refresh-types";
15
+
16
+ export * as resourceDdlDiff from "../resource/ddl/diff";
17
+ export * as resourceDdlEmit from "../resource/ddl/emit";
18
+ export * as resourceDdlSnapshot from "../resource/ddl/snapshot";
19
+ export * as resourceDdlTypeMap from "../resource/ddl/type-map";
20
+ export * as resourceDdlTypes from "../resource/ddl/types";
21
+ export * as resourceGeneratorRepo from "../resource/generator-repo";
22
+
23
+ export * as pluginRunner from "../plugins/runner";
24
+ export * as devErrorOverlay from "../dev-error-overlay";
25
+ export * as tsgolintBridge from "../guard/tsgolint-bridge";
@@ -229,17 +229,17 @@ export class FileAPI {
229
229
  for (const line of stdout.split("\n")) {
230
230
  if (!line.trim()) continue;
231
231
 
232
- const statusCode = line.substring(0, 2);
233
- const gitFilePath = line.substring(3).trim();
234
- const filePath = this.getProjectRelativePath(gitFilePath, gitRoot);
235
- if (!filePath || filePath === ".") {
236
- continue;
237
- }
238
-
239
- changes.push({
240
- filePath,
241
- status: parseGitStatus(statusCode),
242
- });
232
+ const statusCode = line.substring(0, 2);
233
+ const gitFilePath = line.substring(3).trim();
234
+ const filePath = this.getProjectRelativePath(gitFilePath, gitRoot);
235
+ if (!filePath || filePath === ".") {
236
+ continue;
237
+ }
238
+
239
+ changes.push({
240
+ filePath,
241
+ status: parseGitStatus(statusCode),
242
+ });
243
243
  }
244
244
 
245
245
  return changes;
@@ -1 +1 @@
1
- export * from "./build";
1
+ export * from "./build";
@@ -671,12 +671,12 @@ describe("generateSchemaArtifacts — diff + migration orchestration", () => {
671
671
  const result = await computeSchemaGeneration(resources, rootDir);
672
672
  expect(result.changes.length).toBe(2);
673
673
  expect(result.changes.every((c) => c.kind === "create-table")).toBe(true);
674
- expect(result.migrationFilename).not.toBeNull();
675
- expect(result.migrationSql).toContain("CREATE TABLE");
676
- expect(result.migrationSql).not.toMatch(/\bBEGIN\b/i);
677
- expect(result.migrationSql).not.toMatch(/\bCOMMIT\b/i);
678
- expect(result.desiredSchema).toContain("CREATE TABLE");
679
- expect(Object.keys(result.desiredSchemaByTable).sort()).toEqual(["products", "users"]);
674
+ expect(result.migrationFilename).not.toBeNull();
675
+ expect(result.migrationSql).toContain("CREATE TABLE");
676
+ expect(result.migrationSql).not.toMatch(/\bBEGIN\b/i);
677
+ expect(result.migrationSql).not.toMatch(/\bCOMMIT\b/i);
678
+ expect(result.desiredSchema).toContain("CREATE TABLE");
679
+ expect(Object.keys(result.desiredSchemaByTable).sort()).toEqual(["products", "users"]);
680
680
  } finally {
681
681
  await fs.rm(rootDir, { recursive: true, force: true });
682
682
  }
@@ -108,20 +108,20 @@ describe("validateResourceDefinition", () => {
108
108
  });
109
109
 
110
110
  describe("getPluralName", () => {
111
- test("should add 's' for simple pluralization", () => {
112
- const result = getPluralName(userResourceFixture);
113
- expect(result).toBe("users");
114
- });
115
-
116
- test("should use conservative English pluralization for common resource names", () => {
117
- expect(getPluralName({ ...minimalResourceFixture, name: "party" })).toBe("parties");
118
- expect(getPluralName({ ...minimalResourceFixture, name: "box" })).toBe("boxes");
119
- });
120
-
121
- test("should use custom plural name if provided", () => {
122
- const result = getPluralName(productResourceFixture);
123
- expect(result).toBe("inventory");
124
- });
111
+ test("should add 's' for simple pluralization", () => {
112
+ const result = getPluralName(userResourceFixture);
113
+ expect(result).toBe("users");
114
+ });
115
+
116
+ test("should use conservative English pluralization for common resource names", () => {
117
+ expect(getPluralName({ ...minimalResourceFixture, name: "party" })).toBe("parties");
118
+ expect(getPluralName({ ...minimalResourceFixture, name: "box" })).toBe("boxes");
119
+ });
120
+
121
+ test("should use custom plural name if provided", () => {
122
+ const result = getPluralName(productResourceFixture);
123
+ expect(result).toBe("inventory");
124
+ });
125
125
 
126
126
  test("should respect autoPlural: false", () => {
127
127
  const definition = {
@@ -415,112 +415,112 @@ describe("emitChange — add-column", () => {
415
415
  expect(emitChange(change, "mysql"))
416
416
  .toBe("ALTER TABLE `users` ADD COLUMN `age` DOUBLE;");
417
417
  });
418
- test("sqlite", () => {
419
- expect(emitChange(change, "sqlite"))
420
- .toBe('ALTER TABLE "users" ADD COLUMN "age" REAL;');
421
- });
422
-
423
- test("sqlite refuses required add-column without a non-NULL constant default (#294)", () => {
424
- const required: Change = {
425
- kind: "add-column",
426
- resourceName: "votes",
427
- field: field({ name: "created_at", type: "date" }),
428
- };
429
-
430
- expect(() => emitChange(required, "sqlite")).toThrow(
431
- /SQLite cannot add required column "created_at"/,
432
- );
433
- });
434
-
435
- test("sqlite allows required add-column when a scalar literal default is present", () => {
436
- const requiredWithDefault: Change = {
437
- kind: "add-column",
438
- resourceName: "votes",
439
- field: field({
440
- name: "created_at",
441
- type: "date",
442
- default: { kind: "literal", value: "1970-01-01T00:00:00.000Z" },
443
- }),
444
- };
445
-
446
- expect(emitChange(requiredWithDefault, "sqlite")).toBe(
447
- 'ALTER TABLE "votes" ADD COLUMN "created_at" TEXT NOT NULL DEFAULT \'1970-01-01T00:00:00.000Z\';',
448
- );
449
- });
450
-
451
- test("sqlite refuses default: now on add-column because SQLite requires a constant default", () => {
452
- const nowDefault: Change = {
453
- kind: "add-column",
454
- resourceName: "votes",
455
- field: field({
456
- name: "created_at",
457
- type: "date",
458
- nullable: true,
459
- default: { kind: "now" },
460
- }),
461
- };
462
-
463
- expect(() => emitChange(nowDefault, "sqlite")).toThrow(
464
- /CURRENT_TIMESTAMP, which SQLite rejects/,
465
- );
466
- });
467
-
468
- test("sqlite refuses UNIQUE add-column because SQLite cannot add the constraint in place", () => {
469
- const unique: Change = {
470
- kind: "add-column",
471
- resourceName: "votes",
472
- field: field({ name: "slug", type: "string", nullable: true, unique: true }),
473
- };
474
-
475
- expect(() => emitChange(unique, "sqlite")).toThrow(/cannot add UNIQUE column/);
476
- });
477
-
478
- test("sqlite refuses PRIMARY KEY add-column because SQLite cannot add the constraint in place", () => {
479
- const primary: Change = {
480
- kind: "add-column",
481
- resourceName: "votes",
482
- field: field({ name: "other_id", type: "uuid", primary: true }),
483
- };
484
-
485
- expect(() => emitChange(primary, "sqlite")).toThrow(/cannot add PRIMARY KEY column/);
486
- });
487
-
488
- test("sqlite refuses raw function defaults on add-column", () => {
489
- const rawFunction: Change = {
490
- kind: "add-column",
491
- resourceName: "votes",
492
- field: field({
493
- name: "created_at",
494
- type: "date",
495
- nullable: true,
496
- default: { kind: "sql", expr: "datetime('now')" },
497
- }),
498
- };
499
-
500
- expect(() => emitChange(rawFunction, "sqlite")).toThrow(
501
- /non-constant function defaults/,
502
- );
503
- });
504
-
505
- test("sqlite refuses raw expression defaults on add-column", () => {
506
- const rawExpression: Change = {
507
- kind: "add-column",
508
- resourceName: "votes",
509
- field: field({
510
- name: "score",
511
- type: "number",
512
- nullable: true,
513
- default: { kind: "sql", expr: "(1+2)" },
514
- }),
515
- };
516
-
517
- expect(() => emitChange(rawExpression, "sqlite")).toThrow(
518
- /only accepts literal constant defaults/,
519
- );
520
- });
521
-
522
- test("indexed:true field emits ADD COLUMN plus auto CREATE INDEX", () => {
523
- const indexed: Change = {
418
+ test("sqlite", () => {
419
+ expect(emitChange(change, "sqlite"))
420
+ .toBe('ALTER TABLE "users" ADD COLUMN "age" REAL;');
421
+ });
422
+
423
+ test("sqlite refuses required add-column without a non-NULL constant default (#294)", () => {
424
+ const required: Change = {
425
+ kind: "add-column",
426
+ resourceName: "votes",
427
+ field: field({ name: "created_at", type: "date" }),
428
+ };
429
+
430
+ expect(() => emitChange(required, "sqlite")).toThrow(
431
+ /SQLite cannot add required column "created_at"/,
432
+ );
433
+ });
434
+
435
+ test("sqlite allows required add-column when a scalar literal default is present", () => {
436
+ const requiredWithDefault: Change = {
437
+ kind: "add-column",
438
+ resourceName: "votes",
439
+ field: field({
440
+ name: "created_at",
441
+ type: "date",
442
+ default: { kind: "literal", value: "1970-01-01T00:00:00.000Z" },
443
+ }),
444
+ };
445
+
446
+ expect(emitChange(requiredWithDefault, "sqlite")).toBe(
447
+ 'ALTER TABLE "votes" ADD COLUMN "created_at" TEXT NOT NULL DEFAULT \'1970-01-01T00:00:00.000Z\';',
448
+ );
449
+ });
450
+
451
+ test("sqlite refuses default: now on add-column because SQLite requires a constant default", () => {
452
+ const nowDefault: Change = {
453
+ kind: "add-column",
454
+ resourceName: "votes",
455
+ field: field({
456
+ name: "created_at",
457
+ type: "date",
458
+ nullable: true,
459
+ default: { kind: "now" },
460
+ }),
461
+ };
462
+
463
+ expect(() => emitChange(nowDefault, "sqlite")).toThrow(
464
+ /CURRENT_TIMESTAMP, which SQLite rejects/,
465
+ );
466
+ });
467
+
468
+ test("sqlite refuses UNIQUE add-column because SQLite cannot add the constraint in place", () => {
469
+ const unique: Change = {
470
+ kind: "add-column",
471
+ resourceName: "votes",
472
+ field: field({ name: "slug", type: "string", nullable: true, unique: true }),
473
+ };
474
+
475
+ expect(() => emitChange(unique, "sqlite")).toThrow(/cannot add UNIQUE column/);
476
+ });
477
+
478
+ test("sqlite refuses PRIMARY KEY add-column because SQLite cannot add the constraint in place", () => {
479
+ const primary: Change = {
480
+ kind: "add-column",
481
+ resourceName: "votes",
482
+ field: field({ name: "other_id", type: "uuid", primary: true }),
483
+ };
484
+
485
+ expect(() => emitChange(primary, "sqlite")).toThrow(/cannot add PRIMARY KEY column/);
486
+ });
487
+
488
+ test("sqlite refuses raw function defaults on add-column", () => {
489
+ const rawFunction: Change = {
490
+ kind: "add-column",
491
+ resourceName: "votes",
492
+ field: field({
493
+ name: "created_at",
494
+ type: "date",
495
+ nullable: true,
496
+ default: { kind: "sql", expr: "datetime('now')" },
497
+ }),
498
+ };
499
+
500
+ expect(() => emitChange(rawFunction, "sqlite")).toThrow(
501
+ /non-constant function defaults/,
502
+ );
503
+ });
504
+
505
+ test("sqlite refuses raw expression defaults on add-column", () => {
506
+ const rawExpression: Change = {
507
+ kind: "add-column",
508
+ resourceName: "votes",
509
+ field: field({
510
+ name: "score",
511
+ type: "number",
512
+ nullable: true,
513
+ default: { kind: "sql", expr: "(1+2)" },
514
+ }),
515
+ };
516
+
517
+ expect(() => emitChange(rawExpression, "sqlite")).toThrow(
518
+ /only accepts literal constant defaults/,
519
+ );
520
+ });
521
+
522
+ test("indexed:true field emits ADD COLUMN plus auto CREATE INDEX", () => {
523
+ const indexed: Change = {
524
524
  kind: "add-column",
525
525
  resourceName: "users",
526
526
  field: field({ name: "role", type: "string", indexed: true }),
@@ -576,24 +576,24 @@ describe("emitChange — alter-column-type stub", () => {
576
576
  stub: true,
577
577
  };
578
578
 
579
- test("emits comment block with required TODO text", () => {
580
- for (const p of PROVIDERS) {
581
- const sql = emitChange(change, p);
582
- expect(sql).toContain("-- TODO: Mandu does not auto-generate ALTER COLUMN TYPE in v1.");
583
- expect(sql).toContain("mandu db apply");
584
- expect(sql).toContain("Column type change detected: users.age");
585
- expect(sql).toContain("from: number");
586
- expect(sql).toContain("to: string");
587
- expect(sql).toContain("mandu_manual_migration_required");
588
- }
589
- });
590
-
591
- test("includes a deliberate failing manual-migration sentinel", () => {
592
- const sql = emitChange(change, "postgres");
593
- expect(sql).toContain("SELECT mandu_manual_migration_required");
594
- expect(sql).not.toContain("SELECT 1;");
595
- });
596
- });
579
+ test("emits comment block with required TODO text", () => {
580
+ for (const p of PROVIDERS) {
581
+ const sql = emitChange(change, p);
582
+ expect(sql).toContain("-- TODO: Mandu does not auto-generate ALTER COLUMN TYPE in v1.");
583
+ expect(sql).toContain("mandu db apply");
584
+ expect(sql).toContain("Column type change detected: users.age");
585
+ expect(sql).toContain("from: number");
586
+ expect(sql).toContain("to: string");
587
+ expect(sql).toContain("mandu_manual_migration_required");
588
+ }
589
+ });
590
+
591
+ test("includes a deliberate failing manual-migration sentinel", () => {
592
+ const sql = emitChange(change, "postgres");
593
+ expect(sql).toContain("SELECT mandu_manual_migration_required");
594
+ expect(sql).not.toContain("SELECT 1;");
595
+ });
596
+ });
597
597
 
598
598
  describe("emitChange — alter-column-nullable", () => {
599
599
  test("postgres SET NOT NULL / DROP NOT NULL", () => {
@@ -611,24 +611,24 @@ describe("emitChange — alter-column-nullable", () => {
611
611
  ).toBe('ALTER TABLE "users" ALTER COLUMN "email" DROP NOT NULL;');
612
612
  });
613
613
 
614
- test("sqlite emits a stub (cannot toggle NOT NULL in place)", () => {
615
- const sql = emitChange(
616
- { kind: "alter-column-nullable", resourceName: "users", fieldName: "email", nullable: true },
617
- "sqlite",
618
- );
619
- expect(sql).toContain("TODO: SQLite cannot toggle NOT NULL in place");
620
- expect(sql).toContain("mandu_manual_migration_required");
621
- });
622
-
623
- test("mysql emits a stub (MODIFY COLUMN needs full type)", () => {
624
- const sql = emitChange(
625
- { kind: "alter-column-nullable", resourceName: "users", fieldName: "email", nullable: false },
626
- "mysql",
627
- );
628
- expect(sql).toContain("MySQL MODIFY COLUMN requires");
629
- expect(sql).toContain("mandu_manual_migration_required");
630
- });
631
- });
614
+ test("sqlite emits a stub (cannot toggle NOT NULL in place)", () => {
615
+ const sql = emitChange(
616
+ { kind: "alter-column-nullable", resourceName: "users", fieldName: "email", nullable: true },
617
+ "sqlite",
618
+ );
619
+ expect(sql).toContain("TODO: SQLite cannot toggle NOT NULL in place");
620
+ expect(sql).toContain("mandu_manual_migration_required");
621
+ });
622
+
623
+ test("mysql emits a stub (MODIFY COLUMN needs full type)", () => {
624
+ const sql = emitChange(
625
+ { kind: "alter-column-nullable", resourceName: "users", fieldName: "email", nullable: false },
626
+ "mysql",
627
+ );
628
+ expect(sql).toContain("MySQL MODIFY COLUMN requires");
629
+ expect(sql).toContain("mandu_manual_migration_required");
630
+ });
631
+ });
632
632
 
633
633
  describe("emitChange — alter-column-default", () => {
634
634
  test("postgres SET DEFAULT", () => {
@@ -652,35 +652,35 @@ describe("emitChange — alter-column-default", () => {
652
652
  expect(sql).toBe('ALTER TABLE "users" ALTER COLUMN "status" DROP DEFAULT;');
653
653
  });
654
654
 
655
- test("mysql supports SET/DROP DEFAULT directly", () => {
656
- expect(
657
- emitChange(
658
- {
655
+ test("mysql supports SET/DROP DEFAULT directly", () => {
656
+ expect(
657
+ emitChange(
658
+ {
659
659
  kind: "alter-column-default",
660
660
  resourceName: "u",
661
661
  fieldName: "f",
662
662
  default: { kind: "literal", value: 1 },
663
663
  },
664
664
  "mysql",
665
- ),
666
- ).toBe("ALTER TABLE `u` ALTER COLUMN `f` SET DEFAULT 1;");
667
- });
668
-
669
- test("sqlite emits a failing manual stub for default changes", () => {
670
- const sql = emitChange(
671
- {
672
- kind: "alter-column-default",
673
- resourceName: "users",
674
- fieldName: "status",
675
- default: { kind: "literal", value: "active" },
676
- },
677
- "sqlite",
678
- );
679
- expect(sql).toContain("TODO: SQLite cannot ALTER DEFAULT in place");
680
- expect(sql).toContain("mandu_manual_migration_required");
681
- expect(sql).not.toContain("SELECT 1;");
682
- });
683
- });
665
+ ),
666
+ ).toBe("ALTER TABLE `u` ALTER COLUMN `f` SET DEFAULT 1;");
667
+ });
668
+
669
+ test("sqlite emits a failing manual stub for default changes", () => {
670
+ const sql = emitChange(
671
+ {
672
+ kind: "alter-column-default",
673
+ resourceName: "users",
674
+ fieldName: "status",
675
+ default: { kind: "literal", value: "active" },
676
+ },
677
+ "sqlite",
678
+ );
679
+ expect(sql).toContain("TODO: SQLite cannot ALTER DEFAULT in place");
680
+ expect(sql).toContain("mandu_manual_migration_required");
681
+ expect(sql).not.toContain("SELECT 1;");
682
+ });
683
+ });
684
684
 
685
685
  describe("emitChange — indexes", () => {
686
686
  test("add-index single column, non-unique", () => {