@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.
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +53 -0
- package/README.md +83 -0
- package/dist/core/entities/project.d.ts +4 -0
- package/dist/core/entities/project.d.ts.map +1 -1
- package/dist/core/entities/project.js.map +1 -1
- package/dist/core/errors.d.ts +4 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +6 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/projects.d.ts +8 -0
- package/dist/core/projects.d.ts.map +1 -1
- package/dist/core/projects.js +62 -19
- package/dist/core/projects.js.map +1 -1
- package/dist/db/db.d.ts +144 -6
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js.map +1 -1
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/projects.d.ts +53 -0
- package/dist/db/projects.d.ts.map +1 -1
- package/dist/db/projects.js +116 -18
- package/dist/db/projects.js.map +1 -1
- package/dist/db/schema/integration-event-dedup.d.ts +1 -1
- package/dist/db/schema/outbox.d.ts +1 -1
- package/dist/db/schema/projects.d.ts +69 -1
- package/dist/db/schema/projects.d.ts.map +1 -1
- package/dist/db/schema/projects.js +12 -1
- package/dist/db/schema/projects.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -5
- package/dist/index.js.map +1 -1
- package/dist/presentation/dto/project.d.ts +2 -1
- package/dist/presentation/dto/project.d.ts.map +1 -1
- package/dist/presentation/dto/project.js +1 -0
- package/dist/presentation/dto/project.js.map +1 -1
- package/dist/presentation/e2eRoutes/create-project.d.ts.map +1 -1
- package/dist/presentation/e2eRoutes/create-project.js +34 -8
- package/dist/presentation/e2eRoutes/create-project.js.map +1 -1
- package/dist/presentation/inter-module.d.ts +4 -1
- package/dist/presentation/inter-module.d.ts.map +1 -1
- package/dist/presentation/inter-module.js +63 -3
- package/dist/presentation/inter-module.js.map +1 -1
- package/dist/presentation/routes/create-project.d.ts.map +1 -1
- package/dist/presentation/routes/create-project.js +8 -2
- package/dist/presentation/routes/create-project.js.map +1 -1
- package/dist/presentation/routes/index.d.ts.map +1 -1
- package/dist/presentation/routes/index.js +3 -1
- package/dist/presentation/routes/index.js.map +1 -1
- package/dist/presentation/routes/update-project.d.ts +2 -0
- package/dist/presentation/routes/update-project.d.ts.map +1 -0
- package/dist/presentation/routes/update-project.js +53 -0
- package/dist/presentation/routes/update-project.js.map +1 -0
- package/dist/presentation/subscribers/index.d.ts +1 -0
- package/dist/presentation/subscribers/index.d.ts.map +1 -1
- package/dist/presentation/subscribers/index.js +1 -0
- package/dist/presentation/subscribers/index.js.map +1 -1
- package/dist/presentation/subscribers/on-source-repository-updated.d.ts +4 -0
- package/dist/presentation/subscribers/on-source-repository-updated.d.ts.map +1 -0
- package/dist/presentation/subscribers/on-source-repository-updated.js +39 -0
- package/dist/presentation/subscribers/on-source-repository-updated.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0000_initial.sql +6 -0
- package/drizzle/meta/0000_snapshot.json +78 -0
- package/package.json +13 -12
- package/src/core/entities/project.ts +4 -0
- package/src/core/errors.ts +7 -0
- package/src/core/index.ts +3 -2
- package/src/core/projects.test.ts +10 -0
- package/src/core/projects.ts +90 -35
- package/src/db/db.ts +3 -0
- package/src/db/index.ts +6 -0
- package/src/db/projects.test.ts +44 -1
- package/src/db/projects.ts +242 -33
- package/src/db/schema/projects.ts +16 -0
- package/src/index.ts +9 -3
- package/src/presentation/dto/project.ts +1 -0
- package/src/presentation/e2eRoutes/create-project.test.ts +23 -0
- package/src/presentation/e2eRoutes/create-project.ts +39 -10
- package/src/presentation/inter-module.test.ts +349 -0
- package/src/presentation/inter-module.ts +90 -4
- package/src/presentation/routes/create-project.ts +10 -2
- package/src/presentation/routes/index.ts +7 -1
- package/src/presentation/routes/projects.test.ts +300 -4
- package/src/presentation/routes/update-project.ts +46 -0
- package/src/presentation/subscribers/index.ts +1 -0
- package/src/presentation/subscribers/on-source-commit-pushed.test.ts +2 -0
- package/src/presentation/subscribers/on-source-repository-updated.test.ts +108 -0
- package/src/presentation/subscribers/on-source-repository-updated.ts +50 -0
- package/test/factories/project.ts +6 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
$ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
|
|
2
|
-
Successfully compiled:
|
|
3
|
-
2026-
|
|
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
|
|
16
|
-
2026-
|
|
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,
|
|
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"}
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/core/errors.js
CHANGED
|
@@ -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
|
package/dist/core/errors.js.map
CHANGED
|
@@ -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"}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -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
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/core/index.js
CHANGED
|
@@ -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
|
package/dist/core/index.js.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/core/projects.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/core/projects.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
|
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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"}
|