@saasicat/cli 0.26.1 → 1.0.0-rc.0

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/index.d.ts CHANGED
@@ -497,6 +497,466 @@ declare function breaksContract(attribute: MissingBlockAttribute): boolean;
497
497
  */
498
498
  declare function checkSchema(specSchema: string, appSchema: string): SchemaCheckReport;
499
499
 
500
+ /** Marks the block this tool appends, and lets it recognise its own work. */
501
+ declare const CONSTRAINTS_MARKER = "-- saasicat:constraints";
502
+ /**
503
+ * The migration THIS run created — the one that is in `after` and not `before`.
504
+ *
505
+ * The first version asked which directory sorts last, which is the same answer
506
+ * whenever the run created one and a silently wrong one when it did not: the
507
+ * step would then edit a stranger's migration, one already applied, and break
508
+ * its checksum. Taking the difference cannot confuse the two.
509
+ *
510
+ * `<timestamp>_<name>` is required, so `migration_lock.toml` and a stray
511
+ * scratch directory are not candidates however they sort.
512
+ */
513
+ declare function migrationCreatedBy(before: readonly string[], after: readonly string[]): string | null;
514
+ /** Whether this SQL already carries a constraints block from a previous run. */
515
+ declare function hasConstraints(migrationSql: string): boolean;
516
+ /**
517
+ * The tables a constraints statement addresses.
518
+ *
519
+ * `CREATE ... INDEX ... ON <table>` and `ALTER TABLE <table>` are the two
520
+ * shapes the canonical file uses; anything else is returned as addressing
521
+ * nothing, which keeps it.
522
+ */
523
+ declare function tablesAddressedBy(statement: string): string[];
524
+ /**
525
+ * The constraints that apply to tables this schema actually has.
526
+ *
527
+ * `schema migrate --fragments=03` produces a migration with the plan-version
528
+ * tables and nothing else, and appending the whole file would add an index on
529
+ * `bundle_versions` — which Prisma then fails to apply, against the shadow
530
+ * database, with P1014 naming a table the consumer never asked for. Found by
531
+ * running the command rather than by reasoning about it.
532
+ *
533
+ * Statements addressing no table at all are kept: an unrecognised shape is a
534
+ * reason to be conservative, not to drop a constraint.
535
+ */
536
+ declare function constraintsFor(constraintsSql: string, tables: readonly string[]): string;
537
+ /**
538
+ * The migration with the constraints appended, or the input unchanged when it
539
+ * already has them.
540
+ *
541
+ * Appended rather than merged: the statements are `CREATE UNIQUE INDEX IF NOT
542
+ * EXISTS` and an `ALTER TABLE ... ADD CONSTRAINT`, so they have to run after
543
+ * the tables exist, and Prisma writes the table creation into the same file.
544
+ */
545
+ declare function appendConstraints(migrationSql: string, constraintsSql: string): string;
546
+ /**
547
+ * What step 3 of `schema migrate` did — and whether step 4 may follow.
548
+ *
549
+ * It was a boolean, and the boolean conflated two states that need opposite
550
+ * answers: "there was nothing to append" and "appending failed". On the second
551
+ * one the command told the operator to add the SQL by hand *before applying
552
+ * it* — and then applied it three lines later, which both makes the advice
553
+ * unfollowable and puts the file under a recorded checksum, so editing it
554
+ * afterwards offers a reset. Prisma's `--create-only` exists to open exactly
555
+ * that window; closing it by hand was the point.
556
+ */
557
+ type ConstraintsOutcome =
558
+ /** Written into the migration this run created. */
559
+ 'appended'
560
+ /** The migration already carried them — a re-run. */
561
+ | 'already-present'
562
+ /** No constraint addresses a table in this schema. */
563
+ | 'not-applicable'
564
+ /** Prisma created no migration, so there was nothing to append to. */
565
+ | 'no-migration'
566
+ /** The file could not be read or written. */
567
+ | 'failed';
568
+ interface ConstraintsReport {
569
+ readonly outcome: ConstraintsOutcome;
570
+ /**
571
+ * Whether the command may go on to apply the migration.
572
+ *
573
+ * False only for `failed`: every other outcome leaves a migration that is
574
+ * complete, or none at all.
575
+ */
576
+ readonly mayApply: boolean;
577
+ /** What to tell the operator, in one line. */
578
+ readonly message: string;
579
+ }
580
+ /**
581
+ * The decision and the message together, so they cannot contradict each other.
582
+ *
583
+ * They did: the message named a window the caller had already closed. Keeping
584
+ * them in one function lets a test assert the invariant that broke —
585
+ * "before applying" appears exactly when the command will not apply.
586
+ */
587
+ declare function reportConstraints(outcome: ConstraintsOutcome, context: {
588
+ readonly sqlPath: string;
589
+ readonly migration?: string | null;
590
+ }): ConstraintsReport;
591
+
592
+ /** A commented-out relation line, and what it points at. */
593
+ interface FkPointer {
594
+ /** 0-based line index in the schema. */
595
+ readonly line: number;
596
+ /** The model the relation targets, as the fragment names it. */
597
+ readonly target: 'Tenant' | 'User';
598
+ /** The model the line lives in — the other side of the relation. */
599
+ readonly model: string;
600
+ /** The line as it stands, still commented. */
601
+ readonly text: string;
602
+ }
603
+ /** Every commented-out FK pointer in `schema`, with the model it sits in. */
604
+ declare function findFkPointers(schema: string): FkPointer[];
605
+ /** The name of a named relation (`@relation("AuditLogUser", …)`), or null. */
606
+ declare function relationNameOf(relationAttribute: string): string | null;
607
+ /**
608
+ * Whether the foreign key is unique — which makes the relation 1:1, not 1:n.
609
+ *
610
+ * `Subscription.tenantId` carries `@unique`, so a tenant has at most one
611
+ * subscription and the opposite field is `subscription Subscription?`, not a
612
+ * list. The example app writes it exactly that way. A check that only knew
613
+ * lists called that correct schema incomplete and told the consumer to add a
614
+ * second, contradictory field.
615
+ *
616
+ * Measured, because the obvious guess is wrong: `prisma validate` 6.19.3
617
+ * ACCEPTS `subscriptions Subscription[]` against a `@unique` foreign key. So
618
+ * the list is not a build break — it is worse placed than that. The generated
619
+ * client types the relation as a list the database can never hold more than
620
+ * one of, and nothing says so until someone writes code for the second row.
621
+ * Only the missing field is P1012.
622
+ */
623
+ declare function isOneToOne(schema: string, model: string, foreignKey: string): boolean;
624
+ /**
625
+ * Whether `owner` already declares the opposite side of this relation.
626
+ *
627
+ * Prisma relations have two sides. Enabling `tenant Tenant @relation(...)` on
628
+ * `AuditLog` without a matching field on `Tenant` produces a schema Prisma
629
+ * refuses with P1012 — and the first version of this did exactly that to the
630
+ * project's own example app.
631
+ *
632
+ * Two things are part of the question rather than details, and Prisma taught
633
+ * each by refusing the result:
634
+ *
635
+ * - The relation NAME. `AuditLog.user` carries `@relation("AuditLogUser", …)`
636
+ * because a model may point at `User` more than once, and an unnamed field
637
+ * does not pair with it.
638
+ * - The CARDINALITY. A unique foreign key makes the opposite side singular,
639
+ * and a check that only knew lists reported a correct schema as broken.
640
+ */
641
+ declare function hasBackRelation(schema: string, model: string, owner: string, relationName: string | null, singular?: boolean): boolean;
642
+ interface FkModelNames {
643
+ /** What the app calls its tenant model, e.g. `Organization`. */
644
+ tenant?: string;
645
+ /** What the app calls its user model, e.g. `Account`. */
646
+ user?: string;
647
+ }
648
+ interface EnableFkResult {
649
+ readonly schema: string;
650
+ /** The pointers that were enabled, with the model each now names. */
651
+ readonly enabled: ReadonlyArray<{
652
+ line: number;
653
+ model: string;
654
+ }>;
655
+ /**
656
+ * Pointers left commented because the caller did not name that model.
657
+ *
658
+ * Reported rather than dropped: a schema half-wired for referential
659
+ * integrity is worse than one that is not, because it looks finished.
660
+ */
661
+ readonly skipped: ReadonlyArray<{
662
+ line: number;
663
+ target: string;
664
+ }>;
665
+ /**
666
+ * Pointers left commented because the app model has no opposite field, with
667
+ * the line to add.
668
+ *
669
+ * Separate from `skipped`, because the answer is different: those need a
670
+ * flag, these need one line in a model the tool must not edit on its own.
671
+ */
672
+ readonly needsBackRelation: ReadonlyArray<{
673
+ line: number;
674
+ owner: string;
675
+ suggestion: string;
676
+ }>;
677
+ }
678
+ /**
679
+ * Uncomments the FK pointers and renames their target to the app's model.
680
+ *
681
+ * Only for targets the caller actually named. `--tenant-model` without
682
+ * `--user-model` enables the tenant relations and leaves the user ones
683
+ * commented, which is a real configuration: not every app has a `User` the
684
+ * audit log should point at.
685
+ */
686
+ declare function enableFkPointers(schema: string, models: FkModelNames): EnableFkResult;
687
+ /** The scalar this relation is built on — `fields: [tenantId]`. */
688
+ declare function foreignKeyOf(relationAttribute: string): string | null;
689
+ /**
690
+ * Refuses a model name the schema does not define.
691
+ *
692
+ * Without this the command would produce a schema that does not validate, and
693
+ * the error would come from Prisma, about a line the consumer did not write.
694
+ */
695
+ declare function assertModelsExist(declaredModels: readonly string[], models: FkModelNames): void;
696
+
697
+ /** What the caller asked for. */
698
+ interface InitOptions {
699
+ /** The catalogue this app administers. Also the storage-key prefix. */
700
+ projectKey: string;
701
+ /** Human name in the manifest and the YAML. Defaults to `projectKey`. */
702
+ appName?: string;
703
+ /** Admin API prefix, e.g. `/api/v1/admin`. */
704
+ apiBase?: string;
705
+ /**
706
+ * Countable dimensions, as `key:Model` — `notes:Note` means a quota
707
+ * `notes` counted with `prisma.note.count()`.
708
+ */
709
+ quotas?: readonly string[];
710
+ /** Skip the password hasher when the app already has one. */
711
+ skipHasher?: boolean;
712
+ }
713
+ /** One file the generator will write. */
714
+ interface PlannedFile {
715
+ /** Path relative to the app root. */
716
+ readonly path: string;
717
+ /** Template path relative to `templates/init/`, without `.tpl`. */
718
+ readonly template: string;
719
+ /** Substitutions for this file, on top of the shared ones. */
720
+ readonly tokens: Readonly<Record<string, string>>;
721
+ }
722
+ interface InitPlan {
723
+ readonly files: readonly PlannedFile[];
724
+ readonly tokens: Readonly<Record<string, string>>;
725
+ /**
726
+ * The quota providers `app.module.ts` has to register, with the file each
727
+ * one was written to.
728
+ *
729
+ * The path is carried rather than re-derived. It was re-derived, from the
730
+ * class name, while the file was named from the quota key — two spellings
731
+ * of one name that agree for `notes` and part company for `apiCalls`:
732
+ * `apicalls-quota.provider.ts` written, `./saas/api-calls-quota.provider`
733
+ * imported, TS2307. The same shape as the persistence import a round
734
+ * earlier: a fix in the plan that its caller did not follow.
735
+ */
736
+ readonly quotaProviders: readonly QuotaProviderFile[];
737
+ /** The hasher class, or null when the caller brings their own. */
738
+ readonly hasherClass: string | null;
739
+ }
740
+ /** A parsed `--quota=key:Model` entry. */
741
+ interface QuotaProviderFile {
742
+ /** The class the module registers. */
743
+ readonly className: string;
744
+ /** Where the plan writes it, relative to the project root. */
745
+ readonly path: string;
746
+ }
747
+ interface QuotaSpec {
748
+ readonly key: string;
749
+ /** The Prisma delegate to count, e.g. `note`. */
750
+ readonly model: string;
751
+ }
752
+ /**
753
+ * Reads `key:Model`, or `key` when the model matches the key.
754
+ *
755
+ * The model is lower-camelised because that is what Prisma calls its delegate:
756
+ * a `Note` model is `prisma.note`, a `TeamMember` is `prisma.teamMember`. A
757
+ * generated file that named the model instead would not compile, and the
758
+ * failure would look like a schema problem.
759
+ */
760
+ declare function parseQuota(spec: string): QuotaSpec;
761
+ /** `notes` → `Notes`, `team-members` → `TeamMembers`. */
762
+ declare function pascalCase(value: string): string;
763
+ /**
764
+ * Everything the generator will do, as data.
765
+ *
766
+ * The quota block in the YAML is rendered here rather than in the template
767
+ * because it varies in LENGTH — a template can substitute a value, not repeat
768
+ * a section, and a template language that could would be a second thing to
769
+ * learn for the one file that needs it.
770
+ */
771
+ declare function planInit(options: InitOptions): InitPlan;
772
+ /** `NotesApp` → `notes-app`. */
773
+ declare const kebabCase: (value: string) => string;
774
+ /** Replaces `__TOKEN__` with its value; an unknown token is left visible. */
775
+ declare function applyTokens(content: string, tokens: Record<string, string>): string;
776
+ /**
777
+ * The patch options a plan implies.
778
+ *
779
+ * Here rather than in `bin/saasicat.js`, and that is the point of the move:
780
+ * both leftovers of the first review round were in this derivation, where
781
+ * `plan.ts` and `patchAppModule` were each tested and the step between them was
782
+ * not. `persistenceImport` hung on `hasherClass` while the plan had started
783
+ * writing the bundle in both cases, so `--skip-hasher` produced an app whose
784
+ * persistence file existed and was never imported.
785
+ *
786
+ * Read off the plan's own file list, so a file that is generated is a file that
787
+ * is wired, and the two cannot drift again.
788
+ */
789
+ declare function patchOptionsFor(plan: InitPlan): PatchOptionsFromPlan;
790
+ /** What `patchAppModule` takes, derived from a plan. */
791
+ interface PatchOptionsFromPlan {
792
+ persistenceImport: string | null;
793
+ adminModule: {
794
+ className: string;
795
+ importPath: string;
796
+ };
797
+ quotaProviders: Array<{
798
+ className: string;
799
+ importPath: string;
800
+ }>;
801
+ registry: {
802
+ constName: string;
803
+ importPath: string;
804
+ };
805
+ }
806
+
807
+ /** The pattern `plan-catalog.schema.json` puts on `projectKey`. */
808
+ declare function projectKeyPattern(): RegExp;
809
+ /** The pattern it puts on the keys inside a plan's `quotas` object. */
810
+ declare function quotaKeyPattern(): RegExp;
811
+ /** How many quotas a plan must declare — 1 today, and read rather than assumed. */
812
+ declare function minimumQuotasPerPlan(): number;
813
+ /**
814
+ * Refuses a project key the platform will refuse, while nothing is written yet.
815
+ *
816
+ * The message carries the pattern rather than a prose paraphrase, because the
817
+ * paraphrase is what goes stale.
818
+ */
819
+ declare function assertValidProjectKey(projectKey: string): void;
820
+ /** The same, for a quota key. `additionalProperties: false` makes it a hard rule. */
821
+ declare function assertValidQuotaKey(quotaKey: string): void;
822
+
823
+ /** One entry of the move table: where a file was, and where it went. */
824
+ interface MoveTable {
825
+ readonly moves: Readonly<Record<string, string>>;
826
+ /**
827
+ * Prefixes that left the package entirely. The value is a full specifier
828
+ * — `@saasicat/ui-vue-tenant/` — and is emitted verbatim.
829
+ */
830
+ readonly packages?: Readonly<Record<string, string>>;
831
+ /**
832
+ * Directories whose files left the surface as a whole — the page-private
833
+ * parts under `pages-standard/<page>/` that became `internal/<page>/`.
834
+ */
835
+ readonly moveDirectories?: Readonly<Record<string, string>>;
836
+ }
837
+ /**
838
+ * Old subpath → new subpath, derived from the move table.
839
+ *
840
+ * Both spellings of a page that moved are mapped, because both were reachable:
841
+ * `pages/AdminLayout.vue` and `pages-standard/AdminLayout.vue` named one file.
842
+ */
843
+ declare function buildImportMap(table: MoveTable): Map<string, string>;
844
+ /**
845
+ * What a subpath becomes, or null when it is already right.
846
+ *
847
+ * A `pages-standard/` path with no entry in the table is a page that did not
848
+ * move: it keeps its name under the surviving alias.
849
+ */
850
+ declare function rewriteSubpath(map: ReadonlyMap<string, string>, subpath: string): string | null;
851
+ /**
852
+ * Whether a subpath was public before and is not any more.
853
+ *
854
+ * Reported rather than rewritten: it moved into `features/` or `internal/`,
855
+ * which the 1.0 surface does not publish, so there is no destination to point
856
+ * at. Leaving it silently would hand the consumer a build error with no
857
+ * explanation of what happened.
858
+ */
859
+ declare function isNoLongerPublic(map: ReadonlyMap<string, string>, subpath: string): boolean;
860
+ /** Every `@saasicat/ui-vue/<subpath>` occurrence in a source text. */
861
+ declare const UI_VUE_SPECIFIER: RegExp;
862
+ interface RewriteResult {
863
+ readonly text: string;
864
+ readonly rewritten: number;
865
+ /** Subpaths that lost their export, with how often each appeared. */
866
+ readonly unmapped: ReadonlyMap<string, number>;
867
+ }
868
+ /** Applies the map to one file's text. */
869
+ declare function rewriteImports(text: string, map: ReadonlyMap<string, string>): RewriteResult;
870
+
871
+ /** One entry of the rename table. */
872
+ interface RenameTable {
873
+ /** An identifier stem, matched anywhere in an identifier, and its replacement. */
874
+ readonly identifierStems: Readonly<Record<string, string>>;
875
+ /** A registry-key prefix (or a whole key) inside a string literal, and its replacement. */
876
+ readonly registryKeys: Readonly<Record<string, string>>;
877
+ /** Per import specifier: a name that means something different per entry. */
878
+ readonly entryTokens: Readonly<Record<string, Readonly<Record<string, string>>>>;
879
+ /** A module specifier prefix and its replacement. */
880
+ readonly subpaths: Readonly<Record<string, string>>;
881
+ }
882
+ interface RenameResult {
883
+ readonly text: string;
884
+ readonly rewritten: number;
885
+ /**
886
+ * Names the table knows only per entry, imported from somewhere the table
887
+ * does not cover. Reported rather than guessed: which registry the
888
+ * consumer meant is not in the text.
889
+ */
890
+ readonly ambiguous: readonly string[];
891
+ }
892
+ /**
893
+ * The specifier and the bound names of every `import { … } from '…'`.
894
+ *
895
+ * Read backwards from each `from`, one character at a time, instead of with
896
+ * one regular expression over the statement: `\{([^}]*)\}\s+from` and its
897
+ * siblings backtrack quadratically on a file full of `import {{`, and the
898
+ * file is a consumer's — whatever they wrote, this must finish.
899
+ */
900
+ declare function namedImports(text: string): Array<{
901
+ names: string[];
902
+ specifier: string;
903
+ }>;
904
+ /** Applies the table to one file's text. Idempotent: a second run changes nothing. */
905
+ declare function rewriteNames(text: string, table: RenameTable): RenameResult;
906
+
907
+ interface PatchAppModuleOptions {
908
+ /** Import specifier for the persistence bundle, or null when not generated. */
909
+ persistenceImport: string | null;
910
+ /** The app's admin module class and the file it lives in. */
911
+ adminModule: {
912
+ className: string;
913
+ importPath: string;
914
+ };
915
+ /** Quota provider classes and where they came from. */
916
+ quotaProviders: ReadonlyArray<{
917
+ className: string;
918
+ importPath: string;
919
+ }>;
920
+ /** The feature-UI registry constant and its file. */
921
+ registry: {
922
+ constName: string;
923
+ importPath: string;
924
+ };
925
+ }
926
+ interface PatchResult {
927
+ /** The patched source, or the input unchanged when nothing was done. */
928
+ readonly source: string;
929
+ /** What happened, for the command to print. */
930
+ readonly status: 'patched' | 'already-wired' | 'declined';
931
+ /** Why it declined, and what to do instead. Empty otherwise. */
932
+ readonly reason: string;
933
+ /** The block to paste by hand when it declined. */
934
+ readonly manualBlock: string;
935
+ }
936
+ /**
937
+ * Adds the platform to an `@Module({ imports: [...] })` decorator.
938
+ *
939
+ * Returns `declined` rather than guessing when the shape is not the one this
940
+ * can edit safely: no `@Module`, no `imports` array, or a file that already
941
+ * mentions the marker.
942
+ */
943
+ declare function patchAppModule(source: string, options: PatchAppModuleOptions): PatchResult;
944
+ /**
945
+ * The `APP_FILTER` provider, as text.
946
+ *
947
+ * Not inserted automatically: `providers` is where an application keeps its own
948
+ * wiring, and an entry added into the middle of it is the edit most likely to
949
+ * land somewhere surprising. Printed instead, with the reason.
950
+ */
951
+ declare const LIMIT_FILTER_PROVIDER = "{ provide: APP_FILTER, useClass: LimitExceededFilter }";
952
+ /**
953
+ * The imports that provider needs, printed with it rather than inserted.
954
+ *
955
+ * They are not in `renderImports` on purpose: the file would import two symbols
956
+ * it does not use, which is a lint error in the first project this lands in.
957
+ */
958
+ declare const LIMIT_FILTER_IMPORTS: string;
959
+
500
960
  interface CliContextModuleOptions {
501
961
  config: CliContextConfig;
502
962
  userPort: ProviderSpec<UserPort>;
@@ -687,4 +1147,4 @@ declare class UserCommands extends CommandRunner {
687
1147
  parsePassword(val: string): string;
688
1148
  }
689
1149
 
690
- export { AUDIT_QUERY_PORT_TOKEN, AdminCommands, AdminManifestDoctorCheck, AdminMfaSetupCommand, AdminWhoamiCommand, type ApplyResult, AuditCommands, AuditTailCommand, AuditTailFlow, type AuditTailOptions, type BlockAttributeKind, type BlockAttributes, CLI_CONTEXT_CONFIG_TOKEN, type CheckSeverity, type CliContextConfig, CliContextModule, type CliContextModuleOptions, CliContextService, CliError, type CliIdentity, DEFAULT_MANIFEST_CHECKS, DOCTOR_CHECKS_TOKEN, DiscoveryCommands, DiscoveryScanCommand, DiscoverySnapshotDoctorCheck, type DoctorCheck, type DoctorCheckResult, DoctorCommands, DoctorFlow, type DoctorReport, type FieldMismatch, type FieldMismatchReason, type FieldSignature, MANIFEST_ACCESS_PORT_TOKEN, MANIFEST_CHECKS_TOKEN, type ManifestCheck, ManifestCheckCommand, type ManifestCheckReport, type ManifestCheckResult, ManifestCliFlow, ManifestCommands, type ManifestDiff, ManifestDumpCommand, ManifestHashCommand, ManifestValidateCommand, MfaSetupFlow, type MfaSetupOptions, type MfaSetupResult, type MissingBlockAttribute, type MissingEnumValue, type MissingField, PLATFORM_DOCTOR_CHECK_PROVIDERS, type ParsedSchema, PlanCatalogDoctorCheck, type SchemaCheckReport, USER_MANAGEMENT_PORT_TOKEN, USER_PORT_TOKEN, UserCommands, UserPortDoctorCheck, WhoAmIFlow, type WhoAmIResult, applyFragmentBlocks, blankStringLiterals, blockBodyLines, breaksContract, checkSchema, extractBlockNames, extractBlocks, extractModelBlocks, extractModelNames, parseBlockAttributes, parseEnumValues, parseFields, parseSchema, stripLineComment, structuralOnly };
1150
+ export { AUDIT_QUERY_PORT_TOKEN, AdminCommands, AdminManifestDoctorCheck, AdminMfaSetupCommand, AdminWhoamiCommand, type ApplyResult, AuditCommands, AuditTailCommand, AuditTailFlow, type AuditTailOptions, type BlockAttributeKind, type BlockAttributes, CLI_CONTEXT_CONFIG_TOKEN, CONSTRAINTS_MARKER, type CheckSeverity, type CliContextConfig, CliContextModule, type CliContextModuleOptions, CliContextService, CliError, type CliIdentity, type ConstraintsOutcome, type ConstraintsReport, DEFAULT_MANIFEST_CHECKS, DOCTOR_CHECKS_TOKEN, DiscoveryCommands, DiscoveryScanCommand, DiscoverySnapshotDoctorCheck, type DoctorCheck, type DoctorCheckResult, DoctorCommands, DoctorFlow, type DoctorReport, type EnableFkResult, type FieldMismatch, type FieldMismatchReason, type FieldSignature, type FkModelNames, type FkPointer, type InitOptions, type InitPlan, LIMIT_FILTER_IMPORTS, LIMIT_FILTER_PROVIDER, MANIFEST_ACCESS_PORT_TOKEN, MANIFEST_CHECKS_TOKEN, type ManifestCheck, ManifestCheckCommand, type ManifestCheckReport, type ManifestCheckResult, ManifestCliFlow, ManifestCommands, type ManifestDiff, ManifestDumpCommand, ManifestHashCommand, ManifestValidateCommand, MfaSetupFlow, type MfaSetupOptions, type MfaSetupResult, type MissingBlockAttribute, type MissingEnumValue, type MissingField, type MoveTable, PLATFORM_DOCTOR_CHECK_PROVIDERS, type ParsedSchema, type PatchAppModuleOptions, type PatchOptionsFromPlan, type PatchResult, PlanCatalogDoctorCheck, type PlannedFile, type QuotaProviderFile, type QuotaSpec, type RenameResult, type RenameTable, type RewriteResult, type SchemaCheckReport, UI_VUE_SPECIFIER, USER_MANAGEMENT_PORT_TOKEN, USER_PORT_TOKEN, UserCommands, UserPortDoctorCheck, WhoAmIFlow, type WhoAmIResult, appendConstraints, applyFragmentBlocks, applyTokens, assertModelsExist, assertValidProjectKey, assertValidQuotaKey, blankStringLiterals, blockBodyLines, breaksContract, buildImportMap, checkSchema, constraintsFor, enableFkPointers, extractBlockNames, extractBlocks, extractModelBlocks, extractModelNames, findFkPointers, foreignKeyOf, hasBackRelation, hasConstraints, isNoLongerPublic, isOneToOne, kebabCase, migrationCreatedBy, minimumQuotasPerPlan, namedImports, parseBlockAttributes, parseEnumValues, parseFields, parseQuota, parseSchema, pascalCase, patchAppModule, patchOptionsFor, planInit, projectKeyPattern, quotaKeyPattern, relationNameOf, reportConstraints, rewriteImports, rewriteNames, rewriteSubpath, stripLineComment, structuralOnly, tablesAddressedBy };