@shipfox/api-projects 11.0.0 → 12.2.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.
Files changed (98) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/CHANGELOG.md +53 -0
  3. package/README.md +83 -0
  4. package/dist/core/entities/project.d.ts +4 -0
  5. package/dist/core/entities/project.d.ts.map +1 -1
  6. package/dist/core/entities/project.js.map +1 -1
  7. package/dist/core/errors.d.ts +4 -0
  8. package/dist/core/errors.d.ts.map +1 -1
  9. package/dist/core/errors.js +6 -0
  10. package/dist/core/errors.js.map +1 -1
  11. package/dist/core/index.d.ts +3 -3
  12. package/dist/core/index.d.ts.map +1 -1
  13. package/dist/core/index.js +2 -2
  14. package/dist/core/index.js.map +1 -1
  15. package/dist/core/projects.d.ts +8 -0
  16. package/dist/core/projects.d.ts.map +1 -1
  17. package/dist/core/projects.js +62 -19
  18. package/dist/core/projects.js.map +1 -1
  19. package/dist/db/db.d.ts +144 -6
  20. package/dist/db/db.d.ts.map +1 -1
  21. package/dist/db/db.js.map +1 -1
  22. package/dist/db/index.d.ts +2 -2
  23. package/dist/db/index.d.ts.map +1 -1
  24. package/dist/db/index.js +1 -1
  25. package/dist/db/index.js.map +1 -1
  26. package/dist/db/projects.d.ts +53 -0
  27. package/dist/db/projects.d.ts.map +1 -1
  28. package/dist/db/projects.js +116 -18
  29. package/dist/db/projects.js.map +1 -1
  30. package/dist/db/schema/integration-event-dedup.d.ts +1 -1
  31. package/dist/db/schema/outbox.d.ts +1 -1
  32. package/dist/db/schema/projects.d.ts +69 -1
  33. package/dist/db/schema/projects.d.ts.map +1 -1
  34. package/dist/db/schema/projects.js +12 -1
  35. package/dist/db/schema/projects.js.map +1 -1
  36. package/dist/index.d.ts +1 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +8 -5
  39. package/dist/index.js.map +1 -1
  40. package/dist/presentation/dto/project.d.ts +2 -1
  41. package/dist/presentation/dto/project.d.ts.map +1 -1
  42. package/dist/presentation/dto/project.js +1 -0
  43. package/dist/presentation/dto/project.js.map +1 -1
  44. package/dist/presentation/e2eRoutes/create-project.d.ts.map +1 -1
  45. package/dist/presentation/e2eRoutes/create-project.js +34 -8
  46. package/dist/presentation/e2eRoutes/create-project.js.map +1 -1
  47. package/dist/presentation/inter-module.d.ts +4 -1
  48. package/dist/presentation/inter-module.d.ts.map +1 -1
  49. package/dist/presentation/inter-module.js +63 -3
  50. package/dist/presentation/inter-module.js.map +1 -1
  51. package/dist/presentation/routes/create-project.d.ts.map +1 -1
  52. package/dist/presentation/routes/create-project.js +8 -2
  53. package/dist/presentation/routes/create-project.js.map +1 -1
  54. package/dist/presentation/routes/index.d.ts.map +1 -1
  55. package/dist/presentation/routes/index.js +3 -1
  56. package/dist/presentation/routes/index.js.map +1 -1
  57. package/dist/presentation/routes/update-project.d.ts +2 -0
  58. package/dist/presentation/routes/update-project.d.ts.map +1 -0
  59. package/dist/presentation/routes/update-project.js +53 -0
  60. package/dist/presentation/routes/update-project.js.map +1 -0
  61. package/dist/presentation/subscribers/index.d.ts +1 -0
  62. package/dist/presentation/subscribers/index.d.ts.map +1 -1
  63. package/dist/presentation/subscribers/index.js +1 -0
  64. package/dist/presentation/subscribers/index.js.map +1 -1
  65. package/dist/presentation/subscribers/on-source-repository-updated.d.ts +4 -0
  66. package/dist/presentation/subscribers/on-source-repository-updated.d.ts.map +1 -0
  67. package/dist/presentation/subscribers/on-source-repository-updated.js +39 -0
  68. package/dist/presentation/subscribers/on-source-repository-updated.js.map +1 -0
  69. package/dist/tsconfig.test.tsbuildinfo +1 -1
  70. package/drizzle/0000_initial.sql +6 -0
  71. package/drizzle/meta/0000_snapshot.json +78 -0
  72. package/package.json +13 -12
  73. package/src/core/entities/project.ts +4 -0
  74. package/src/core/errors.ts +7 -0
  75. package/src/core/index.ts +3 -2
  76. package/src/core/projects.test.ts +10 -0
  77. package/src/core/projects.ts +90 -35
  78. package/src/db/db.ts +3 -0
  79. package/src/db/index.ts +6 -0
  80. package/src/db/projects.test.ts +44 -1
  81. package/src/db/projects.ts +242 -33
  82. package/src/db/schema/projects.ts +16 -0
  83. package/src/index.ts +9 -3
  84. package/src/presentation/dto/project.ts +1 -0
  85. package/src/presentation/e2eRoutes/create-project.test.ts +23 -0
  86. package/src/presentation/e2eRoutes/create-project.ts +39 -10
  87. package/src/presentation/inter-module.test.ts +349 -0
  88. package/src/presentation/inter-module.ts +90 -4
  89. package/src/presentation/routes/create-project.ts +10 -2
  90. package/src/presentation/routes/index.ts +7 -1
  91. package/src/presentation/routes/projects.test.ts +300 -4
  92. package/src/presentation/routes/update-project.ts +46 -0
  93. package/src/presentation/subscribers/index.ts +1 -0
  94. package/src/presentation/subscribers/on-source-commit-pushed.test.ts +2 -0
  95. package/src/presentation/subscribers/on-source-repository-updated.test.ts +108 -0
  96. package/src/presentation/subscribers/on-source-repository-updated.ts +50 -0
  97. package/test/factories/project.ts +6 -0
  98. package/tsconfig.build.tsbuildinfo +1 -1
package/dist/db/db.d.ts CHANGED
@@ -72,6 +72,57 @@ export declare const schema: {
72
72
  identity: undefined;
73
73
  generated: undefined;
74
74
  }, {}, {}>;
75
+ sourceRepositoryOwner: import("drizzle-orm/pg-core").PgColumn<{
76
+ name: "source_repository_owner";
77
+ tableName: "projects";
78
+ dataType: "string";
79
+ columnType: "PgText";
80
+ data: string;
81
+ driverParam: string;
82
+ notNull: false;
83
+ hasDefault: false;
84
+ isPrimaryKey: false;
85
+ isAutoincrement: false;
86
+ hasRuntimeDefault: false;
87
+ enumValues: [string, ...string[]];
88
+ baseColumn: never;
89
+ identity: undefined;
90
+ generated: undefined;
91
+ }, {}, {}>;
92
+ sourceRepositoryName: import("drizzle-orm/pg-core").PgColumn<{
93
+ name: "source_repository_name";
94
+ tableName: "projects";
95
+ dataType: "string";
96
+ columnType: "PgText";
97
+ data: string;
98
+ driverParam: string;
99
+ notNull: false;
100
+ hasDefault: false;
101
+ isPrimaryKey: false;
102
+ isAutoincrement: false;
103
+ hasRuntimeDefault: false;
104
+ enumValues: [string, ...string[]];
105
+ baseColumn: never;
106
+ identity: undefined;
107
+ generated: undefined;
108
+ }, {}, {}>;
109
+ sourceDefaultBranch: import("drizzle-orm/pg-core").PgColumn<{
110
+ name: "source_default_branch";
111
+ tableName: "projects";
112
+ dataType: "string";
113
+ columnType: "PgText";
114
+ data: string;
115
+ driverParam: string;
116
+ notNull: false;
117
+ hasDefault: false;
118
+ isPrimaryKey: false;
119
+ isAutoincrement: false;
120
+ hasRuntimeDefault: false;
121
+ enumValues: [string, ...string[]];
122
+ baseColumn: never;
123
+ identity: undefined;
124
+ generated: undefined;
125
+ }, {}, {}>;
75
126
  name: import("drizzle-orm/pg-core").PgColumn<{
76
127
  name: "name";
77
128
  tableName: "projects";
@@ -89,6 +140,23 @@ export declare const schema: {
89
140
  identity: undefined;
90
141
  generated: undefined;
91
142
  }, {}, {}>;
143
+ slug: import("drizzle-orm/pg-core").PgColumn<{
144
+ name: "slug";
145
+ tableName: "projects";
146
+ dataType: "string";
147
+ columnType: "PgText";
148
+ data: string;
149
+ driverParam: string;
150
+ notNull: true;
151
+ hasDefault: false;
152
+ isPrimaryKey: false;
153
+ isAutoincrement: false;
154
+ hasRuntimeDefault: false;
155
+ enumValues: [string, ...string[]];
156
+ baseColumn: never;
157
+ identity: undefined;
158
+ generated: undefined;
159
+ }, {}, {}>;
92
160
  createdAt: import("drizzle-orm/pg-core").PgColumn<{
93
161
  name: "created_at";
94
162
  tableName: "projects";
@@ -124,7 +192,7 @@ export declare const schema: {
124
192
  generated: undefined;
125
193
  }, {}, {}>;
126
194
  };
127
- dialect: "pg";
195
+ dialect: 'pg';
128
196
  }>;
129
197
  projectsOutbox: import("drizzle-orm/pg-core").PgTableWithColumns<{
130
198
  name: "outbox";
@@ -318,7 +386,7 @@ export declare const schema: {
318
386
  generated: undefined;
319
387
  }, {}, {}>;
320
388
  };
321
- dialect: "pg";
389
+ dialect: 'pg';
322
390
  }>;
323
391
  projectsIntegrationEventDedup: import("drizzle-orm/pg-core").PgTableWithColumns<{
324
392
  name: "integration_event_dedup";
@@ -376,7 +444,7 @@ export declare const schema: {
376
444
  generated: undefined;
377
445
  }, {}, {}>;
378
446
  };
379
- dialect: "pg";
447
+ dialect: 'pg';
380
448
  }>;
381
449
  };
382
450
  export declare function db(): NodePgDatabase<{
@@ -452,6 +520,57 @@ export declare function db(): NodePgDatabase<{
452
520
  identity: undefined;
453
521
  generated: undefined;
454
522
  }, {}, {}>;
523
+ sourceRepositoryOwner: import("drizzle-orm/pg-core").PgColumn<{
524
+ name: "source_repository_owner";
525
+ tableName: "projects";
526
+ dataType: "string";
527
+ columnType: "PgText";
528
+ data: string;
529
+ driverParam: string;
530
+ notNull: false;
531
+ hasDefault: false;
532
+ isPrimaryKey: false;
533
+ isAutoincrement: false;
534
+ hasRuntimeDefault: false;
535
+ enumValues: [string, ...string[]];
536
+ baseColumn: never;
537
+ identity: undefined;
538
+ generated: undefined;
539
+ }, {}, {}>;
540
+ sourceRepositoryName: import("drizzle-orm/pg-core").PgColumn<{
541
+ name: "source_repository_name";
542
+ tableName: "projects";
543
+ dataType: "string";
544
+ columnType: "PgText";
545
+ data: string;
546
+ driverParam: string;
547
+ notNull: false;
548
+ hasDefault: false;
549
+ isPrimaryKey: false;
550
+ isAutoincrement: false;
551
+ hasRuntimeDefault: false;
552
+ enumValues: [string, ...string[]];
553
+ baseColumn: never;
554
+ identity: undefined;
555
+ generated: undefined;
556
+ }, {}, {}>;
557
+ sourceDefaultBranch: import("drizzle-orm/pg-core").PgColumn<{
558
+ name: "source_default_branch";
559
+ tableName: "projects";
560
+ dataType: "string";
561
+ columnType: "PgText";
562
+ data: string;
563
+ driverParam: string;
564
+ notNull: false;
565
+ hasDefault: false;
566
+ isPrimaryKey: false;
567
+ isAutoincrement: false;
568
+ hasRuntimeDefault: false;
569
+ enumValues: [string, ...string[]];
570
+ baseColumn: never;
571
+ identity: undefined;
572
+ generated: undefined;
573
+ }, {}, {}>;
455
574
  name: import("drizzle-orm/pg-core").PgColumn<{
456
575
  name: "name";
457
576
  tableName: "projects";
@@ -469,6 +588,23 @@ export declare function db(): NodePgDatabase<{
469
588
  identity: undefined;
470
589
  generated: undefined;
471
590
  }, {}, {}>;
591
+ slug: import("drizzle-orm/pg-core").PgColumn<{
592
+ name: "slug";
593
+ tableName: "projects";
594
+ dataType: "string";
595
+ columnType: "PgText";
596
+ data: string;
597
+ driverParam: string;
598
+ notNull: true;
599
+ hasDefault: false;
600
+ isPrimaryKey: false;
601
+ isAutoincrement: false;
602
+ hasRuntimeDefault: false;
603
+ enumValues: [string, ...string[]];
604
+ baseColumn: never;
605
+ identity: undefined;
606
+ generated: undefined;
607
+ }, {}, {}>;
472
608
  createdAt: import("drizzle-orm/pg-core").PgColumn<{
473
609
  name: "created_at";
474
610
  tableName: "projects";
@@ -504,7 +640,7 @@ export declare function db(): NodePgDatabase<{
504
640
  generated: undefined;
505
641
  }, {}, {}>;
506
642
  };
507
- dialect: "pg";
643
+ dialect: 'pg';
508
644
  }>;
509
645
  projectsOutbox: import("drizzle-orm/pg-core").PgTableWithColumns<{
510
646
  name: "outbox";
@@ -698,7 +834,7 @@ export declare function db(): NodePgDatabase<{
698
834
  generated: undefined;
699
835
  }, {}, {}>;
700
836
  };
701
- dialect: "pg";
837
+ dialect: 'pg';
702
838
  }>;
703
839
  projectsIntegrationEventDedup: import("drizzle-orm/pg-core").PgTableWithColumns<{
704
840
  name: "integration_event_dedup";
@@ -756,8 +892,10 @@ export declare function db(): NodePgDatabase<{
756
892
  generated: undefined;
757
893
  }, {}, {}>;
758
894
  };
759
- dialect: "pg";
895
+ dialect: 'pg';
760
896
  }>;
761
897
  }>;
898
+ export type Tx = Parameters<Parameters<ReturnType<typeof db>['transaction']>[0]>[0];
899
+ export type Executor = ReturnType<typeof db> | Tx;
762
900
  export declare function closeDb(): void;
763
901
  //# sourceMappingURL=db.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAMnE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAIlB,CAAC;AAIF,wBAAgB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAGjB;AAED,wBAAgB,OAAO,IAAI,IAAI,CAE9B"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAMnE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAIlB,CAAC;AAIF,wBAAgB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAGjB;AAED,MAAM,MAAM,EAAE,GAAG,UAAU,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpF,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC;AAElD,wBAAgB,OAAO,IAAI,IAAI,CAE9B"}
package/dist/db/db.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/db/db.ts"],"sourcesContent":["import {drizzle, type NodePgDatabase} from '@shipfox/node-drizzle';\nimport {pgClient} from '@shipfox/node-postgres';\nimport {projectsIntegrationEventDedup} from './schema/integration-event-dedup.js';\nimport {projectsOutbox} from './schema/outbox.js';\nimport {projects} from './schema/projects.js';\n\nexport const schema = {\n projects,\n projectsOutbox,\n projectsIntegrationEventDedup,\n};\n\nlet _db: NodePgDatabase<typeof schema> | undefined;\n\nexport function db() {\n if (!_db) _db = drizzle(pgClient(), {schema});\n return _db;\n}\n\nexport function closeDb(): void {\n _db = undefined;\n}\n"],"names":["drizzle","pgClient","projectsIntegrationEventDedup","projectsOutbox","projects","schema","_db","db","closeDb","undefined"],"mappings":"AAAA,SAAQA,OAAO,QAA4B,wBAAwB;AACnE,SAAQC,QAAQ,QAAO,yBAAyB;AAChD,SAAQC,6BAA6B,QAAO,sCAAsC;AAClF,SAAQC,cAAc,QAAO,qBAAqB;AAClD,SAAQC,QAAQ,QAAO,uBAAuB;AAE9C,OAAO,MAAMC,SAAS;IACpBD;IACAD;IACAD;AACF,EAAE;AAEF,IAAII;AAEJ,OAAO,SAASC;IACd,IAAI,CAACD,KAAKA,MAAMN,QAAQC,YAAY;QAACI;IAAM;IAC3C,OAAOC;AACT;AAEA,OAAO,SAASE;IACdF,MAAMG;AACR"}
1
+ {"version":3,"sources":["../../src/db/db.ts"],"sourcesContent":["import {drizzle, type NodePgDatabase} from '@shipfox/node-drizzle';\nimport {pgClient} from '@shipfox/node-postgres';\nimport {projectsIntegrationEventDedup} from './schema/integration-event-dedup.js';\nimport {projectsOutbox} from './schema/outbox.js';\nimport {projects} from './schema/projects.js';\n\nexport const schema = {\n projects,\n projectsOutbox,\n projectsIntegrationEventDedup,\n};\n\nlet _db: NodePgDatabase<typeof schema> | undefined;\n\nexport function db() {\n if (!_db) _db = drizzle(pgClient(), {schema});\n return _db;\n}\n\nexport type Tx = Parameters<Parameters<ReturnType<typeof db>['transaction']>[0]>[0];\nexport type Executor = ReturnType<typeof db> | Tx;\n\nexport function closeDb(): void {\n _db = undefined;\n}\n"],"names":["drizzle","pgClient","projectsIntegrationEventDedup","projectsOutbox","projects","schema","_db","db","closeDb","undefined"],"mappings":"AAAA,SAAQA,OAAO,QAA4B,wBAAwB;AACnE,SAAQC,QAAQ,QAAO,yBAAyB;AAChD,SAAQC,6BAA6B,QAAO,sCAAsC;AAClF,SAAQC,cAAc,QAAO,qBAAqB;AAClD,SAAQC,QAAQ,QAAO,uBAAuB;AAE9C,OAAO,MAAMC,SAAS;IACpBD;IACAD;IACAD;AACF,EAAE;AAEF,IAAII;AAEJ,OAAO,SAASC;IACd,IAAI,CAACD,KAAKA,MAAMN,QAAQC,YAAY;QAACI;IAAM;IAC3C,OAAOC;AACT;AAKA,OAAO,SAASE;IACdF,MAAMG;AACR"}
@@ -1,7 +1,7 @@
1
1
  export { closeDb, db, schema } from './db.js';
2
2
  export { pruneIntegrationEventDedup, recordIntegrationEventForProject, } from './integration-event-dedup.js';
3
- export type { AdminProjectSummary, CreateProjectParams, GetProjectBySourceParams, ListAdminProjectsParams, ListAdminProjectsResult, ListProjectsParams, ListProjectsResult, } from './projects.js';
4
- export { createProject, getProjectById, getProjectBySource, getProjectCount, getWorkspaceProjectCounts, listAdminProjects, listProjects, requireProjectForWorkspace, } from './projects.js';
3
+ export type { AdminProjectSummary, CreateProjectParams, GetProjectBySourceParams, ListAdminProjectsParams, ListAdminProjectsResult, ListProjectsParams, ListProjectsResult, ResolveCheckoutTargetParams, ResolvedCheckoutTarget, UpdateProjectParams, UpdateProjectResult, } from './projects.js';
4
+ export { createProject, getProjectById, getProjectBySource, getProjectCount, getWorkspaceProjectCounts, listAdminProjects, listProjects, requireProjectForWorkspace, resolveCheckoutTarget, updateProject, } from './projects.js';
5
5
  export { projectsIntegrationEventDedup } from './schema/integration-event-dedup.js';
6
6
  export { projectsOutbox } from './schema/outbox.js';
7
7
  export declare const migrationsPath: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAC,MAAM,SAAS,CAAC;AAC5C,OAAO,EACL,0BAA0B,EAC1B,gCAAgC,GACjC,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,iBAAiB,EACjB,YAAY,EACZ,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAC,6BAA6B,EAAC,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAElD,eAAO,MAAM,cAAc,QAAoE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAC,MAAM,SAAS,CAAC;AAC5C,OAAO,EACL,0BAA0B,EAC1B,gCAAgC,GACjC,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,2BAA2B,EAC3B,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,iBAAiB,EACjB,YAAY,EACZ,0BAA0B,EAC1B,qBAAqB,EACrB,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAC,6BAA6B,EAAC,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAElD,eAAO,MAAM,cAAc,QAAoE,CAAC"}
package/dist/db/index.js CHANGED
@@ -2,7 +2,7 @@ import { dirname, resolve } from 'node:path';
2
2
  import { fileURLToPath } from 'node:url';
3
3
  export { closeDb, db, schema } from './db.js';
4
4
  export { pruneIntegrationEventDedup, recordIntegrationEventForProject } from './integration-event-dedup.js';
5
- export { createProject, getProjectById, getProjectBySource, getProjectCount, getWorkspaceProjectCounts, listAdminProjects, listProjects, requireProjectForWorkspace } from './projects.js';
5
+ export { createProject, getProjectById, getProjectBySource, getProjectCount, getWorkspaceProjectCounts, listAdminProjects, listProjects, requireProjectForWorkspace, resolveCheckoutTarget, updateProject } from './projects.js';
6
6
  export { projectsIntegrationEventDedup } from './schema/integration-event-dedup.js';
7
7
  export { projectsOutbox } from './schema/outbox.js';
8
8
  export const migrationsPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../drizzle');
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/db/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nexport {closeDb, db, schema} from './db.js';\nexport {\n pruneIntegrationEventDedup,\n recordIntegrationEventForProject,\n} from './integration-event-dedup.js';\nexport type {\n AdminProjectSummary,\n CreateProjectParams,\n GetProjectBySourceParams,\n ListAdminProjectsParams,\n ListAdminProjectsResult,\n ListProjectsParams,\n ListProjectsResult,\n} from './projects.js';\nexport {\n createProject,\n getProjectById,\n getProjectBySource,\n getProjectCount,\n getWorkspaceProjectCounts,\n listAdminProjects,\n listProjects,\n requireProjectForWorkspace,\n} from './projects.js';\nexport {projectsIntegrationEventDedup} from './schema/integration-event-dedup.js';\nexport {projectsOutbox} from './schema/outbox.js';\n\nexport const migrationsPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../drizzle');\n"],"names":["dirname","resolve","fileURLToPath","closeDb","db","schema","pruneIntegrationEventDedup","recordIntegrationEventForProject","createProject","getProjectById","getProjectBySource","getProjectCount","getWorkspaceProjectCounts","listAdminProjects","listProjects","requireProjectForWorkspace","projectsIntegrationEventDedup","projectsOutbox","migrationsPath","url"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AAEvC,SAAQC,OAAO,EAAEC,EAAE,EAAEC,MAAM,QAAO,UAAU;AAC5C,SACEC,0BAA0B,EAC1BC,gCAAgC,QAC3B,+BAA+B;AAUtC,SACEC,aAAa,EACbC,cAAc,EACdC,kBAAkB,EAClBC,eAAe,EACfC,yBAAyB,EACzBC,iBAAiB,EACjBC,YAAY,EACZC,0BAA0B,QACrB,gBAAgB;AACvB,SAAQC,6BAA6B,QAAO,sCAAsC;AAClF,SAAQC,cAAc,QAAO,qBAAqB;AAElD,OAAO,MAAMC,iBAAiBjB,QAAQD,QAAQE,cAAc,YAAYiB,GAAG,IAAI,iBAAiB"}
1
+ {"version":3,"sources":["../../src/db/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nexport {closeDb, db, schema} from './db.js';\nexport {\n pruneIntegrationEventDedup,\n recordIntegrationEventForProject,\n} from './integration-event-dedup.js';\nexport type {\n AdminProjectSummary,\n CreateProjectParams,\n GetProjectBySourceParams,\n ListAdminProjectsParams,\n ListAdminProjectsResult,\n ListProjectsParams,\n ListProjectsResult,\n ResolveCheckoutTargetParams,\n ResolvedCheckoutTarget,\n UpdateProjectParams,\n UpdateProjectResult,\n} from './projects.js';\nexport {\n createProject,\n getProjectById,\n getProjectBySource,\n getProjectCount,\n getWorkspaceProjectCounts,\n listAdminProjects,\n listProjects,\n requireProjectForWorkspace,\n resolveCheckoutTarget,\n updateProject,\n} from './projects.js';\nexport {projectsIntegrationEventDedup} from './schema/integration-event-dedup.js';\nexport {projectsOutbox} from './schema/outbox.js';\n\nexport const migrationsPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../drizzle');\n"],"names":["dirname","resolve","fileURLToPath","closeDb","db","schema","pruneIntegrationEventDedup","recordIntegrationEventForProject","createProject","getProjectById","getProjectBySource","getProjectCount","getWorkspaceProjectCounts","listAdminProjects","listProjects","requireProjectForWorkspace","resolveCheckoutTarget","updateProject","projectsIntegrationEventDedup","projectsOutbox","migrationsPath","url"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AAEvC,SAAQC,OAAO,EAAEC,EAAE,EAAEC,MAAM,QAAO,UAAU;AAC5C,SACEC,0BAA0B,EAC1BC,gCAAgC,QAC3B,+BAA+B;AActC,SACEC,aAAa,EACbC,cAAc,EACdC,kBAAkB,EAClBC,eAAe,EACfC,yBAAyB,EACzBC,iBAAiB,EACjBC,YAAY,EACZC,0BAA0B,EAC1BC,qBAAqB,EACrBC,aAAa,QACR,gBAAgB;AACvB,SAAQC,6BAA6B,QAAO,sCAAsC;AAClF,SAAQC,cAAc,QAAO,qBAAqB;AAElD,OAAO,MAAMC,iBAAiBnB,QAAQD,QAAQE,cAAc,YAAYmB,GAAG,IAAI,iBAAiB"}
@@ -1,9 +1,22 @@
1
1
  import type { Project } from '#core/entities/project.js';
2
+ import { db, type Executor } from './db.js';
3
+ type ProjectDatabase = ReturnType<typeof db>;
4
+ type ProjectTransaction = Parameters<Parameters<ProjectDatabase['transaction']>[0]>[0];
2
5
  export interface CreateProjectParams {
3
6
  workspaceId: string;
4
7
  sourceConnectionId: string;
5
8
  sourceExternalRepositoryId: string;
6
9
  name: string;
10
+ slug: string;
11
+ }
12
+ export interface UpdateProjectParams {
13
+ projectId: string;
14
+ name?: string | undefined;
15
+ slug?: string | undefined;
16
+ }
17
+ export interface UpdateProjectResult {
18
+ project: Project;
19
+ changed: boolean;
7
20
  }
8
21
  export interface ProjectCursor {
9
22
  createdAt: Date;
@@ -31,6 +44,9 @@ export interface ListAdminProjectsResult {
31
44
  nextCursor: ProjectCursor | null;
32
45
  }
33
46
  export declare function createProject(params: CreateProjectParams): Promise<Project>;
47
+ export declare function updateProject(params: UpdateProjectParams, options?: {
48
+ tx?: ProjectDatabase | ProjectTransaction | undefined;
49
+ }): Promise<UpdateProjectResult | undefined>;
34
50
  export declare function getProjectById(id: string): Promise<Project | undefined>;
35
51
  export interface GetProjectBySourceParams {
36
52
  workspaceId: string;
@@ -38,10 +54,46 @@ export interface GetProjectBySourceParams {
38
54
  sourceExternalRepositoryId: string;
39
55
  }
40
56
  export declare function getProjectBySource(params: GetProjectBySourceParams): Promise<Project | undefined>;
57
+ export interface UpdateProjectSourceRepositoryParams extends GetProjectBySourceParams {
58
+ tx?: Executor;
59
+ sourceRepositoryOwner: string;
60
+ sourceRepositoryName: string;
61
+ sourceDefaultBranch: string;
62
+ }
63
+ export declare function updateProjectSourceRepository(params: UpdateProjectSourceRepositoryParams): Promise<Project | undefined>;
41
64
  export declare function requireProjectForWorkspace(params: {
42
65
  projectId: string;
43
66
  workspaceId: string;
44
67
  }): Promise<Project>;
68
+ export interface ResolveCheckoutTargetParams {
69
+ workspaceId: string;
70
+ defaults: {
71
+ connectionId: string;
72
+ owner: string;
73
+ };
74
+ target: {
75
+ project: string;
76
+ } | {
77
+ connection?: string | undefined;
78
+ repository: string;
79
+ };
80
+ }
81
+ export interface ResolvedCheckoutTarget {
82
+ projectId: string;
83
+ connectionId: string;
84
+ externalRepositoryId: string;
85
+ }
86
+ export interface UpdateProjectSourceMetadataParams {
87
+ workspaceId: string;
88
+ projectId: string;
89
+ sourceConnectionId: string;
90
+ sourceExternalRepositoryId: string;
91
+ sourceRepositoryOwner: string;
92
+ sourceRepositoryName: string;
93
+ sourceDefaultBranch: string;
94
+ }
95
+ export declare function updateProjectSourceMetadata(params: UpdateProjectSourceMetadataParams): Promise<void>;
96
+ export declare function resolveCheckoutTarget(params: ResolveCheckoutTargetParams): Promise<ResolvedCheckoutTarget | undefined>;
45
97
  export declare function listProjects(params: ListProjectsParams): Promise<ListProjectsResult>;
46
98
  export declare function listAdminProjects(params: ListAdminProjectsParams): Promise<ListAdminProjectsResult>;
47
99
  export declare function getProjectCount(): Promise<number>;
@@ -51,4 +103,5 @@ export declare function getWorkspaceProjectCounts(params: {
51
103
  workspaceId: string;
52
104
  count: number;
53
105
  }>>;
106
+ export {};
54
107
  //# sourceMappingURL=projects.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/db/projects.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,2BAA2B,CAAC;AAMvD,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0BAA0B,EAAE,MAAM,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,IAAI,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAMD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,EAAE,aAAa,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,MAAM,mBAAmB,GAAG,IAAI,CACpC,OAAO,EACP,IAAI,GAAG,aAAa,GAAG,MAAM,GAAG,WAAW,GAAG,WAAW,CAC1D,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,UAAU,EAAE,aAAa,GAAG,IAAI,CAAC;CAClC;AAUD,wBAAsB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAwCjF;AAED,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAM7E;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0BAA0B,EAAE,MAAM,CAAC;CACpC;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAgB9B;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,OAAO,CAAC,CAKnB;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAuB1F;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,uBAAuB,CAAC,CA8BlC;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAGvD;AAED,wBAAsB,yBAAyB,CAAC,MAAM,EAAE;IACtD,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,GAAG,OAAO,CAAC,KAAK,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAAC,CAAC,CAYvD"}
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/db/projects.ts"],"names":[],"mappings":"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"}
@@ -1,33 +1,48 @@
1
- import { and, count, desc, eq, ilike, inArray, lt, or } from 'drizzle-orm';
2
- import { ProjectAlreadyExistsError, ProjectNotFoundError } from '#core/errors.js';
1
+ import { isUniqueViolation } from '@shipfox/node-drizzle';
2
+ import { and, count, desc, eq, ilike, inArray, lt, or, sql } from 'drizzle-orm';
3
+ import { ProjectAlreadyExistsError, ProjectNotFoundError, ProjectSlugConflictError } from '#core/errors.js';
3
4
  import { recordProjectCreated } from '#metrics/instance.js';
4
5
  import { db } from './db.js';
5
6
  import { projects, toProject } from './schema/projects.js';
6
7
  function escapeIlikePattern(value) {
7
8
  return value.replace(/[\\%_]/g, (char)=>`\\${char}`);
8
9
  }
10
+ const PROJECTS_WORKSPACE_SLUG_UNIQUE_CONSTRAINT = 'projects_workspace_slug_unique';
9
11
  function cursorWhere(cursor) {
10
12
  if (!cursor) return undefined;
11
13
  return or(lt(projects.createdAt, cursor.createdAt), and(eq(projects.createdAt, cursor.createdAt), lt(projects.id, cursor.id)));
12
14
  }
13
15
  export async function createProject(params) {
14
16
  const project = await db().transaction(async (tx)=>{
15
- const [projectRow] = await tx.insert(projects).values({
16
- workspaceId: params.workspaceId,
17
- sourceConnectionId: params.sourceConnectionId,
18
- sourceExternalRepositoryId: params.sourceExternalRepositoryId,
19
- name: params.name
20
- }).onConflictDoNothing({
21
- target: [
22
- projects.sourceConnectionId,
23
- projects.sourceExternalRepositoryId
24
- ]
25
- }).returning();
26
- if (!projectRow) {
27
- const [conflict] = await tx.select().from(projects).where(and(eq(projects.sourceConnectionId, params.sourceConnectionId), eq(projects.sourceExternalRepositoryId, params.sourceExternalRepositoryId))).limit(1);
28
- if (conflict) {
29
- throw new ProjectAlreadyExistsError(conflict.id, params.sourceConnectionId, params.sourceExternalRepositoryId);
17
+ let projectRow;
18
+ for(let attempt = 0; attempt < 2 && !projectRow; attempt += 1){
19
+ try {
20
+ [projectRow] = await tx.insert(projects).values({
21
+ workspaceId: params.workspaceId,
22
+ sourceConnectionId: params.sourceConnectionId,
23
+ sourceExternalRepositoryId: params.sourceExternalRepositoryId,
24
+ name: params.name,
25
+ slug: params.slug
26
+ }).onConflictDoNothing({
27
+ target: [
28
+ projects.sourceConnectionId,
29
+ projects.sourceExternalRepositoryId
30
+ ]
31
+ }).returning();
32
+ } catch (error) {
33
+ if (isUniqueViolation(error, PROJECTS_WORKSPACE_SLUG_UNIQUE_CONSTRAINT)) {
34
+ throw new ProjectSlugConflictError(params.slug);
35
+ }
36
+ throw error;
37
+ }
38
+ if (!projectRow) {
39
+ const [conflict] = await tx.select().from(projects).where(and(eq(projects.sourceConnectionId, params.sourceConnectionId), eq(projects.sourceExternalRepositoryId, params.sourceExternalRepositoryId))).limit(1);
40
+ if (conflict) {
41
+ throw new ProjectAlreadyExistsError(conflict.id, params.sourceConnectionId, params.sourceExternalRepositoryId);
42
+ }
30
43
  }
44
+ }
45
+ if (!projectRow) {
31
46
  throw new Error('Insert returned no rows');
32
47
  }
33
48
  return toProject(projectRow);
@@ -35,6 +50,39 @@ export async function createProject(params) {
35
50
  recordProjectCreated();
36
51
  return project;
37
52
  }
53
+ export async function updateProject(params, options = {}) {
54
+ const executor = options.tx ?? db();
55
+ const [existingRow] = await executor.select().from(projects).where(eq(projects.id, params.projectId)).limit(1);
56
+ if (!existingRow) return undefined;
57
+ const nextName = params.name ?? existingRow.name;
58
+ const nextSlug = params.slug ?? existingRow.slug;
59
+ if (nextName === existingRow.name && nextSlug === existingRow.slug) {
60
+ return {
61
+ project: toProject(existingRow),
62
+ changed: false
63
+ };
64
+ }
65
+ try {
66
+ const [row] = await executor.update(projects).set({
67
+ ...params.name !== undefined ? {
68
+ name: params.name
69
+ } : {},
70
+ ...params.slug !== undefined ? {
71
+ slug: params.slug
72
+ } : {},
73
+ updatedAt: new Date()
74
+ }).where(eq(projects.id, params.projectId)).returning();
75
+ return row ? {
76
+ project: toProject(row),
77
+ changed: true
78
+ } : undefined;
79
+ } catch (error) {
80
+ if (isUniqueViolation(error, PROJECTS_WORKSPACE_SLUG_UNIQUE_CONSTRAINT)) {
81
+ throw new ProjectSlugConflictError(nextSlug);
82
+ }
83
+ throw error;
84
+ }
85
+ }
38
86
  export async function getProjectById(id) {
39
87
  const rows = await db().select().from(projects).where(eq(projects.id, id)).limit(1);
40
88
  const row = rows[0];
@@ -47,12 +95,61 @@ export async function getProjectBySource(params) {
47
95
  if (!row) return undefined;
48
96
  return toProject(row);
49
97
  }
98
+ export async function updateProjectSourceRepository(params) {
99
+ const executor = params.tx ?? db();
100
+ const rows = await executor.update(projects).set({
101
+ sourceRepositoryOwner: params.sourceRepositoryOwner,
102
+ sourceRepositoryName: params.sourceRepositoryName,
103
+ sourceDefaultBranch: params.sourceDefaultBranch,
104
+ updatedAt: new Date()
105
+ }).where(and(eq(projects.workspaceId, params.workspaceId), eq(projects.sourceConnectionId, params.sourceConnectionId), eq(projects.sourceExternalRepositoryId, params.sourceExternalRepositoryId))).returning();
106
+ const row = rows[0];
107
+ if (!row) return undefined;
108
+ return toProject(row);
109
+ }
50
110
  export async function requireProjectForWorkspace(params) {
51
111
  const project = await getProjectById(params.projectId);
52
112
  if (!project) throw new ProjectNotFoundError(params.projectId);
53
113
  if (project.workspaceId !== params.workspaceId) throw new ProjectNotFoundError(params.projectId);
54
114
  return project;
55
115
  }
116
+ export async function updateProjectSourceMetadata(params) {
117
+ await db().update(projects).set({
118
+ sourceConnectionId: params.sourceConnectionId,
119
+ sourceExternalRepositoryId: params.sourceExternalRepositoryId,
120
+ sourceRepositoryOwner: params.sourceRepositoryOwner,
121
+ sourceRepositoryName: params.sourceRepositoryName,
122
+ sourceDefaultBranch: params.sourceDefaultBranch,
123
+ updatedAt: new Date()
124
+ }).where(and(eq(projects.workspaceId, params.workspaceId), eq(projects.id, params.projectId)));
125
+ }
126
+ export async function resolveCheckoutTarget(params) {
127
+ const selection = {
128
+ projectId: projects.id,
129
+ connectionId: projects.sourceConnectionId,
130
+ externalRepositoryId: projects.sourceExternalRepositoryId
131
+ };
132
+ if ('project' in params.target) {
133
+ const [project] = await db().select(selection).from(projects).where(and(eq(projects.workspaceId, params.workspaceId), eq(projects.id, params.target.project))).limit(1);
134
+ return project;
135
+ }
136
+ const separator = params.target.repository.indexOf('/');
137
+ if (separator === 0 || separator === params.target.repository.length - 1) return undefined;
138
+ const repository = separator === -1 ? {
139
+ connectionId: params.target.connection ?? params.defaults.connectionId,
140
+ owner: params.defaults.owner,
141
+ name: params.target.repository
142
+ } : params.target.repository.indexOf('/', separator + 1) === -1 ? {
143
+ connectionId: params.target.connection ?? params.defaults.connectionId,
144
+ owner: params.target.repository.slice(0, separator),
145
+ name: params.target.repository.slice(separator + 1)
146
+ } : undefined;
147
+ if (repository === undefined) return undefined;
148
+ const matches = await db().select(selection).from(projects).where(and(eq(projects.workspaceId, params.workspaceId), eq(projects.sourceConnectionId, repository.connectionId), sql`lower(${projects.sourceRepositoryOwner}) = lower(${repository.owner})`, sql`lower(${projects.sourceRepositoryName}) = lower(${repository.name})`)).limit(2);
149
+ // Owner/name isn't a unique key: renamed or reconnected repositories can leave
150
+ // more than one project row matching. Fail closed instead of picking arbitrarily.
151
+ return matches.length === 1 ? matches[0] : undefined;
152
+ }
56
153
  export async function listProjects(params) {
57
154
  const conditions = [
58
155
  eq(projects.workspaceId, params.workspaceId)
@@ -60,7 +157,8 @@ export async function listProjects(params) {
60
157
  const cursorCondition = cursorWhere(params.cursor);
61
158
  if (cursorCondition) conditions.push(cursorCondition);
62
159
  if (params.search) {
63
- conditions.push(ilike(projects.name, `%${escapeIlikePattern(params.search)}%`));
160
+ const searchPattern = `%${escapeIlikePattern(params.search)}%`;
161
+ conditions.push(or(ilike(projects.name, searchPattern), ilike(projects.slug, searchPattern)));
64
162
  }
65
163
  const rows = await db().select().from(projects).where(and(...conditions)).orderBy(desc(projects.createdAt), desc(projects.id)).limit(params.limit + 1);
66
164
  const hasMore = rows.length > params.limit;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/db/projects.ts"],"sourcesContent":["import {and, count, desc, eq, ilike, inArray, lt, or, type SQL} from 'drizzle-orm';\nimport type {Project} from '#core/entities/project.js';\nimport {ProjectAlreadyExistsError, ProjectNotFoundError} from '#core/errors.js';\nimport {recordProjectCreated} from '#metrics/instance.js';\nimport {db} from './db.js';\nimport {projects, toProject} from './schema/projects.js';\n\nexport interface CreateProjectParams {\n workspaceId: string;\n sourceConnectionId: string;\n sourceExternalRepositoryId: string;\n name: string;\n}\n\nexport interface ProjectCursor {\n createdAt: Date;\n id: string;\n}\n\nexport interface ListProjectsParams {\n workspaceId: string;\n limit: number;\n cursor?: ProjectCursor | undefined;\n search?: string | undefined;\n}\n\nfunction escapeIlikePattern(value: string): string {\n return value.replace(/[\\\\%_]/g, (char) => `\\\\${char}`);\n}\n\nexport interface ListProjectsResult {\n projects: Project[];\n nextCursor: ProjectCursor | null;\n}\n\nexport type AdminProjectSummary = Pick<\n Project,\n 'id' | 'workspaceId' | 'name' | 'createdAt' | 'updatedAt'\n>;\n\nexport interface ListAdminProjectsParams {\n limit: number;\n cursor?: ProjectCursor | undefined;\n projectId?: string | undefined;\n search?: string | undefined;\n}\n\nexport interface ListAdminProjectsResult {\n projects: AdminProjectSummary[];\n nextCursor: ProjectCursor | null;\n}\n\nfunction cursorWhere(cursor: ProjectCursor | undefined): SQL | undefined {\n if (!cursor) return undefined;\n return or(\n lt(projects.createdAt, cursor.createdAt),\n and(eq(projects.createdAt, cursor.createdAt), lt(projects.id, cursor.id)),\n );\n}\n\nexport async function createProject(params: CreateProjectParams): Promise<Project> {\n const project = await db().transaction(async (tx) => {\n const [projectRow] = await tx\n .insert(projects)\n .values({\n workspaceId: params.workspaceId,\n sourceConnectionId: params.sourceConnectionId,\n sourceExternalRepositoryId: params.sourceExternalRepositoryId,\n name: params.name,\n })\n .onConflictDoNothing({\n target: [projects.sourceConnectionId, projects.sourceExternalRepositoryId],\n })\n .returning();\n\n if (!projectRow) {\n const [conflict] = await tx\n .select()\n .from(projects)\n .where(\n and(\n eq(projects.sourceConnectionId, params.sourceConnectionId),\n eq(projects.sourceExternalRepositoryId, params.sourceExternalRepositoryId),\n ),\n )\n .limit(1);\n if (conflict) {\n throw new ProjectAlreadyExistsError(\n conflict.id,\n params.sourceConnectionId,\n params.sourceExternalRepositoryId,\n );\n }\n throw new Error('Insert returned no rows');\n }\n\n return toProject(projectRow);\n });\n recordProjectCreated();\n return project;\n}\n\nexport async function getProjectById(id: string): Promise<Project | undefined> {\n const rows = await db().select().from(projects).where(eq(projects.id, id)).limit(1);\n\n const row = rows[0];\n if (!row) return undefined;\n return toProject(row);\n}\n\nexport interface GetProjectBySourceParams {\n workspaceId: string;\n sourceConnectionId: string;\n sourceExternalRepositoryId: string;\n}\n\nexport async function getProjectBySource(\n params: GetProjectBySourceParams,\n): Promise<Project | undefined> {\n const rows = await db()\n .select()\n .from(projects)\n .where(\n and(\n eq(projects.workspaceId, params.workspaceId),\n eq(projects.sourceConnectionId, params.sourceConnectionId),\n eq(projects.sourceExternalRepositoryId, params.sourceExternalRepositoryId),\n ),\n )\n .limit(1);\n\n const row = rows[0];\n if (!row) return undefined;\n return toProject(row);\n}\n\nexport async function requireProjectForWorkspace(params: {\n projectId: string;\n workspaceId: string;\n}): Promise<Project> {\n const project = await getProjectById(params.projectId);\n if (!project) throw new ProjectNotFoundError(params.projectId);\n if (project.workspaceId !== params.workspaceId) throw new ProjectNotFoundError(params.projectId);\n return project;\n}\n\nexport async function listProjects(params: ListProjectsParams): Promise<ListProjectsResult> {\n const conditions = [eq(projects.workspaceId, params.workspaceId)];\n const cursorCondition = cursorWhere(params.cursor);\n if (cursorCondition) conditions.push(cursorCondition);\n if (params.search) {\n conditions.push(ilike(projects.name, `%${escapeIlikePattern(params.search)}%`));\n }\n\n const rows = await db()\n .select()\n .from(projects)\n .where(and(...conditions))\n .orderBy(desc(projects.createdAt), desc(projects.id))\n .limit(params.limit + 1);\n\n const hasMore = rows.length > params.limit;\n const pageRows = hasMore ? rows.slice(0, params.limit) : rows;\n const last = pageRows.at(-1);\n\n return {\n projects: pageRows.map(toProject),\n nextCursor: hasMore && last ? {createdAt: last.createdAt, id: last.id} : null,\n };\n}\n\nexport async function listAdminProjects(\n params: ListAdminProjectsParams,\n): Promise<ListAdminProjectsResult> {\n const conditions: SQL[] = [];\n const cursorCondition = cursorWhere(params.cursor);\n if (cursorCondition) conditions.push(cursorCondition);\n if (params.projectId) conditions.push(eq(projects.id, params.projectId));\n if (params.search) {\n conditions.push(ilike(projects.name, `%${escapeIlikePattern(params.search)}%`));\n }\n\n const rows = await db()\n .select({\n id: projects.id,\n workspaceId: projects.workspaceId,\n name: projects.name,\n createdAt: projects.createdAt,\n updatedAt: projects.updatedAt,\n })\n .from(projects)\n .where(conditions.length > 0 ? and(...conditions) : undefined)\n .orderBy(desc(projects.createdAt), desc(projects.id))\n .limit(params.limit + 1);\n\n const hasMore = rows.length > params.limit;\n const pageRows = hasMore ? rows.slice(0, params.limit) : rows;\n const last = pageRows.at(-1);\n\n return {\n projects: pageRows,\n nextCursor: hasMore && last ? {createdAt: last.createdAt, id: last.id} : null,\n };\n}\n\nexport async function getProjectCount(): Promise<number> {\n const [row] = await db().select({value: count()}).from(projects);\n return row?.value ?? 0;\n}\n\nexport async function getWorkspaceProjectCounts(params: {\n workspaceIds: string[];\n}): Promise<Array<{workspaceId: string; count: number}>> {\n const rows = await db()\n .select({workspaceId: projects.workspaceId, count: count()})\n .from(projects)\n .where(inArray(projects.workspaceId, params.workspaceIds))\n .groupBy(projects.workspaceId);\n\n const countsByWorkspace = new Map(rows.map((row) => [row.workspaceId, Number(row.count)]));\n return params.workspaceIds.map((workspaceId) => ({\n workspaceId,\n count: countsByWorkspace.get(workspaceId) ?? 0,\n }));\n}\n"],"names":["and","count","desc","eq","ilike","inArray","lt","or","ProjectAlreadyExistsError","ProjectNotFoundError","recordProjectCreated","db","projects","toProject","escapeIlikePattern","value","replace","char","cursorWhere","cursor","undefined","createdAt","id","createProject","params","project","transaction","tx","projectRow","insert","values","workspaceId","sourceConnectionId","sourceExternalRepositoryId","name","onConflictDoNothing","target","returning","conflict","select","from","where","limit","Error","getProjectById","rows","row","getProjectBySource","requireProjectForWorkspace","projectId","listProjects","conditions","cursorCondition","push","search","orderBy","hasMore","length","pageRows","slice","last","at","map","nextCursor","listAdminProjects","updatedAt","getProjectCount","getWorkspaceProjectCounts","workspaceIds","groupBy","countsByWorkspace","Map","Number","get"],"mappings":"AAAA,SAAQA,GAAG,EAAEC,KAAK,EAAEC,IAAI,EAAEC,EAAE,EAAEC,KAAK,EAAEC,OAAO,EAAEC,EAAE,EAAEC,EAAE,QAAiB,cAAc;AAEnF,SAAQC,yBAAyB,EAAEC,oBAAoB,QAAO,kBAAkB;AAChF,SAAQC,oBAAoB,QAAO,uBAAuB;AAC1D,SAAQC,EAAE,QAAO,UAAU;AAC3B,SAAQC,QAAQ,EAAEC,SAAS,QAAO,uBAAuB;AAqBzD,SAASC,mBAAmBC,KAAa;IACvC,OAAOA,MAAMC,OAAO,CAAC,WAAW,CAACC,OAAS,CAAC,EAAE,EAAEA,MAAM;AACvD;AAwBA,SAASC,YAAYC,MAAiC;IACpD,IAAI,CAACA,QAAQ,OAAOC;IACpB,OAAOb,GACLD,GAAGM,SAASS,SAAS,EAAEF,OAAOE,SAAS,GACvCrB,IAAIG,GAAGS,SAASS,SAAS,EAAEF,OAAOE,SAAS,GAAGf,GAAGM,SAASU,EAAE,EAAEH,OAAOG,EAAE;AAE3E;AAEA,OAAO,eAAeC,cAAcC,MAA2B;IAC7D,MAAMC,UAAU,MAAMd,KAAKe,WAAW,CAAC,OAAOC;QAC5C,MAAM,CAACC,WAAW,GAAG,MAAMD,GACxBE,MAAM,CAACjB,UACPkB,MAAM,CAAC;YACNC,aAAaP,OAAOO,WAAW;YAC/BC,oBAAoBR,OAAOQ,kBAAkB;YAC7CC,4BAA4BT,OAAOS,0BAA0B;YAC7DC,MAAMV,OAAOU,IAAI;QACnB,GACCC,mBAAmB,CAAC;YACnBC,QAAQ;gBAACxB,SAASoB,kBAAkB;gBAAEpB,SAASqB,0BAA0B;aAAC;QAC5E,GACCI,SAAS;QAEZ,IAAI,CAACT,YAAY;YACf,MAAM,CAACU,SAAS,GAAG,MAAMX,GACtBY,MAAM,GACNC,IAAI,CAAC5B,UACL6B,KAAK,CACJzC,IACEG,GAAGS,SAASoB,kBAAkB,EAAER,OAAOQ,kBAAkB,GACzD7B,GAAGS,SAASqB,0BAA0B,EAAET,OAAOS,0BAA0B,IAG5ES,KAAK,CAAC;YACT,IAAIJ,UAAU;gBACZ,MAAM,IAAI9B,0BACR8B,SAAShB,EAAE,EACXE,OAAOQ,kBAAkB,EACzBR,OAAOS,0BAA0B;YAErC;YACA,MAAM,IAAIU,MAAM;QAClB;QAEA,OAAO9B,UAAUe;IACnB;IACAlB;IACA,OAAOe;AACT;AAEA,OAAO,eAAemB,eAAetB,EAAU;IAC7C,MAAMuB,OAAO,MAAMlC,KAAK4B,MAAM,GAAGC,IAAI,CAAC5B,UAAU6B,KAAK,CAACtC,GAAGS,SAASU,EAAE,EAAEA,KAAKoB,KAAK,CAAC;IAEjF,MAAMI,MAAMD,IAAI,CAAC,EAAE;IACnB,IAAI,CAACC,KAAK,OAAO1B;IACjB,OAAOP,UAAUiC;AACnB;AAQA,OAAO,eAAeC,mBACpBvB,MAAgC;IAEhC,MAAMqB,OAAO,MAAMlC,KAChB4B,MAAM,GACNC,IAAI,CAAC5B,UACL6B,KAAK,CACJzC,IACEG,GAAGS,SAASmB,WAAW,EAAEP,OAAOO,WAAW,GAC3C5B,GAAGS,SAASoB,kBAAkB,EAAER,OAAOQ,kBAAkB,GACzD7B,GAAGS,SAASqB,0BAA0B,EAAET,OAAOS,0BAA0B,IAG5ES,KAAK,CAAC;IAET,MAAMI,MAAMD,IAAI,CAAC,EAAE;IACnB,IAAI,CAACC,KAAK,OAAO1B;IACjB,OAAOP,UAAUiC;AACnB;AAEA,OAAO,eAAeE,2BAA2BxB,MAGhD;IACC,MAAMC,UAAU,MAAMmB,eAAepB,OAAOyB,SAAS;IACrD,IAAI,CAACxB,SAAS,MAAM,IAAIhB,qBAAqBe,OAAOyB,SAAS;IAC7D,IAAIxB,QAAQM,WAAW,KAAKP,OAAOO,WAAW,EAAE,MAAM,IAAItB,qBAAqBe,OAAOyB,SAAS;IAC/F,OAAOxB;AACT;AAEA,OAAO,eAAeyB,aAAa1B,MAA0B;IAC3D,MAAM2B,aAAa;QAAChD,GAAGS,SAASmB,WAAW,EAAEP,OAAOO,WAAW;KAAE;IACjE,MAAMqB,kBAAkBlC,YAAYM,OAAOL,MAAM;IACjD,IAAIiC,iBAAiBD,WAAWE,IAAI,CAACD;IACrC,IAAI5B,OAAO8B,MAAM,EAAE;QACjBH,WAAWE,IAAI,CAACjD,MAAMQ,SAASsB,IAAI,EAAE,CAAC,CAAC,EAAEpB,mBAAmBU,OAAO8B,MAAM,EAAE,CAAC,CAAC;IAC/E;IAEA,MAAMT,OAAO,MAAMlC,KAChB4B,MAAM,GACNC,IAAI,CAAC5B,UACL6B,KAAK,CAACzC,OAAOmD,aACbI,OAAO,CAACrD,KAAKU,SAASS,SAAS,GAAGnB,KAAKU,SAASU,EAAE,GAClDoB,KAAK,CAAClB,OAAOkB,KAAK,GAAG;IAExB,MAAMc,UAAUX,KAAKY,MAAM,GAAGjC,OAAOkB,KAAK;IAC1C,MAAMgB,WAAWF,UAAUX,KAAKc,KAAK,CAAC,GAAGnC,OAAOkB,KAAK,IAAIG;IACzD,MAAMe,OAAOF,SAASG,EAAE,CAAC,CAAC;IAE1B,OAAO;QACLjD,UAAU8C,SAASI,GAAG,CAACjD;QACvBkD,YAAYP,WAAWI,OAAO;YAACvC,WAAWuC,KAAKvC,SAAS;YAAEC,IAAIsC,KAAKtC,EAAE;QAAA,IAAI;IAC3E;AACF;AAEA,OAAO,eAAe0C,kBACpBxC,MAA+B;IAE/B,MAAM2B,aAAoB,EAAE;IAC5B,MAAMC,kBAAkBlC,YAAYM,OAAOL,MAAM;IACjD,IAAIiC,iBAAiBD,WAAWE,IAAI,CAACD;IACrC,IAAI5B,OAAOyB,SAAS,EAAEE,WAAWE,IAAI,CAAClD,GAAGS,SAASU,EAAE,EAAEE,OAAOyB,SAAS;IACtE,IAAIzB,OAAO8B,MAAM,EAAE;QACjBH,WAAWE,IAAI,CAACjD,MAAMQ,SAASsB,IAAI,EAAE,CAAC,CAAC,EAAEpB,mBAAmBU,OAAO8B,MAAM,EAAE,CAAC,CAAC;IAC/E;IAEA,MAAMT,OAAO,MAAMlC,KAChB4B,MAAM,CAAC;QACNjB,IAAIV,SAASU,EAAE;QACfS,aAAanB,SAASmB,WAAW;QACjCG,MAAMtB,SAASsB,IAAI;QACnBb,WAAWT,SAASS,SAAS;QAC7B4C,WAAWrD,SAASqD,SAAS;IAC/B,GACCzB,IAAI,CAAC5B,UACL6B,KAAK,CAACU,WAAWM,MAAM,GAAG,IAAIzD,OAAOmD,cAAc/B,WACnDmC,OAAO,CAACrD,KAAKU,SAASS,SAAS,GAAGnB,KAAKU,SAASU,EAAE,GAClDoB,KAAK,CAAClB,OAAOkB,KAAK,GAAG;IAExB,MAAMc,UAAUX,KAAKY,MAAM,GAAGjC,OAAOkB,KAAK;IAC1C,MAAMgB,WAAWF,UAAUX,KAAKc,KAAK,CAAC,GAAGnC,OAAOkB,KAAK,IAAIG;IACzD,MAAMe,OAAOF,SAASG,EAAE,CAAC,CAAC;IAE1B,OAAO;QACLjD,UAAU8C;QACVK,YAAYP,WAAWI,OAAO;YAACvC,WAAWuC,KAAKvC,SAAS;YAAEC,IAAIsC,KAAKtC,EAAE;QAAA,IAAI;IAC3E;AACF;AAEA,OAAO,eAAe4C;IACpB,MAAM,CAACpB,IAAI,GAAG,MAAMnC,KAAK4B,MAAM,CAAC;QAACxB,OAAOd;IAAO,GAAGuC,IAAI,CAAC5B;IACvD,OAAOkC,KAAK/B,SAAS;AACvB;AAEA,OAAO,eAAeoD,0BAA0B3C,MAE/C;IACC,MAAMqB,OAAO,MAAMlC,KAChB4B,MAAM,CAAC;QAACR,aAAanB,SAASmB,WAAW;QAAE9B,OAAOA;IAAO,GACzDuC,IAAI,CAAC5B,UACL6B,KAAK,CAACpC,QAAQO,SAASmB,WAAW,EAAEP,OAAO4C,YAAY,GACvDC,OAAO,CAACzD,SAASmB,WAAW;IAE/B,MAAMuC,oBAAoB,IAAIC,IAAI1B,KAAKiB,GAAG,CAAC,CAAChB,MAAQ;YAACA,IAAIf,WAAW;YAAEyC,OAAO1B,IAAI7C,KAAK;SAAE;IACxF,OAAOuB,OAAO4C,YAAY,CAACN,GAAG,CAAC,CAAC/B,cAAiB,CAAA;YAC/CA;YACA9B,OAAOqE,kBAAkBG,GAAG,CAAC1C,gBAAgB;QAC/C,CAAA;AACF"}
1
+ {"version":3,"sources":["../../src/db/projects.ts"],"sourcesContent":["import {isUniqueViolation} from '@shipfox/node-drizzle';\nimport {and, count, desc, eq, ilike, inArray, lt, or, type SQL, sql} from 'drizzle-orm';\nimport type {Project} from '#core/entities/project.js';\nimport {\n ProjectAlreadyExistsError,\n ProjectNotFoundError,\n ProjectSlugConflictError,\n} from '#core/errors.js';\nimport {recordProjectCreated} from '#metrics/instance.js';\nimport {db, type Executor} from './db.js';\nimport {projects, toProject} from './schema/projects.js';\n\ntype ProjectDatabase = ReturnType<typeof db>;\ntype ProjectTransaction = Parameters<Parameters<ProjectDatabase['transaction']>[0]>[0];\n\nexport interface CreateProjectParams {\n workspaceId: string;\n sourceConnectionId: string;\n sourceExternalRepositoryId: string;\n name: string;\n slug: string;\n}\n\nexport interface UpdateProjectParams {\n projectId: string;\n name?: string | undefined;\n slug?: string | undefined;\n}\n\nexport interface UpdateProjectResult {\n project: Project;\n changed: boolean;\n}\n\nexport interface ProjectCursor {\n createdAt: Date;\n id: string;\n}\n\nexport interface ListProjectsParams {\n workspaceId: string;\n limit: number;\n cursor?: ProjectCursor | undefined;\n search?: string | undefined;\n}\n\nfunction escapeIlikePattern(value: string): string {\n return value.replace(/[\\\\%_]/g, (char) => `\\\\${char}`);\n}\n\nexport interface ListProjectsResult {\n projects: Project[];\n nextCursor: ProjectCursor | null;\n}\n\nexport type AdminProjectSummary = Pick<\n Project,\n 'id' | 'workspaceId' | 'name' | 'createdAt' | 'updatedAt'\n>;\n\nexport interface ListAdminProjectsParams {\n limit: number;\n cursor?: ProjectCursor | undefined;\n projectId?: string | undefined;\n search?: string | undefined;\n}\n\nexport interface ListAdminProjectsResult {\n projects: AdminProjectSummary[];\n nextCursor: ProjectCursor | null;\n}\n\nconst PROJECTS_WORKSPACE_SLUG_UNIQUE_CONSTRAINT = 'projects_workspace_slug_unique';\n\nfunction cursorWhere(cursor: ProjectCursor | undefined): SQL | undefined {\n if (!cursor) return undefined;\n return or(\n lt(projects.createdAt, cursor.createdAt),\n and(eq(projects.createdAt, cursor.createdAt), lt(projects.id, cursor.id)),\n );\n}\n\nexport async function createProject(params: CreateProjectParams): Promise<Project> {\n const project = await db().transaction(async (tx) => {\n let projectRow: typeof projects.$inferSelect | undefined;\n for (let attempt = 0; attempt < 2 && !projectRow; attempt += 1) {\n try {\n [projectRow] = await tx\n .insert(projects)\n .values({\n workspaceId: params.workspaceId,\n sourceConnectionId: params.sourceConnectionId,\n sourceExternalRepositoryId: params.sourceExternalRepositoryId,\n name: params.name,\n slug: params.slug,\n })\n .onConflictDoNothing({\n target: [projects.sourceConnectionId, projects.sourceExternalRepositoryId],\n })\n .returning();\n } catch (error) {\n if (isUniqueViolation(error, PROJECTS_WORKSPACE_SLUG_UNIQUE_CONSTRAINT)) {\n throw new ProjectSlugConflictError(params.slug);\n }\n throw error;\n }\n\n if (!projectRow) {\n const [conflict] = await tx\n .select()\n .from(projects)\n .where(\n and(\n eq(projects.sourceConnectionId, params.sourceConnectionId),\n eq(projects.sourceExternalRepositoryId, params.sourceExternalRepositoryId),\n ),\n )\n .limit(1);\n if (conflict) {\n throw new ProjectAlreadyExistsError(\n conflict.id,\n params.sourceConnectionId,\n params.sourceExternalRepositoryId,\n );\n }\n }\n }\n\n if (!projectRow) {\n throw new Error('Insert returned no rows');\n }\n\n return toProject(projectRow);\n });\n recordProjectCreated();\n return project;\n}\n\nexport async function updateProject(\n params: UpdateProjectParams,\n options: {tx?: ProjectDatabase | ProjectTransaction | undefined} = {},\n): Promise<UpdateProjectResult | undefined> {\n const executor = options.tx ?? db();\n\n const [existingRow] = await executor\n .select()\n .from(projects)\n .where(eq(projects.id, params.projectId))\n .limit(1);\n if (!existingRow) return undefined;\n\n const nextName = params.name ?? existingRow.name;\n const nextSlug = params.slug ?? existingRow.slug;\n if (nextName === existingRow.name && nextSlug === existingRow.slug) {\n return {project: toProject(existingRow), changed: false};\n }\n\n try {\n const [row] = await executor\n .update(projects)\n .set({\n ...(params.name !== undefined ? {name: params.name} : {}),\n ...(params.slug !== undefined ? {slug: params.slug} : {}),\n updatedAt: new Date(),\n })\n .where(eq(projects.id, params.projectId))\n .returning();\n\n return row ? {project: toProject(row), changed: true} : undefined;\n } catch (error) {\n if (isUniqueViolation(error, PROJECTS_WORKSPACE_SLUG_UNIQUE_CONSTRAINT)) {\n throw new ProjectSlugConflictError(nextSlug);\n }\n throw error;\n }\n}\n\nexport async function getProjectById(id: string): Promise<Project | undefined> {\n const rows = await db().select().from(projects).where(eq(projects.id, id)).limit(1);\n\n const row = rows[0];\n if (!row) return undefined;\n return toProject(row);\n}\n\nexport interface GetProjectBySourceParams {\n workspaceId: string;\n sourceConnectionId: string;\n sourceExternalRepositoryId: string;\n}\n\nexport async function getProjectBySource(\n params: GetProjectBySourceParams,\n): Promise<Project | undefined> {\n const rows = await db()\n .select()\n .from(projects)\n .where(\n and(\n eq(projects.workspaceId, params.workspaceId),\n eq(projects.sourceConnectionId, params.sourceConnectionId),\n eq(projects.sourceExternalRepositoryId, params.sourceExternalRepositoryId),\n ),\n )\n .limit(1);\n\n const row = rows[0];\n if (!row) return undefined;\n return toProject(row);\n}\n\nexport interface UpdateProjectSourceRepositoryParams extends GetProjectBySourceParams {\n tx?: Executor;\n sourceRepositoryOwner: string;\n sourceRepositoryName: string;\n sourceDefaultBranch: string;\n}\n\nexport async function updateProjectSourceRepository(\n params: UpdateProjectSourceRepositoryParams,\n): Promise<Project | undefined> {\n const executor = params.tx ?? db();\n const rows = await executor\n .update(projects)\n .set({\n sourceRepositoryOwner: params.sourceRepositoryOwner,\n sourceRepositoryName: params.sourceRepositoryName,\n sourceDefaultBranch: params.sourceDefaultBranch,\n updatedAt: new Date(),\n })\n .where(\n and(\n eq(projects.workspaceId, params.workspaceId),\n eq(projects.sourceConnectionId, params.sourceConnectionId),\n eq(projects.sourceExternalRepositoryId, params.sourceExternalRepositoryId),\n ),\n )\n .returning();\n\n const row = rows[0];\n if (!row) return undefined;\n return toProject(row);\n}\n\nexport async function requireProjectForWorkspace(params: {\n projectId: string;\n workspaceId: string;\n}): Promise<Project> {\n const project = await getProjectById(params.projectId);\n if (!project) throw new ProjectNotFoundError(params.projectId);\n if (project.workspaceId !== params.workspaceId) throw new ProjectNotFoundError(params.projectId);\n return project;\n}\n\nexport interface ResolveCheckoutTargetParams {\n workspaceId: string;\n defaults: {\n connectionId: string;\n owner: string;\n };\n target: {project: string} | {connection?: string | undefined; repository: string};\n}\n\nexport interface ResolvedCheckoutTarget {\n projectId: string;\n connectionId: string;\n externalRepositoryId: string;\n}\n\nexport interface UpdateProjectSourceMetadataParams {\n workspaceId: string;\n projectId: string;\n sourceConnectionId: string;\n sourceExternalRepositoryId: string;\n sourceRepositoryOwner: string;\n sourceRepositoryName: string;\n sourceDefaultBranch: string;\n}\n\nexport async function updateProjectSourceMetadata(\n params: UpdateProjectSourceMetadataParams,\n): Promise<void> {\n await db()\n .update(projects)\n .set({\n sourceConnectionId: params.sourceConnectionId,\n sourceExternalRepositoryId: params.sourceExternalRepositoryId,\n sourceRepositoryOwner: params.sourceRepositoryOwner,\n sourceRepositoryName: params.sourceRepositoryName,\n sourceDefaultBranch: params.sourceDefaultBranch,\n updatedAt: new Date(),\n })\n .where(and(eq(projects.workspaceId, params.workspaceId), eq(projects.id, params.projectId)));\n}\n\nexport async function resolveCheckoutTarget(\n params: ResolveCheckoutTargetParams,\n): Promise<ResolvedCheckoutTarget | undefined> {\n const selection = {\n projectId: projects.id,\n connectionId: projects.sourceConnectionId,\n externalRepositoryId: projects.sourceExternalRepositoryId,\n };\n\n if ('project' in params.target) {\n const [project] = await db()\n .select(selection)\n .from(projects)\n .where(\n and(eq(projects.workspaceId, params.workspaceId), eq(projects.id, params.target.project)),\n )\n .limit(1);\n return project;\n }\n\n const separator = params.target.repository.indexOf('/');\n if (separator === 0 || separator === params.target.repository.length - 1) return undefined;\n\n const repository =\n separator === -1\n ? {\n connectionId: params.target.connection ?? params.defaults.connectionId,\n owner: params.defaults.owner,\n name: params.target.repository,\n }\n : params.target.repository.indexOf('/', separator + 1) === -1\n ? {\n connectionId: params.target.connection ?? params.defaults.connectionId,\n owner: params.target.repository.slice(0, separator),\n name: params.target.repository.slice(separator + 1),\n }\n : undefined;\n if (repository === undefined) return undefined;\n\n const matches = await db()\n .select(selection)\n .from(projects)\n .where(\n and(\n eq(projects.workspaceId, params.workspaceId),\n eq(projects.sourceConnectionId, repository.connectionId),\n sql`lower(${projects.sourceRepositoryOwner}) = lower(${repository.owner})`,\n sql`lower(${projects.sourceRepositoryName}) = lower(${repository.name})`,\n ),\n )\n .limit(2);\n\n // Owner/name isn't a unique key: renamed or reconnected repositories can leave\n // more than one project row matching. Fail closed instead of picking arbitrarily.\n return matches.length === 1 ? matches[0] : undefined;\n}\n\nexport async function listProjects(params: ListProjectsParams): Promise<ListProjectsResult> {\n const conditions = [eq(projects.workspaceId, params.workspaceId)];\n const cursorCondition = cursorWhere(params.cursor);\n if (cursorCondition) conditions.push(cursorCondition);\n if (params.search) {\n const searchPattern = `%${escapeIlikePattern(params.search)}%`;\n conditions.push(\n or(ilike(projects.name, searchPattern), ilike(projects.slug, searchPattern)) as SQL,\n );\n }\n\n const rows = await db()\n .select()\n .from(projects)\n .where(and(...conditions))\n .orderBy(desc(projects.createdAt), desc(projects.id))\n .limit(params.limit + 1);\n\n const hasMore = rows.length > params.limit;\n const pageRows = hasMore ? rows.slice(0, params.limit) : rows;\n const last = pageRows.at(-1);\n\n return {\n projects: pageRows.map(toProject),\n nextCursor: hasMore && last ? {createdAt: last.createdAt, id: last.id} : null,\n };\n}\n\nexport async function listAdminProjects(\n params: ListAdminProjectsParams,\n): Promise<ListAdminProjectsResult> {\n const conditions: SQL[] = [];\n const cursorCondition = cursorWhere(params.cursor);\n if (cursorCondition) conditions.push(cursorCondition);\n if (params.projectId) conditions.push(eq(projects.id, params.projectId));\n if (params.search) {\n conditions.push(ilike(projects.name, `%${escapeIlikePattern(params.search)}%`));\n }\n\n const rows = await db()\n .select({\n id: projects.id,\n workspaceId: projects.workspaceId,\n name: projects.name,\n createdAt: projects.createdAt,\n updatedAt: projects.updatedAt,\n })\n .from(projects)\n .where(conditions.length > 0 ? and(...conditions) : undefined)\n .orderBy(desc(projects.createdAt), desc(projects.id))\n .limit(params.limit + 1);\n\n const hasMore = rows.length > params.limit;\n const pageRows = hasMore ? rows.slice(0, params.limit) : rows;\n const last = pageRows.at(-1);\n\n return {\n projects: pageRows,\n nextCursor: hasMore && last ? {createdAt: last.createdAt, id: last.id} : null,\n };\n}\n\nexport async function getProjectCount(): Promise<number> {\n const [row] = await db().select({value: count()}).from(projects);\n return row?.value ?? 0;\n}\n\nexport async function getWorkspaceProjectCounts(params: {\n workspaceIds: string[];\n}): Promise<Array<{workspaceId: string; count: number}>> {\n const rows = await db()\n .select({workspaceId: projects.workspaceId, count: count()})\n .from(projects)\n .where(inArray(projects.workspaceId, params.workspaceIds))\n .groupBy(projects.workspaceId);\n\n const countsByWorkspace = new Map(rows.map((row) => [row.workspaceId, Number(row.count)]));\n return params.workspaceIds.map((workspaceId) => ({\n workspaceId,\n count: countsByWorkspace.get(workspaceId) ?? 0,\n }));\n}\n"],"names":["isUniqueViolation","and","count","desc","eq","ilike","inArray","lt","or","sql","ProjectAlreadyExistsError","ProjectNotFoundError","ProjectSlugConflictError","recordProjectCreated","db","projects","toProject","escapeIlikePattern","value","replace","char","PROJECTS_WORKSPACE_SLUG_UNIQUE_CONSTRAINT","cursorWhere","cursor","undefined","createdAt","id","createProject","params","project","transaction","tx","projectRow","attempt","insert","values","workspaceId","sourceConnectionId","sourceExternalRepositoryId","name","slug","onConflictDoNothing","target","returning","error","conflict","select","from","where","limit","Error","updateProject","options","executor","existingRow","projectId","nextName","nextSlug","changed","row","update","set","updatedAt","Date","getProjectById","rows","getProjectBySource","updateProjectSourceRepository","sourceRepositoryOwner","sourceRepositoryName","sourceDefaultBranch","requireProjectForWorkspace","updateProjectSourceMetadata","resolveCheckoutTarget","selection","connectionId","externalRepositoryId","separator","repository","indexOf","length","connection","defaults","owner","slice","matches","listProjects","conditions","cursorCondition","push","search","searchPattern","orderBy","hasMore","pageRows","last","at","map","nextCursor","listAdminProjects","getProjectCount","getWorkspaceProjectCounts","workspaceIds","groupBy","countsByWorkspace","Map","Number","get"],"mappings":"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"}