@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
@@ -1,6 +1,6 @@
1
1
  $ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
2
- Successfully compiled: 37 files with swc (413.68ms)
3
- 2026-07-28T22:45:34.926Z [INFO] asset workflow-bundle-601f98c1048b285735c6.js 3.17 MiB [emitted] [immutable] (name: main)
2
+ Successfully compiled: 39 files with swc (449.23ms)
3
+ 2026-08-06T13:12:47.464Z [INFO] asset workflow-bundle-601f98c1048b285735c6.js 3.17 MiB [emitted] [immutable] (name: main)
4
4
  orphan modules 33.5 KiB [orphan] 21 modules
5
5
  runtime modules 1.13 KiB 5 modules
6
6
  modules by path ../../../node_modules/.pnpm/ 970 KiB 196 modules
@@ -12,6 +12,6 @@ optional modules 30 bytes [optional]
12
12
  __temporal_custom_payload_converter (ignored) 15 bytes [optional] [built] [code generated]
13
13
  __temporal_custom_failure_converter (ignored) 15 bytes [optional] [built] [code generated]
14
14
  ../../shared/node/temporal/dist/workflow-error-interceptor.js 1.21 KiB [built] [code generated]
15
- webpack 5.107.2 compiled successfully in 7385 ms
16
- 2026-07-28T22:45:34.932Z [INFO] Workflow bundle created { size: '3.17MB' }
15
+ webpack 5.107.2 compiled successfully in 8227 ms
16
+ 2026-08-06T13:12:47.497Z [INFO] Workflow bundle created { size: '3.17MB' }
17
17
  /home/runner/work/shipfox/shipfox/libs/api/projects/dist/temporal/workflows/index.js: 3319553 bytes
package/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # @shipfox/api-projects
2
2
 
3
+ ## 12.2.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 7901a60: Retry workspace workflow definition syncs when an integration connection becomes available.
8
+ - Updated dependencies [7901a60]
9
+ - @shipfox/api-integration-core-dto@12.2.0
10
+ - @shipfox/api-projects-dto@12.2.0
11
+ - @shipfox/node-opentelemetry@0.6.4
12
+ - @shipfox/node-fastify@0.4.2
13
+ - @shipfox/node-module@1.0.6
14
+ - @shipfox/node-temporal@0.4.5
15
+ - @shipfox/api-auth-context@12.2.0
16
+
17
+ ## 12.0.0
18
+
19
+ ### Major Changes
20
+
21
+ - 4eb18b8: Add required, workspace-scoped project slugs across the API and project creation form.
22
+
23
+ ### Minor Changes
24
+
25
+ - 8cc5a36: Add a `resolveCheckoutTarget` inter-module method. It resolves a project by ID
26
+ or by owner and repository within a workspace for callers that authorize a
27
+ checkout target.
28
+ - cb0abfa: Expose the normalized trigger project, repository, ref, and commit in workflow context.
29
+
30
+ ### Patch Changes
31
+
32
+ - e405e92: Move client routes to slug-based `/w/$workspaceSlug` and `/p/$projectSlug` URLs, enforce the new composition contract, and support bounded project-slug resolution.
33
+ - 869a792: Refresh source-backed project repository identity from GitHub repository and installation-repository events.
34
+ - a0a02cc: Store normalized repository identity on source-backed projects.
35
+ - Updated dependencies [f78740d]
36
+ - Updated dependencies [4eb18b8]
37
+ - Updated dependencies [f13e8bb]
38
+ - Updated dependencies [869a792]
39
+ - Updated dependencies [8cc5a36]
40
+ - Updated dependencies [34a5639]
41
+ - Updated dependencies [032d316]
42
+ - Updated dependencies [54c820e]
43
+ - Updated dependencies [cb0abfa]
44
+ - @shipfox/api-auth-dto@12.0.0
45
+ - @shipfox/api-common-dto@12.0.0
46
+ - @shipfox/inter-module@0.2.3
47
+ - @shipfox/node-fastify@0.4.1
48
+ - @shipfox/node-module@1.0.5
49
+ - @shipfox/api-projects-dto@12.0.0
50
+ - @shipfox/api-integration-core-dto@12.0.0
51
+ - @shipfox/node-postgres@0.5.0
52
+ - @shipfox/api-auth-context@12.0.0
53
+ - @shipfox/node-drizzle@0.3.5
54
+ - @shipfox/node-outbox@0.2.6
55
+
3
56
  ## 11.0.0
4
57
 
5
58
  ### Patch Changes
package/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # Shipfox API Projects
2
+
3
+ Shipfox API Projects manages project resources and their source repository bindings.
4
+
5
+ ## What it does
6
+
7
+ - **`createProjectFromSource`**: Creates a project from a repository in an integration connection.
8
+ - **`updateProjectDetails`**: Changes a project's name or slug and writes the update event.
9
+ - **`createProjectRoutes`**: Mounts project and administrator HTTP routes.
10
+ - **`Project`**: Represents the project identity, URL slug, source repository, and timestamps.
11
+
12
+ ## Installation / Setup
13
+
14
+ ```sh
15
+ pnpm add @shipfox/api-projects
16
+ ```
17
+
18
+ The module needs an integrations client to resolve the source integration
19
+ connection and an Auth client for module setup.
20
+
21
+ ## Usage
22
+
23
+ ```ts
24
+ import {createProjectFromSource} from '@shipfox/api-projects';
25
+
26
+ const project = await createProjectFromSource({
27
+ actorId,
28
+ workspaceId,
29
+ name: 'Checkout API',
30
+ slug: 'checkout-api',
31
+ sourceConnectionId,
32
+ sourceExternalRepositoryId,
33
+ integrations,
34
+ });
35
+ ```
36
+
37
+ ## Routes / API / Data Model
38
+
39
+ Routes mount under `/projects` and use UUIDs for resource identity:
40
+
41
+ | Method | Path | Purpose |
42
+ | --- | --- | --- |
43
+ | `POST` | `/projects` | Create a project from a source repository. |
44
+ | `GET` | `/projects?workspace_id=<workspaceId>` | List projects in a workspace. |
45
+ | `GET` | `/projects/<projectId>` | Read one project. |
46
+ | `PATCH` | `/projects/<projectId>` | Update a project's name or slug. |
47
+
48
+ The create and update bodies carry the mutable `slug` field. A project slug is
49
+ unique within its workspace. A duplicate returns `409 slug-conflict`, while a
50
+ repository already bound to a project returns the separate
51
+ `409 project-already-exists` error.
52
+
53
+ | Field | Constraint | Use |
54
+ | --- | --- | --- |
55
+ | `id` | UUID, stable | API resource identity |
56
+ | `workspace_id` | UUID | Workspace ownership |
57
+ | `name` | Required display text | Project label |
58
+ | `slug` | Required, unique within `workspace_id` | Client navigation and display |
59
+ | `source` | Integration connection and repository identifiers | Source binding |
60
+
61
+ Project slugs are navigation values. The API does not resolve a project from a
62
+ slug in a resource path or query. The client resolves a project slug from its
63
+ workspace project list, then sends the UUID to the API.
64
+
65
+ ## Behavior Notes
66
+
67
+ The create form derives an editable default slug from the project name. The API
68
+ requires an explicit slug and never adds a suffix when the value is taken. A
69
+ rename frees the old slug immediately and emits a project-updated outbox event.
70
+
71
+ ## Development
72
+
73
+ ```sh
74
+ turbo check --filter=@shipfox/api-projects
75
+ turbo type --filter=@shipfox/api-projects
76
+ turbo test --filter=@shipfox/api-projects
77
+ ```
78
+
79
+ For repository test conventions, read the [testing guide](../../../docs/guides/testing.md).
80
+
81
+ ## License
82
+
83
+ MIT
@@ -3,7 +3,11 @@ export interface Project {
3
3
  workspaceId: string;
4
4
  sourceConnectionId: string;
5
5
  sourceExternalRepositoryId: string;
6
+ sourceRepositoryOwner: string | null;
7
+ sourceRepositoryName: string | null;
8
+ sourceDefaultBranch: string | null;
6
9
  name: string;
10
+ slug: string;
7
11
  createdAt: Date;
8
12
  updatedAt: Date;
9
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../../src/core/entities/project.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0BAA0B,EAAE,MAAM,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB"}
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../../src/core/entities/project.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0BAA0B,EAAE,MAAM,CAAC;IACnC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/entities/project.ts"],"sourcesContent":["export interface Project {\n id: string;\n workspaceId: string;\n sourceConnectionId: string;\n sourceExternalRepositoryId: string;\n name: string;\n createdAt: Date;\n updatedAt: Date;\n}\n"],"names":[],"mappings":"AAAA,WAQC"}
1
+ {"version":3,"sources":["../../../src/core/entities/project.ts"],"sourcesContent":["export interface Project {\n id: string;\n workspaceId: string;\n sourceConnectionId: string;\n sourceExternalRepositoryId: string;\n sourceRepositoryOwner: string | null;\n sourceRepositoryName: string | null;\n sourceDefaultBranch: string | null;\n name: string;\n slug: string;\n createdAt: Date;\n updatedAt: Date;\n}\n"],"names":[],"mappings":"AAAA,WAYC"}
@@ -10,4 +10,8 @@ export declare class ProjectAlreadyExistsError extends Error {
10
10
  readonly sourceExternalRepositoryId: string;
11
11
  constructor(existingProjectId: string, sourceConnectionId: string, sourceExternalRepositoryId: string);
12
12
  }
13
+ export declare class ProjectSlugConflictError extends Error {
14
+ readonly slug: string;
15
+ constructor(slug: string);
16
+ }
13
17
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,SAAS,EAAE,MAAM;CAI9B;AAED,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,SAAS,EAAE,MAAM;CAI9B;AAED,qBAAa,yBAA0B,SAAQ,KAAK;aAEhC,iBAAiB,EAAE,MAAM;aACzB,kBAAkB,EAAE,MAAM;aAC1B,0BAA0B,EAAE,MAAM;gBAFlC,iBAAiB,EAAE,MAAM,EACzB,kBAAkB,EAAE,MAAM,EAC1B,0BAA0B,EAAE,MAAM;CAOrD"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,SAAS,EAAE,MAAM,EAG5B;CACF;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,YAAY,SAAS,EAAE,MAAM,EAG5B;CACF;AAED,qBAAa,yBAA0B,SAAQ,KAAK;aAEhC,iBAAiB,EAAE,MAAM;aACzB,kBAAkB,EAAE,MAAM;aAC1B,0BAA0B,EAAE,MAAM;IAHpD,YACkB,iBAAiB,EAAE,MAAM,EACzB,kBAAkB,EAAE,MAAM,EAC1B,0BAA0B,EAAE,MAAM,EAMnD;CACF;AAED,qBAAa,wBAAyB,SAAQ,KAAK;aACrB,IAAI,EAAE,MAAM;IAAxC,YAA4B,IAAI,EAAE,MAAM,EAGvC;CACF"}
@@ -16,5 +16,11 @@ export class ProjectAlreadyExistsError extends Error {
16
16
  this.name = 'ProjectAlreadyExistsError';
17
17
  }
18
18
  }
19
+ export class ProjectSlugConflictError extends Error {
20
+ constructor(slug){
21
+ super(`Project slug already exists: ${slug}`), this.slug = slug;
22
+ this.name = 'ProjectSlugConflictError';
23
+ }
24
+ }
19
25
 
20
26
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/errors.ts"],"sourcesContent":["export class ProjectNotFoundError extends Error {\n constructor(projectId: string) {\n super(`Project not found: ${projectId}`);\n this.name = 'ProjectNotFoundError';\n }\n}\n\nexport class ProjectAccessDeniedError extends Error {\n constructor(projectId: string) {\n super(`Access denied for project: ${projectId}`);\n this.name = 'ProjectAccessDeniedError';\n }\n}\n\nexport class ProjectAlreadyExistsError extends Error {\n constructor(\n public readonly existingProjectId: string,\n public readonly sourceConnectionId: string,\n public readonly sourceExternalRepositoryId: string,\n ) {\n super(\n `Project already exists for source repository: ${sourceConnectionId}/${sourceExternalRepositoryId}`,\n );\n this.name = 'ProjectAlreadyExistsError';\n }\n}\n"],"names":["ProjectNotFoundError","Error","projectId","name","ProjectAccessDeniedError","ProjectAlreadyExistsError","existingProjectId","sourceConnectionId","sourceExternalRepositoryId"],"mappings":"AAAA,OAAO,MAAMA,6BAA6BC;IACxC,YAAYC,SAAiB,CAAE;QAC7B,KAAK,CAAC,CAAC,mBAAmB,EAAEA,WAAW;QACvC,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMC,iCAAiCH;IAC5C,YAAYC,SAAiB,CAAE;QAC7B,KAAK,CAAC,CAAC,2BAA2B,EAAEA,WAAW;QAC/C,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAME,kCAAkCJ;IAC7C,YACE,AAAgBK,iBAAyB,EACzC,AAAgBC,kBAA0B,EAC1C,AAAgBC,0BAAkC,CAClD;QACA,KAAK,CACH,CAAC,8CAA8C,EAAED,mBAAmB,CAAC,EAAEC,4BAA4B,QALrFF,oBAAAA,wBACAC,qBAAAA,yBACAC,6BAAAA;QAKhB,IAAI,CAACL,IAAI,GAAG;IACd;AACF"}
1
+ {"version":3,"sources":["../../src/core/errors.ts"],"sourcesContent":["export class ProjectNotFoundError extends Error {\n constructor(projectId: string) {\n super(`Project not found: ${projectId}`);\n this.name = 'ProjectNotFoundError';\n }\n}\n\nexport class ProjectAccessDeniedError extends Error {\n constructor(projectId: string) {\n super(`Access denied for project: ${projectId}`);\n this.name = 'ProjectAccessDeniedError';\n }\n}\n\nexport class ProjectAlreadyExistsError extends Error {\n constructor(\n public readonly existingProjectId: string,\n public readonly sourceConnectionId: string,\n public readonly sourceExternalRepositoryId: string,\n ) {\n super(\n `Project already exists for source repository: ${sourceConnectionId}/${sourceExternalRepositoryId}`,\n );\n this.name = 'ProjectAlreadyExistsError';\n }\n}\n\nexport class ProjectSlugConflictError extends Error {\n constructor(public readonly slug: string) {\n super(`Project slug already exists: ${slug}`);\n this.name = 'ProjectSlugConflictError';\n }\n}\n"],"names":["ProjectNotFoundError","Error","projectId","name","ProjectAccessDeniedError","ProjectAlreadyExistsError","existingProjectId","sourceConnectionId","sourceExternalRepositoryId","ProjectSlugConflictError","slug"],"mappings":"AAAA,OAAO,MAAMA,6BAA6BC;IACxC,YAAYC,SAAiB,CAAE;QAC7B,KAAK,CAAC,CAAC,mBAAmB,EAAEA,WAAW;QACvC,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMC,iCAAiCH;IAC5C,YAAYC,SAAiB,CAAE;QAC7B,KAAK,CAAC,CAAC,2BAA2B,EAAEA,WAAW;QAC/C,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAME,kCAAkCJ;IAC7C,YACE,AAAgBK,iBAAyB,EACzC,AAAgBC,kBAA0B,EAC1C,AAAgBC,0BAAkC,CAClD;QACA,KAAK,CACH,CAAC,8CAA8C,EAAED,mBAAmB,CAAC,EAAEC,4BAA4B,QALrFF,oBAAAA,wBACAC,qBAAAA,yBACAC,6BAAAA;QAKhB,IAAI,CAACL,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMM,iCAAiCR;IAC5C,YAAY,AAAgBS,IAAY,CAAE;QACxC,KAAK,CAAC,CAAC,6BAA6B,EAAEA,MAAM,QADlBA,OAAAA;QAE1B,IAAI,CAACP,IAAI,GAAG;IACd;AACF"}
@@ -1,5 +1,5 @@
1
1
  export type * from './entities/index.js';
2
- export { ProjectAccessDeniedError, ProjectAlreadyExistsError, ProjectNotFoundError, } from './errors.js';
3
- export type { CreateProjectFromSourceParams } from './projects.js';
4
- export { createProjectFromSource } from './projects.js';
2
+ export { ProjectAccessDeniedError, ProjectAlreadyExistsError, ProjectNotFoundError, ProjectSlugConflictError, } from './errors.js';
3
+ export type { CreateProjectFromSourceParams, UpdateProjectDetailsParams } from './projects.js';
4
+ export { createProjectFromSource, updateProjectDetails } from './projects.js';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,qBAAqB,CAAC;AACzC,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAC,6BAA6B,EAAC,MAAM,eAAe,CAAC;AACjE,OAAO,EAAC,uBAAuB,EAAC,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,qBAAqB,CAAC;AACzC,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAC,6BAA6B,EAAE,0BAA0B,EAAC,MAAM,eAAe,CAAC;AAC7F,OAAO,EAAC,uBAAuB,EAAE,oBAAoB,EAAC,MAAM,eAAe,CAAC"}
@@ -1,4 +1,4 @@
1
- export { ProjectAccessDeniedError, ProjectAlreadyExistsError, ProjectNotFoundError } from './errors.js';
2
- export { createProjectFromSource } from './projects.js';
1
+ export { ProjectAccessDeniedError, ProjectAlreadyExistsError, ProjectNotFoundError, ProjectSlugConflictError } from './errors.js';
2
+ export { createProjectFromSource, updateProjectDetails } from './projects.js';
3
3
 
4
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/index.ts"],"sourcesContent":["export type * from './entities/index.js';\nexport {\n ProjectAccessDeniedError,\n ProjectAlreadyExistsError,\n ProjectNotFoundError,\n} from './errors.js';\nexport type {CreateProjectFromSourceParams} from './projects.js';\nexport {createProjectFromSource} from './projects.js';\n"],"names":["ProjectAccessDeniedError","ProjectAlreadyExistsError","ProjectNotFoundError","createProjectFromSource"],"mappings":"AACA,SACEA,wBAAwB,EACxBC,yBAAyB,EACzBC,oBAAoB,QACf,cAAc;AAErB,SAAQC,uBAAuB,QAAO,gBAAgB"}
1
+ {"version":3,"sources":["../../src/core/index.ts"],"sourcesContent":["export type * from './entities/index.js';\nexport {\n ProjectAccessDeniedError,\n ProjectAlreadyExistsError,\n ProjectNotFoundError,\n ProjectSlugConflictError,\n} from './errors.js';\nexport type {CreateProjectFromSourceParams, UpdateProjectDetailsParams} from './projects.js';\nexport {createProjectFromSource, updateProjectDetails} from './projects.js';\n"],"names":["ProjectAccessDeniedError","ProjectAlreadyExistsError","ProjectNotFoundError","ProjectSlugConflictError","createProjectFromSource","updateProjectDetails"],"mappings":"AACA,SACEA,wBAAwB,EACxBC,yBAAyB,EACzBC,oBAAoB,EACpBC,wBAAwB,QACnB,cAAc;AAErB,SAAQC,uBAAuB,EAAEC,oBAAoB,QAAO,gBAAgB"}
@@ -6,7 +6,15 @@ export interface CreateProjectFromSourceParams {
6
6
  name: string;
7
7
  sourceConnectionId: string;
8
8
  sourceExternalRepositoryId: string;
9
+ slug: string;
9
10
  integrations: IntegrationsModuleClient;
10
11
  }
11
12
  export declare function createProjectFromSource(params: CreateProjectFromSourceParams): Promise<Project>;
13
+ export interface UpdateProjectDetailsParams {
14
+ actorId: string;
15
+ projectId: string;
16
+ name?: string | undefined;
17
+ slug?: string | undefined;
18
+ }
19
+ export declare function updateProjectDetails(params: UpdateProjectDetailsParams): Promise<Project>;
12
20
  //# sourceMappingURL=projects.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/core/projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,gDAAgD,CAAC;AAY7F,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAGnD,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0BAA0B,EAAE,MAAM,CAAC;IACnC,YAAY,EAAE,wBAAwB,CAAC;CACxC;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,OAAO,CAAC,CA0ElB"}
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/core/projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,gDAAgD,CAAC;AAe7F,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AASnD,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0BAA0B,EAAE,MAAM,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,wBAAwB,CAAC;CACxC;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,OAAO,CAAC,CAwFlB;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,0BAA0B,GAAG,OAAO,CAAC,OAAO,CAAC,CAsBzF"}
@@ -1,35 +1,53 @@
1
- import { PROJECT_CREATED, PROJECT_SOURCE_BOUND } from '@shipfox/api-projects-dto';
1
+ import { PROJECT_CREATED, PROJECT_SOURCE_BOUND, PROJECT_UPDATED } from '@shipfox/api-projects-dto';
2
+ import { isUniqueViolation } from '@shipfox/node-drizzle';
2
3
  import { writeOutboxEvent } from '@shipfox/node-outbox';
3
4
  import { and, eq } from 'drizzle-orm';
4
5
  import { db } from '#db/db.js';
6
+ import { updateProject } from '#db/projects.js';
5
7
  import { projectsOutbox } from '#db/schema/outbox.js';
6
8
  import { projects, toProject } from '#db/schema/projects.js';
7
9
  import { recordProjectCreated } from '#metrics/instance.js';
8
- import { ProjectAlreadyExistsError } from './errors.js';
10
+ import { ProjectAlreadyExistsError, ProjectNotFoundError, ProjectSlugConflictError } from './errors.js';
11
+ const PROJECTS_WORKSPACE_SLUG_UNIQUE_CONSTRAINT = 'projects_workspace_slug_unique';
9
12
  export async function createProjectFromSource(params) {
10
- let source;
11
- source = await params.integrations.resolveSourceRepository({
13
+ const source = await params.integrations.resolveSourceRepository({
12
14
  workspaceId: params.workspaceId,
13
15
  connectionId: params.sourceConnectionId,
14
16
  externalRepositoryId: params.sourceExternalRepositoryId
15
17
  });
16
18
  const project = await db().transaction(async (tx)=>{
17
- const [projectRow] = await tx.insert(projects).values({
18
- workspaceId: params.workspaceId,
19
- sourceConnectionId: source.connection.id,
20
- sourceExternalRepositoryId: source.repository.externalRepositoryId,
21
- name: params.name
22
- }).onConflictDoNothing({
23
- target: [
24
- projects.sourceConnectionId,
25
- projects.sourceExternalRepositoryId
26
- ]
27
- }).returning();
28
- if (!projectRow) {
29
- const [existing] = await tx.select().from(projects).where(and(eq(projects.sourceConnectionId, source.connection.id), eq(projects.sourceExternalRepositoryId, source.repository.externalRepositoryId))).limit(1);
30
- if (existing) {
31
- throw new ProjectAlreadyExistsError(existing.id, source.connection.id, source.repository.externalRepositoryId);
19
+ let projectRow;
20
+ for(let attempt = 0; attempt < 2 && !projectRow; attempt += 1){
21
+ try {
22
+ [projectRow] = await tx.insert(projects).values({
23
+ workspaceId: params.workspaceId,
24
+ sourceConnectionId: source.connection.id,
25
+ sourceExternalRepositoryId: source.repository.externalRepositoryId,
26
+ sourceRepositoryOwner: source.repository.owner,
27
+ sourceRepositoryName: source.repository.name,
28
+ sourceDefaultBranch: source.repository.defaultBranch,
29
+ name: params.name,
30
+ slug: params.slug
31
+ }).onConflictDoNothing({
32
+ target: [
33
+ projects.sourceConnectionId,
34
+ projects.sourceExternalRepositoryId
35
+ ]
36
+ }).returning();
37
+ } catch (error) {
38
+ if (isUniqueViolation(error, PROJECTS_WORKSPACE_SLUG_UNIQUE_CONSTRAINT)) {
39
+ throw new ProjectSlugConflictError(params.slug);
40
+ }
41
+ throw error;
42
+ }
43
+ if (!projectRow) {
44
+ const [existing] = await tx.select().from(projects).where(and(eq(projects.sourceConnectionId, source.connection.id), eq(projects.sourceExternalRepositoryId, source.repository.externalRepositoryId))).limit(1);
45
+ if (existing) {
46
+ throw new ProjectAlreadyExistsError(existing.id, source.connection.id, source.repository.externalRepositoryId);
47
+ }
32
48
  }
49
+ }
50
+ if (!projectRow) {
33
51
  throw new Error('Project insert returned no rows');
34
52
  }
35
53
  const project = toProject(projectRow);
@@ -39,6 +57,7 @@ export async function createProjectFromSource(params) {
39
57
  actorId: params.actorId,
40
58
  workspaceId: project.workspaceId,
41
59
  projectId: project.id,
60
+ slug: project.slug,
42
61
  sourceConnectionId: project.sourceConnectionId,
43
62
  sourceExternalRepositoryId: project.sourceExternalRepositoryId
44
63
  }
@@ -59,5 +78,29 @@ export async function createProjectFromSource(params) {
59
78
  recordProjectCreated();
60
79
  return project;
61
80
  }
81
+ export function updateProjectDetails(params) {
82
+ return db().transaction(async (tx)=>{
83
+ const update = await updateProject({
84
+ projectId: params.projectId,
85
+ name: params.name,
86
+ slug: params.slug
87
+ }, {
88
+ tx
89
+ });
90
+ if (!update) throw new ProjectNotFoundError(params.projectId);
91
+ if (!update.changed) return update.project;
92
+ await writeOutboxEvent(tx, projectsOutbox, {
93
+ type: PROJECT_UPDATED,
94
+ payload: {
95
+ actorId: params.actorId,
96
+ workspaceId: update.project.workspaceId,
97
+ projectId: update.project.id,
98
+ name: update.project.name,
99
+ slug: update.project.slug
100
+ }
101
+ });
102
+ return update.project;
103
+ });
104
+ }
62
105
 
63
106
  //# sourceMappingURL=projects.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/projects.ts"],"sourcesContent":["import type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/inter-module';\nimport {\n PROJECT_CREATED,\n PROJECT_SOURCE_BOUND,\n type ProjectsEventMap,\n} from '@shipfox/api-projects-dto';\nimport {writeOutboxEvent} from '@shipfox/node-outbox';\nimport {and, eq} from 'drizzle-orm';\nimport {db} from '#db/db.js';\nimport {projectsOutbox} from '#db/schema/outbox.js';\nimport {projects, toProject} from '#db/schema/projects.js';\nimport {recordProjectCreated} from '#metrics/instance.js';\nimport type {Project} from './entities/project.js';\nimport {ProjectAlreadyExistsError} from './errors.js';\n\nexport interface CreateProjectFromSourceParams {\n actorId: string;\n workspaceId: string;\n name: string;\n sourceConnectionId: string;\n sourceExternalRepositoryId: string;\n integrations: IntegrationsModuleClient;\n}\n\nexport async function createProjectFromSource(\n params: CreateProjectFromSourceParams,\n): Promise<Project> {\n let source: {\n connection: {id: string; provider: string};\n repository: {externalRepositoryId: string};\n };\n source = await params.integrations.resolveSourceRepository({\n workspaceId: params.workspaceId,\n connectionId: params.sourceConnectionId,\n externalRepositoryId: params.sourceExternalRepositoryId,\n });\n\n const project = await db().transaction(async (tx) => {\n const [projectRow] = await tx\n .insert(projects)\n .values({\n workspaceId: params.workspaceId,\n sourceConnectionId: source.connection.id,\n sourceExternalRepositoryId: source.repository.externalRepositoryId,\n name: params.name,\n })\n .onConflictDoNothing({\n target: [projects.sourceConnectionId, projects.sourceExternalRepositoryId],\n })\n .returning();\n\n if (!projectRow) {\n const [existing] = await tx\n .select()\n .from(projects)\n .where(\n and(\n eq(projects.sourceConnectionId, source.connection.id),\n eq(projects.sourceExternalRepositoryId, source.repository.externalRepositoryId),\n ),\n )\n .limit(1);\n if (existing) {\n throw new ProjectAlreadyExistsError(\n existing.id,\n source.connection.id,\n source.repository.externalRepositoryId,\n );\n }\n throw new Error('Project insert returned no rows');\n }\n\n const project = toProject(projectRow);\n\n await writeOutboxEvent<ProjectsEventMap>(tx, projectsOutbox, {\n type: PROJECT_CREATED,\n payload: {\n actorId: params.actorId,\n workspaceId: project.workspaceId,\n projectId: project.id,\n sourceConnectionId: project.sourceConnectionId,\n sourceExternalRepositoryId: project.sourceExternalRepositoryId,\n },\n });\n await writeOutboxEvent<ProjectsEventMap>(tx, projectsOutbox, {\n type: PROJECT_SOURCE_BOUND,\n payload: {\n actorId: params.actorId,\n workspaceId: project.workspaceId,\n projectId: project.id,\n sourceConnectionId: project.sourceConnectionId,\n provider: source.connection.provider,\n externalRepositoryId: project.sourceExternalRepositoryId,\n },\n });\n\n return project;\n });\n recordProjectCreated();\n return project;\n}\n"],"names":["PROJECT_CREATED","PROJECT_SOURCE_BOUND","writeOutboxEvent","and","eq","db","projectsOutbox","projects","toProject","recordProjectCreated","ProjectAlreadyExistsError","createProjectFromSource","params","source","integrations","resolveSourceRepository","workspaceId","connectionId","sourceConnectionId","externalRepositoryId","sourceExternalRepositoryId","project","transaction","tx","projectRow","insert","values","connection","id","repository","name","onConflictDoNothing","target","returning","existing","select","from","where","limit","Error","type","payload","actorId","projectId","provider"],"mappings":"AACA,SACEA,eAAe,EACfC,oBAAoB,QAEf,4BAA4B;AACnC,SAAQC,gBAAgB,QAAO,uBAAuB;AACtD,SAAQC,GAAG,EAAEC,EAAE,QAAO,cAAc;AACpC,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,cAAc,QAAO,uBAAuB;AACpD,SAAQC,QAAQ,EAAEC,SAAS,QAAO,yBAAyB;AAC3D,SAAQC,oBAAoB,QAAO,uBAAuB;AAE1D,SAAQC,yBAAyB,QAAO,cAAc;AAWtD,OAAO,eAAeC,wBACpBC,MAAqC;IAErC,IAAIC;IAIJA,SAAS,MAAMD,OAAOE,YAAY,CAACC,uBAAuB,CAAC;QACzDC,aAAaJ,OAAOI,WAAW;QAC/BC,cAAcL,OAAOM,kBAAkB;QACvCC,sBAAsBP,OAAOQ,0BAA0B;IACzD;IAEA,MAAMC,UAAU,MAAMhB,KAAKiB,WAAW,CAAC,OAAOC;QAC5C,MAAM,CAACC,WAAW,GAAG,MAAMD,GACxBE,MAAM,CAAClB,UACPmB,MAAM,CAAC;YACNV,aAAaJ,OAAOI,WAAW;YAC/BE,oBAAoBL,OAAOc,UAAU,CAACC,EAAE;YACxCR,4BAA4BP,OAAOgB,UAAU,CAACV,oBAAoB;YAClEW,MAAMlB,OAAOkB,IAAI;QACnB,GACCC,mBAAmB,CAAC;YACnBC,QAAQ;gBAACzB,SAASW,kBAAkB;gBAAEX,SAASa,0BAA0B;aAAC;QAC5E,GACCa,SAAS;QAEZ,IAAI,CAACT,YAAY;YACf,MAAM,CAACU,SAAS,GAAG,MAAMX,GACtBY,MAAM,GACNC,IAAI,CAAC7B,UACL8B,KAAK,CACJlC,IACEC,GAAGG,SAASW,kBAAkB,EAAEL,OAAOc,UAAU,CAACC,EAAE,GACpDxB,GAAGG,SAASa,0BAA0B,EAAEP,OAAOgB,UAAU,CAACV,oBAAoB,IAGjFmB,KAAK,CAAC;YACT,IAAIJ,UAAU;gBACZ,MAAM,IAAIxB,0BACRwB,SAASN,EAAE,EACXf,OAAOc,UAAU,CAACC,EAAE,EACpBf,OAAOgB,UAAU,CAACV,oBAAoB;YAE1C;YACA,MAAM,IAAIoB,MAAM;QAClB;QAEA,MAAMlB,UAAUb,UAAUgB;QAE1B,MAAMtB,iBAAmCqB,IAAIjB,gBAAgB;YAC3DkC,MAAMxC;YACNyC,SAAS;gBACPC,SAAS9B,OAAO8B,OAAO;gBACvB1B,aAAaK,QAAQL,WAAW;gBAChC2B,WAAWtB,QAAQO,EAAE;gBACrBV,oBAAoBG,QAAQH,kBAAkB;gBAC9CE,4BAA4BC,QAAQD,0BAA0B;YAChE;QACF;QACA,MAAMlB,iBAAmCqB,IAAIjB,gBAAgB;YAC3DkC,MAAMvC;YACNwC,SAAS;gBACPC,SAAS9B,OAAO8B,OAAO;gBACvB1B,aAAaK,QAAQL,WAAW;gBAChC2B,WAAWtB,QAAQO,EAAE;gBACrBV,oBAAoBG,QAAQH,kBAAkB;gBAC9C0B,UAAU/B,OAAOc,UAAU,CAACiB,QAAQ;gBACpCzB,sBAAsBE,QAAQD,0BAA0B;YAC1D;QACF;QAEA,OAAOC;IACT;IACAZ;IACA,OAAOY;AACT"}
1
+ {"version":3,"sources":["../../src/core/projects.ts"],"sourcesContent":["import type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/inter-module';\nimport {\n PROJECT_CREATED,\n PROJECT_SOURCE_BOUND,\n PROJECT_UPDATED,\n type ProjectsEventMap,\n} from '@shipfox/api-projects-dto';\nimport {isUniqueViolation} from '@shipfox/node-drizzle';\nimport {writeOutboxEvent} from '@shipfox/node-outbox';\nimport {and, eq} from 'drizzle-orm';\nimport {db} from '#db/db.js';\nimport {updateProject} from '#db/projects.js';\nimport {projectsOutbox} from '#db/schema/outbox.js';\nimport {projects, toProject} from '#db/schema/projects.js';\nimport {recordProjectCreated} from '#metrics/instance.js';\nimport type {Project} from './entities/project.js';\nimport {\n ProjectAlreadyExistsError,\n ProjectNotFoundError,\n ProjectSlugConflictError,\n} from './errors.js';\n\nconst PROJECTS_WORKSPACE_SLUG_UNIQUE_CONSTRAINT = 'projects_workspace_slug_unique';\n\nexport interface CreateProjectFromSourceParams {\n actorId: string;\n workspaceId: string;\n name: string;\n sourceConnectionId: string;\n sourceExternalRepositoryId: string;\n slug: string;\n integrations: IntegrationsModuleClient;\n}\n\nexport async function createProjectFromSource(\n params: CreateProjectFromSourceParams,\n): Promise<Project> {\n const source = await params.integrations.resolveSourceRepository({\n workspaceId: params.workspaceId,\n connectionId: params.sourceConnectionId,\n externalRepositoryId: params.sourceExternalRepositoryId,\n });\n\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: source.connection.id,\n sourceExternalRepositoryId: source.repository.externalRepositoryId,\n sourceRepositoryOwner: source.repository.owner,\n sourceRepositoryName: source.repository.name,\n sourceDefaultBranch: source.repository.defaultBranch,\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 [existing] = await tx\n .select()\n .from(projects)\n .where(\n and(\n eq(projects.sourceConnectionId, source.connection.id),\n eq(projects.sourceExternalRepositoryId, source.repository.externalRepositoryId),\n ),\n )\n .limit(1);\n if (existing) {\n throw new ProjectAlreadyExistsError(\n existing.id,\n source.connection.id,\n source.repository.externalRepositoryId,\n );\n }\n }\n }\n\n if (!projectRow) {\n throw new Error('Project insert returned no rows');\n }\n\n const project = toProject(projectRow);\n\n await writeOutboxEvent<ProjectsEventMap>(tx, projectsOutbox, {\n type: PROJECT_CREATED,\n payload: {\n actorId: params.actorId,\n workspaceId: project.workspaceId,\n projectId: project.id,\n slug: project.slug,\n sourceConnectionId: project.sourceConnectionId,\n sourceExternalRepositoryId: project.sourceExternalRepositoryId,\n },\n });\n await writeOutboxEvent<ProjectsEventMap>(tx, projectsOutbox, {\n type: PROJECT_SOURCE_BOUND,\n payload: {\n actorId: params.actorId,\n workspaceId: project.workspaceId,\n projectId: project.id,\n sourceConnectionId: project.sourceConnectionId,\n provider: source.connection.provider,\n externalRepositoryId: project.sourceExternalRepositoryId,\n },\n });\n\n return project;\n });\n recordProjectCreated();\n return project;\n}\n\nexport interface UpdateProjectDetailsParams {\n actorId: string;\n projectId: string;\n name?: string | undefined;\n slug?: string | undefined;\n}\n\nexport function updateProjectDetails(params: UpdateProjectDetailsParams): Promise<Project> {\n return db().transaction(async (tx) => {\n const update = await updateProject(\n {projectId: params.projectId, name: params.name, slug: params.slug},\n {tx},\n );\n if (!update) throw new ProjectNotFoundError(params.projectId);\n if (!update.changed) return update.project;\n\n await writeOutboxEvent<ProjectsEventMap>(tx, projectsOutbox, {\n type: PROJECT_UPDATED,\n payload: {\n actorId: params.actorId,\n workspaceId: update.project.workspaceId,\n projectId: update.project.id,\n name: update.project.name,\n slug: update.project.slug,\n },\n });\n\n return update.project;\n });\n}\n"],"names":["PROJECT_CREATED","PROJECT_SOURCE_BOUND","PROJECT_UPDATED","isUniqueViolation","writeOutboxEvent","and","eq","db","updateProject","projectsOutbox","projects","toProject","recordProjectCreated","ProjectAlreadyExistsError","ProjectNotFoundError","ProjectSlugConflictError","PROJECTS_WORKSPACE_SLUG_UNIQUE_CONSTRAINT","createProjectFromSource","params","source","integrations","resolveSourceRepository","workspaceId","connectionId","sourceConnectionId","externalRepositoryId","sourceExternalRepositoryId","project","transaction","tx","projectRow","attempt","insert","values","connection","id","repository","sourceRepositoryOwner","owner","sourceRepositoryName","name","sourceDefaultBranch","defaultBranch","slug","onConflictDoNothing","target","returning","error","existing","select","from","where","limit","Error","type","payload","actorId","projectId","provider","updateProjectDetails","update","changed"],"mappings":"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"}