@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 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/create-project.ts"],"sourcesContent":["import {AUTH_USER, requireUserContext, requireWorkspaceAccess} from '@shipfox/api-auth-context';\nimport {\n type IntegrationsModuleClient,\n integrationsInterModuleContract,\n} from '@shipfox/api-integration-core-dto/inter-module';\nimport {createProjectBodySchema, projectResponseSchema} from '@shipfox/api-projects-dto';\nimport {isInterModuleKnownError} from '@shipfox/inter-module';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {createProjectFromSource, ProjectAlreadyExistsError} from '#core/index.js';\nimport {toProjectDto} from '#presentation/dto/index.js';\n\nfunction providerStatus(reason: string): number {\n if (reason === 'rate-limited') return 429;\n if (reason === 'timeout' || reason === 'provider-unavailable') return 503;\n return 422;\n}\n\nexport function createProjectRoute(integrations: IntegrationsModuleClient) {\n return defineRoute({\n method: 'POST',\n path: '/',\n auth: AUTH_USER,\n description: 'Create a project bound to a source repository.',\n schema: {\n body: createProjectBodySchema,\n response: {\n 201: projectResponseSchema,\n },\n },\n errorHandler: (error) => {\n const known = isInterModuleKnownError(\n integrationsInterModuleContract.methods.resolveSourceRepository,\n error,\n )\n ? error\n : undefined;\n if (known?.code === 'connection-not-found') {\n throw new ClientError('Source connection not found', 'source-connection-not-found', {\n status: 404,\n });\n }\n if (known?.code === 'connection-workspace-mismatch') {\n throw new ClientError('Source connection does not belong to this workspace', 'forbidden', {\n status: 403,\n });\n }\n if (known?.code === 'connection-inactive') {\n throw new ClientError('Source connection is not active', 'source-connection-inactive', {\n status: 422,\n });\n }\n if (known?.code === 'provider-unavailable') {\n throw new ClientError(\n 'Integration provider is unavailable',\n 'integration-provider-unavailable',\n {status: 422},\n );\n }\n if (known?.code === 'capability-unavailable') {\n throw new ClientError(\n 'Integration capability is unavailable',\n 'integration-capability-unavailable',\n {status: 422},\n );\n }\n if (error instanceof ProjectAlreadyExistsError) {\n throw new ClientError(error.message, 'project-already-exists', {\n details: {\n existing_project_id: error.existingProjectId,\n source_connection_id: error.sourceConnectionId,\n source_external_repository_id: error.sourceExternalRepositoryId,\n },\n status: 409,\n });\n }\n if (known?.code === 'provider-failure') {\n throw new ClientError('Integration provider request failed', known.details.reason, {\n details: {retry_after_seconds: known.details.retryAfterSeconds},\n status: providerStatus(known.details.reason),\n });\n }\n throw error;\n },\n handler: async (request, reply) => {\n const {workspace_id: workspaceId, name, source} = request.body;\n const actor = requireUserContext(request);\n\n requireWorkspaceAccess({request, workspaceId});\n const project = await createProjectFromSource({\n actorId: actor.userId,\n workspaceId,\n name,\n sourceConnectionId: source.connection_id,\n sourceExternalRepositoryId: source.external_repository_id,\n integrations,\n });\n\n reply.status(201);\n return toProjectDto(project);\n },\n });\n}\n"],"names":["AUTH_USER","requireUserContext","requireWorkspaceAccess","integrationsInterModuleContract","createProjectBodySchema","projectResponseSchema","isInterModuleKnownError","ClientError","defineRoute","createProjectFromSource","ProjectAlreadyExistsError","toProjectDto","providerStatus","reason","createProjectRoute","integrations","method","path","auth","description","schema","body","response","errorHandler","error","known","methods","resolveSourceRepository","undefined","code","status","message","details","existing_project_id","existingProjectId","source_connection_id","sourceConnectionId","source_external_repository_id","sourceExternalRepositoryId","retry_after_seconds","retryAfterSeconds","handler","request","reply","workspace_id","workspaceId","name","source","actor","project","actorId","userId","connection_id","external_repository_id"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,kBAAkB,EAAEC,sBAAsB,QAAO,4BAA4B;AAChG,SAEEC,+BAA+B,QAC1B,iDAAiD;AACxD,SAAQC,uBAAuB,EAAEC,qBAAqB,QAAO,4BAA4B;AACzF,SAAQC,uBAAuB,QAAO,wBAAwB;AAC9D,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SAAQC,uBAAuB,EAAEC,yBAAyB,QAAO,iBAAiB;AAClF,SAAQC,YAAY,QAAO,6BAA6B;AAExD,SAASC,eAAeC,MAAc;IACpC,IAAIA,WAAW,gBAAgB,OAAO;IACtC,IAAIA,WAAW,aAAaA,WAAW,wBAAwB,OAAO;IACtE,OAAO;AACT;AAEA,OAAO,SAASC,mBAAmBC,YAAsC;IACvE,OAAOP,YAAY;QACjBQ,QAAQ;QACRC,MAAM;QACNC,MAAMlB;QACNmB,aAAa;QACbC,QAAQ;YACNC,MAAMjB;YACNkB,UAAU;gBACR,KAAKjB;YACP;QACF;QACAkB,cAAc,CAACC;YACb,MAAMC,QAAQnB,wBACZH,gCAAgCuB,OAAO,CAACC,uBAAuB,EAC/DH,SAEEA,QACAI;YACJ,IAAIH,OAAOI,SAAS,wBAAwB;gBAC1C,MAAM,IAAItB,YAAY,+BAA+B,+BAA+B;oBAClFuB,QAAQ;gBACV;YACF;YACA,IAAIL,OAAOI,SAAS,iCAAiC;gBACnD,MAAM,IAAItB,YAAY,uDAAuD,aAAa;oBACxFuB,QAAQ;gBACV;YACF;YACA,IAAIL,OAAOI,SAAS,uBAAuB;gBACzC,MAAM,IAAItB,YAAY,mCAAmC,8BAA8B;oBACrFuB,QAAQ;gBACV;YACF;YACA,IAAIL,OAAOI,SAAS,wBAAwB;gBAC1C,MAAM,IAAItB,YACR,uCACA,oCACA;oBAACuB,QAAQ;gBAAG;YAEhB;YACA,IAAIL,OAAOI,SAAS,0BAA0B;gBAC5C,MAAM,IAAItB,YACR,yCACA,sCACA;oBAACuB,QAAQ;gBAAG;YAEhB;YACA,IAAIN,iBAAiBd,2BAA2B;gBAC9C,MAAM,IAAIH,YAAYiB,MAAMO,OAAO,EAAE,0BAA0B;oBAC7DC,SAAS;wBACPC,qBAAqBT,MAAMU,iBAAiB;wBAC5CC,sBAAsBX,MAAMY,kBAAkB;wBAC9CC,+BAA+Bb,MAAMc,0BAA0B;oBACjE;oBACAR,QAAQ;gBACV;YACF;YACA,IAAIL,OAAOI,SAAS,oBAAoB;gBACtC,MAAM,IAAItB,YAAY,uCAAuCkB,MAAMO,OAAO,CAACnB,MAAM,EAAE;oBACjFmB,SAAS;wBAACO,qBAAqBd,MAAMO,OAAO,CAACQ,iBAAiB;oBAAA;oBAC9DV,QAAQlB,eAAea,MAAMO,OAAO,CAACnB,MAAM;gBAC7C;YACF;YACA,MAAMW;QACR;QACAiB,SAAS,OAAOC,SAASC;YACvB,MAAM,EAACC,cAAcC,WAAW,EAAEC,IAAI,EAAEC,MAAM,EAAC,GAAGL,QAAQrB,IAAI;YAC9D,MAAM2B,QAAQ/C,mBAAmByC;YAEjCxC,uBAAuB;gBAACwC;gBAASG;YAAW;YAC5C,MAAMI,UAAU,MAAMxC,wBAAwB;gBAC5CyC,SAASF,MAAMG,MAAM;gBACrBN;gBACAC;gBACAV,oBAAoBW,OAAOK,aAAa;gBACxCd,4BAA4BS,OAAOM,sBAAsB;gBACzDtC;YACF;YAEA4B,MAAMb,MAAM,CAAC;YACb,OAAOnB,aAAasC;QACtB;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/create-project.ts"],"sourcesContent":["import {AUTH_USER, requireUserContext, requireWorkspaceAccess} from '@shipfox/api-auth-context';\nimport {\n type IntegrationsModuleClient,\n integrationsInterModuleContract,\n} from '@shipfox/api-integration-core-dto/inter-module';\nimport {createProjectBodySchema, projectResponseSchema} from '@shipfox/api-projects-dto';\nimport {isInterModuleKnownError} from '@shipfox/inter-module';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {\n createProjectFromSource,\n ProjectAlreadyExistsError,\n ProjectSlugConflictError,\n} from '#core/index.js';\nimport {toProjectDto} from '#presentation/dto/index.js';\n\nfunction providerStatus(reason: string): number {\n if (reason === 'rate-limited') return 429;\n if (reason === 'timeout' || reason === 'provider-unavailable') return 503;\n return 422;\n}\n\nexport function createProjectRoute(integrations: IntegrationsModuleClient) {\n return defineRoute({\n method: 'POST',\n path: '/',\n auth: AUTH_USER,\n description: 'Create a project bound to a source repository.',\n schema: {\n body: createProjectBodySchema,\n response: {\n 201: projectResponseSchema,\n },\n },\n errorHandler: (error) => {\n const known = isInterModuleKnownError(\n integrationsInterModuleContract.methods.resolveSourceRepository,\n error,\n )\n ? error\n : undefined;\n if (known?.code === 'connection-not-found') {\n throw new ClientError('Source connection not found', 'source-connection-not-found', {\n status: 404,\n });\n }\n if (known?.code === 'connection-workspace-mismatch') {\n throw new ClientError('Source connection does not belong to this workspace', 'forbidden', {\n status: 403,\n });\n }\n if (known?.code === 'connection-inactive') {\n throw new ClientError('Source connection is not active', 'source-connection-inactive', {\n status: 422,\n });\n }\n if (known?.code === 'provider-unavailable') {\n throw new ClientError(\n 'Integration provider is unavailable',\n 'integration-provider-unavailable',\n {status: 422},\n );\n }\n if (known?.code === 'capability-unavailable') {\n throw new ClientError(\n 'Integration capability is unavailable',\n 'integration-capability-unavailable',\n {status: 422},\n );\n }\n if (error instanceof ProjectAlreadyExistsError) {\n throw new ClientError(error.message, 'project-already-exists', {\n details: {\n existing_project_id: error.existingProjectId,\n source_connection_id: error.sourceConnectionId,\n source_external_repository_id: error.sourceExternalRepositoryId,\n },\n status: 409,\n });\n }\n if (error instanceof ProjectSlugConflictError) {\n throw new ClientError('Project slug already exists', 'slug-conflict', {status: 409});\n }\n if (known?.code === 'provider-failure') {\n throw new ClientError('Integration provider request failed', known.details.reason, {\n details: {retry_after_seconds: known.details.retryAfterSeconds},\n status: providerStatus(known.details.reason),\n });\n }\n throw error;\n },\n handler: async (request, reply) => {\n const {workspace_id: workspaceId, name, slug, source} = request.body;\n const actor = requireUserContext(request);\n\n requireWorkspaceAccess({request, workspaceId});\n const project = await createProjectFromSource({\n actorId: actor.userId,\n workspaceId,\n name,\n slug,\n sourceConnectionId: source.connection_id,\n sourceExternalRepositoryId: source.external_repository_id,\n integrations,\n });\n\n reply.status(201);\n return toProjectDto(project);\n },\n });\n}\n"],"names":["AUTH_USER","requireUserContext","requireWorkspaceAccess","integrationsInterModuleContract","createProjectBodySchema","projectResponseSchema","isInterModuleKnownError","ClientError","defineRoute","createProjectFromSource","ProjectAlreadyExistsError","ProjectSlugConflictError","toProjectDto","providerStatus","reason","createProjectRoute","integrations","method","path","auth","description","schema","body","response","errorHandler","error","known","methods","resolveSourceRepository","undefined","code","status","message","details","existing_project_id","existingProjectId","source_connection_id","sourceConnectionId","source_external_repository_id","sourceExternalRepositoryId","retry_after_seconds","retryAfterSeconds","handler","request","reply","workspace_id","workspaceId","name","slug","source","actor","project","actorId","userId","connection_id","external_repository_id"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,kBAAkB,EAAEC,sBAAsB,QAAO,4BAA4B;AAChG,SAEEC,+BAA+B,QAC1B,iDAAiD;AACxD,SAAQC,uBAAuB,EAAEC,qBAAqB,QAAO,4BAA4B;AACzF,SAAQC,uBAAuB,QAAO,wBAAwB;AAC9D,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SACEC,uBAAuB,EACvBC,yBAAyB,EACzBC,wBAAwB,QACnB,iBAAiB;AACxB,SAAQC,YAAY,QAAO,6BAA6B;AAExD,SAASC,eAAeC,MAAc;IACpC,IAAIA,WAAW,gBAAgB,OAAO;IACtC,IAAIA,WAAW,aAAaA,WAAW,wBAAwB,OAAO;IACtE,OAAO;AACT;AAEA,OAAO,SAASC,mBAAmBC,YAAsC;IACvE,OAAOR,YAAY;QACjBS,QAAQ;QACRC,MAAM;QACNC,MAAMnB;QACNoB,aAAa;QACbC,QAAQ;YACNC,MAAMlB;YACNmB,UAAU;gBACR,KAAKlB;YACP;QACF;QACAmB,cAAc,CAACC;YACb,MAAMC,QAAQpB,wBACZH,gCAAgCwB,OAAO,CAACC,uBAAuB,EAC/DH,SAEEA,QACAI;YACJ,IAAIH,OAAOI,SAAS,wBAAwB;gBAC1C,MAAM,IAAIvB,YAAY,+BAA+B,+BAA+B;oBAClFwB,QAAQ;gBACV;YACF;YACA,IAAIL,OAAOI,SAAS,iCAAiC;gBACnD,MAAM,IAAIvB,YAAY,uDAAuD,aAAa;oBACxFwB,QAAQ;gBACV;YACF;YACA,IAAIL,OAAOI,SAAS,uBAAuB;gBACzC,MAAM,IAAIvB,YAAY,mCAAmC,8BAA8B;oBACrFwB,QAAQ;gBACV;YACF;YACA,IAAIL,OAAOI,SAAS,wBAAwB;gBAC1C,MAAM,IAAIvB,YACR,uCACA,oCACA;oBAACwB,QAAQ;gBAAG;YAEhB;YACA,IAAIL,OAAOI,SAAS,0BAA0B;gBAC5C,MAAM,IAAIvB,YACR,yCACA,sCACA;oBAACwB,QAAQ;gBAAG;YAEhB;YACA,IAAIN,iBAAiBf,2BAA2B;gBAC9C,MAAM,IAAIH,YAAYkB,MAAMO,OAAO,EAAE,0BAA0B;oBAC7DC,SAAS;wBACPC,qBAAqBT,MAAMU,iBAAiB;wBAC5CC,sBAAsBX,MAAMY,kBAAkB;wBAC9CC,+BAA+Bb,MAAMc,0BAA0B;oBACjE;oBACAR,QAAQ;gBACV;YACF;YACA,IAAIN,iBAAiBd,0BAA0B;gBAC7C,MAAM,IAAIJ,YAAY,+BAA+B,iBAAiB;oBAACwB,QAAQ;gBAAG;YACpF;YACA,IAAIL,OAAOI,SAAS,oBAAoB;gBACtC,MAAM,IAAIvB,YAAY,uCAAuCmB,MAAMO,OAAO,CAACnB,MAAM,EAAE;oBACjFmB,SAAS;wBAACO,qBAAqBd,MAAMO,OAAO,CAACQ,iBAAiB;oBAAA;oBAC9DV,QAAQlB,eAAea,MAAMO,OAAO,CAACnB,MAAM;gBAC7C;YACF;YACA,MAAMW;QACR;QACAiB,SAAS,OAAOC,SAASC;YACvB,MAAM,EAACC,cAAcC,WAAW,EAAEC,IAAI,EAAEC,IAAI,EAAEC,MAAM,EAAC,GAAGN,QAAQrB,IAAI;YACpE,MAAM4B,QAAQjD,mBAAmB0C;YAEjCzC,uBAAuB;gBAACyC;gBAASG;YAAW;YAC5C,MAAMK,UAAU,MAAM1C,wBAAwB;gBAC5C2C,SAASF,MAAMG,MAAM;gBACrBP;gBACAC;gBACAC;gBACAX,oBAAoBY,OAAOK,aAAa;gBACxCf,4BAA4BU,OAAOM,sBAAsB;gBACzDvC;YACF;YAEA4B,MAAMb,MAAM,CAAC;YACb,OAAOnB,aAAauC;QACtB;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,gDAAgD,CAAC;AAC7F,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAMtD,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,wBAAwB,EACtC,IAAI,EAAE,IAAI,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,GACpD,UAAU,EAAE,CAWd"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,gDAAgD,CAAC;AAC7F,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAOtD,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,wBAAwB,EACtC,IAAI,EAAE,IAAI,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,GACpD,UAAU,EAAE,CAgBd"}
@@ -2,6 +2,7 @@ import { createAdminProjectsRoute } from './admin-projects.js';
2
2
  import { createProjectRoute } from './create-project.js';
3
3
  import { getProjectRoute } from './get-project.js';
4
4
  import { listProjectsRoute } from './list-projects.js';
5
+ import { updateProjectRoute } from './update-project.js';
5
6
  export function createProjectRoutes(integrations, auth) {
6
7
  return [
7
8
  {
@@ -9,7 +10,8 @@ export function createProjectRoutes(integrations, auth) {
9
10
  routes: [
10
11
  createProjectRoute(integrations),
11
12
  listProjectsRoute,
12
- getProjectRoute
13
+ getProjectRoute,
14
+ updateProjectRoute
13
15
  ]
14
16
  },
15
17
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/index.ts"],"sourcesContent":["import type {AuthInterModuleClient} from '@shipfox/api-auth-dto/inter-module';\nimport type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/inter-module';\nimport type {RouteGroup} from '@shipfox/node-fastify';\nimport {createAdminProjectsRoute} from './admin-projects.js';\nimport {createProjectRoute} from './create-project.js';\nimport {getProjectRoute} from './get-project.js';\nimport {listProjectsRoute} from './list-projects.js';\n\nexport function createProjectRoutes(\n integrations: IntegrationsModuleClient,\n auth: Pick<AuthInterModuleClient, 'requireAdminRole'>,\n): RouteGroup[] {\n return [\n {\n prefix: '/projects',\n routes: [createProjectRoute(integrations), listProjectsRoute, getProjectRoute],\n },\n {\n prefix: '/admin/projects',\n routes: [createAdminProjectsRoute(auth)],\n },\n ];\n}\n"],"names":["createAdminProjectsRoute","createProjectRoute","getProjectRoute","listProjectsRoute","createProjectRoutes","integrations","auth","prefix","routes"],"mappings":"AAGA,SAAQA,wBAAwB,QAAO,sBAAsB;AAC7D,SAAQC,kBAAkB,QAAO,sBAAsB;AACvD,SAAQC,eAAe,QAAO,mBAAmB;AACjD,SAAQC,iBAAiB,QAAO,qBAAqB;AAErD,OAAO,SAASC,oBACdC,YAAsC,EACtCC,IAAqD;IAErD,OAAO;QACL;YACEC,QAAQ;YACRC,QAAQ;gBAACP,mBAAmBI;gBAAeF;gBAAmBD;aAAgB;QAChF;QACA;YACEK,QAAQ;YACRC,QAAQ;gBAACR,yBAAyBM;aAAM;QAC1C;KACD;AACH"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/index.ts"],"sourcesContent":["import type {AuthInterModuleClient} from '@shipfox/api-auth-dto/inter-module';\nimport type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/inter-module';\nimport type {RouteGroup} from '@shipfox/node-fastify';\nimport {createAdminProjectsRoute} from './admin-projects.js';\nimport {createProjectRoute} from './create-project.js';\nimport {getProjectRoute} from './get-project.js';\nimport {listProjectsRoute} from './list-projects.js';\nimport {updateProjectRoute} from './update-project.js';\n\nexport function createProjectRoutes(\n integrations: IntegrationsModuleClient,\n auth: Pick<AuthInterModuleClient, 'requireAdminRole'>,\n): RouteGroup[] {\n return [\n {\n prefix: '/projects',\n routes: [\n createProjectRoute(integrations),\n listProjectsRoute,\n getProjectRoute,\n updateProjectRoute,\n ],\n },\n {\n prefix: '/admin/projects',\n routes: [createAdminProjectsRoute(auth)],\n },\n ];\n}\n"],"names":["createAdminProjectsRoute","createProjectRoute","getProjectRoute","listProjectsRoute","updateProjectRoute","createProjectRoutes","integrations","auth","prefix","routes"],"mappings":"AAGA,SAAQA,wBAAwB,QAAO,sBAAsB;AAC7D,SAAQC,kBAAkB,QAAO,sBAAsB;AACvD,SAAQC,eAAe,QAAO,mBAAmB;AACjD,SAAQC,iBAAiB,QAAO,qBAAqB;AACrD,SAAQC,kBAAkB,QAAO,sBAAsB;AAEvD,OAAO,SAASC,oBACdC,YAAsC,EACtCC,IAAqD;IAErD,OAAO;QACL;YACEC,QAAQ;YACRC,QAAQ;gBACNR,mBAAmBK;gBACnBH;gBACAD;gBACAE;aACD;QACH;QACA;YACEI,QAAQ;YACRC,QAAQ;gBAACT,yBAAyBO;aAAM;QAC1C;KACD;AACH"}
@@ -0,0 +1,2 @@
1
+ export declare const updateProjectRoute: import("@shipfox/node-fastify").RouteDefinition;
2
+ //# sourceMappingURL=update-project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-project.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/update-project.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,kBAAkB,iDAiC7B,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { AUTH_USER, requireUserContext } from '@shipfox/api-auth-context';
2
+ import { projectResponseSchema, updateProjectBodySchema } from '@shipfox/api-projects-dto';
3
+ import { ClientError, defineRoute } from '@shipfox/node-fastify';
4
+ import { z } from 'zod';
5
+ import { ProjectNotFoundError, ProjectSlugConflictError, updateProjectDetails } from '#core/index.js';
6
+ import { requireProjectAccess } from '#presentation/auth/require-project-access.js';
7
+ import { toProjectDto } from '#presentation/dto/index.js';
8
+ const projectParamsSchema = z.object({
9
+ projectId: z.string().uuid()
10
+ });
11
+ export const updateProjectRoute = defineRoute({
12
+ method: 'PATCH',
13
+ path: '/:projectId',
14
+ auth: AUTH_USER,
15
+ description: 'Update a project.',
16
+ schema: {
17
+ params: projectParamsSchema,
18
+ body: updateProjectBodySchema,
19
+ response: {
20
+ 200: projectResponseSchema
21
+ }
22
+ },
23
+ errorHandler: (error)=>{
24
+ if (error instanceof ProjectSlugConflictError) {
25
+ throw new ClientError('Project slug already exists', 'slug-conflict', {
26
+ status: 409
27
+ });
28
+ }
29
+ if (error instanceof ProjectNotFoundError) {
30
+ throw new ClientError('Project not found', 'project-not-found', {
31
+ status: 404
32
+ });
33
+ }
34
+ throw error;
35
+ },
36
+ handler: async (request)=>{
37
+ const { projectId } = request.params;
38
+ await requireProjectAccess({
39
+ request,
40
+ projectId
41
+ });
42
+ const actor = requireUserContext(request);
43
+ const project = await updateProjectDetails({
44
+ actorId: actor.userId,
45
+ projectId,
46
+ name: request.body.name,
47
+ slug: request.body.slug
48
+ });
49
+ return toProjectDto(project);
50
+ }
51
+ });
52
+
53
+ //# sourceMappingURL=update-project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/presentation/routes/update-project.ts"],"sourcesContent":["import {AUTH_USER, requireUserContext} from '@shipfox/api-auth-context';\nimport {projectResponseSchema, updateProjectBodySchema} from '@shipfox/api-projects-dto';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport {ProjectNotFoundError, ProjectSlugConflictError, updateProjectDetails} from '#core/index.js';\nimport {requireProjectAccess} from '#presentation/auth/require-project-access.js';\nimport {toProjectDto} from '#presentation/dto/index.js';\n\nconst projectParamsSchema = z.object({\n projectId: z.string().uuid(),\n});\n\nexport const updateProjectRoute = defineRoute({\n method: 'PATCH',\n path: '/:projectId',\n auth: AUTH_USER,\n description: 'Update a project.',\n schema: {\n params: projectParamsSchema,\n body: updateProjectBodySchema,\n response: {\n 200: projectResponseSchema,\n },\n },\n errorHandler: (error) => {\n if (error instanceof ProjectSlugConflictError) {\n throw new ClientError('Project slug already exists', 'slug-conflict', {status: 409});\n }\n if (error instanceof ProjectNotFoundError) {\n throw new ClientError('Project not found', 'project-not-found', {status: 404});\n }\n throw error;\n },\n handler: async (request) => {\n const {projectId} = request.params;\n await requireProjectAccess({request, projectId});\n const actor = requireUserContext(request);\n const project = await updateProjectDetails({\n actorId: actor.userId,\n projectId,\n name: request.body.name,\n slug: request.body.slug,\n });\n return toProjectDto(project);\n },\n});\n"],"names":["AUTH_USER","requireUserContext","projectResponseSchema","updateProjectBodySchema","ClientError","defineRoute","z","ProjectNotFoundError","ProjectSlugConflictError","updateProjectDetails","requireProjectAccess","toProjectDto","projectParamsSchema","object","projectId","string","uuid","updateProjectRoute","method","path","auth","description","schema","params","body","response","errorHandler","error","status","handler","request","actor","project","actorId","userId","name","slug"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,kBAAkB,QAAO,4BAA4B;AACxE,SAAQC,qBAAqB,EAAEC,uBAAuB,QAAO,4BAA4B;AACzF,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SAAQC,CAAC,QAAO,MAAM;AACtB,SAAQC,oBAAoB,EAAEC,wBAAwB,EAAEC,oBAAoB,QAAO,iBAAiB;AACpG,SAAQC,oBAAoB,QAAO,+CAA+C;AAClF,SAAQC,YAAY,QAAO,6BAA6B;AAExD,MAAMC,sBAAsBN,EAAEO,MAAM,CAAC;IACnCC,WAAWR,EAAES,MAAM,GAAGC,IAAI;AAC5B;AAEA,OAAO,MAAMC,qBAAqBZ,YAAY;IAC5Ca,QAAQ;IACRC,MAAM;IACNC,MAAMpB;IACNqB,aAAa;IACbC,QAAQ;QACNC,QAAQX;QACRY,MAAMrB;QACNsB,UAAU;YACR,KAAKvB;QACP;IACF;IACAwB,cAAc,CAACC;QACb,IAAIA,iBAAiBnB,0BAA0B;YAC7C,MAAM,IAAIJ,YAAY,+BAA+B,iBAAiB;gBAACwB,QAAQ;YAAG;QACpF;QACA,IAAID,iBAAiBpB,sBAAsB;YACzC,MAAM,IAAIH,YAAY,qBAAqB,qBAAqB;gBAACwB,QAAQ;YAAG;QAC9E;QACA,MAAMD;IACR;IACAE,SAAS,OAAOC;QACd,MAAM,EAAChB,SAAS,EAAC,GAAGgB,QAAQP,MAAM;QAClC,MAAMb,qBAAqB;YAACoB;YAAShB;QAAS;QAC9C,MAAMiB,QAAQ9B,mBAAmB6B;QACjC,MAAME,UAAU,MAAMvB,qBAAqB;YACzCwB,SAASF,MAAMG,MAAM;YACrBpB;YACAqB,MAAML,QAAQN,IAAI,CAACW,IAAI;YACvBC,MAAMN,QAAQN,IAAI,CAACY,IAAI;QACzB;QACA,OAAOzB,aAAaqB;IACtB;AACF,GAAG"}
@@ -1,2 +1,3 @@
1
1
  export { onSourceCommitPushed } from './on-source-commit-pushed.js';
2
+ export { onSourceRepositoryUpdated } from './on-source-repository-updated.js';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/subscribers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,oBAAoB,EAAC,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/subscribers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,oBAAoB,EAAC,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAC,yBAAyB,EAAC,MAAM,mCAAmC,CAAC"}
@@ -1,3 +1,4 @@
1
1
  export { onSourceCommitPushed } from './on-source-commit-pushed.js';
2
+ export { onSourceRepositoryUpdated } from './on-source-repository-updated.js';
2
3
 
3
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/subscribers/index.ts"],"sourcesContent":["export {onSourceCommitPushed} from './on-source-commit-pushed.js';\n"],"names":["onSourceCommitPushed"],"mappings":"AAAA,SAAQA,oBAAoB,QAAO,+BAA+B"}
1
+ {"version":3,"sources":["../../../src/presentation/subscribers/index.ts"],"sourcesContent":["export {onSourceCommitPushed} from './on-source-commit-pushed.js';\nexport {onSourceRepositoryUpdated} from './on-source-repository-updated.js';\n"],"names":["onSourceCommitPushed","onSourceRepositoryUpdated"],"mappings":"AAAA,SAAQA,oBAAoB,QAAO,+BAA+B;AAClE,SAAQC,yBAAyB,QAAO,oCAAoC"}
@@ -0,0 +1,4 @@
1
+ import type { IntegrationSourceRepositoryUpdatedEvent } from '@shipfox/api-integration-core-dto';
2
+ import type { DomainEvent } from '@shipfox/node-outbox';
3
+ export declare function onSourceRepositoryUpdated(payload: IntegrationSourceRepositoryUpdatedEvent, event: DomainEvent<IntegrationSourceRepositoryUpdatedEvent>): Promise<void>;
4
+ //# sourceMappingURL=on-source-repository-updated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"on-source-repository-updated.d.ts","sourceRoot":"","sources":["../../../src/presentation/subscribers/on-source-repository-updated.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,uCAAuC,EAAC,MAAM,mCAAmC,CAAC;AAE/F,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,sBAAsB,CAAC;AAKtD,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,uCAAuC,EAChD,KAAK,EAAE,WAAW,CAAC,uCAAuC,CAAC,GAC1D,OAAO,CAAC,IAAI,CAAC,CAuCf"}
@@ -0,0 +1,39 @@
1
+ import { logger } from '@shipfox/node-opentelemetry';
2
+ import { db } from '#db/db.js';
3
+ import { recordIntegrationEventForProject } from '#db/integration-event-dedup.js';
4
+ import { getProjectBySource, updateProjectSourceRepository } from '#db/projects.js';
5
+ export async function onSourceRepositoryUpdated(payload, event) {
6
+ const project = await getProjectBySource({
7
+ workspaceId: payload.workspaceId,
8
+ sourceConnectionId: payload.connectionId,
9
+ sourceExternalRepositoryId: payload.repository.externalRepositoryId
10
+ });
11
+ if (project) {
12
+ const outcome = await db().transaction(async (tx)=>{
13
+ const { firstSeen } = await recordIntegrationEventForProject({
14
+ tx,
15
+ integrationEventId: event.id,
16
+ projectId: project.id
17
+ });
18
+ if (!firstSeen) return 'duplicate';
19
+ const updated = await updateProjectSourceRepository({
20
+ tx,
21
+ workspaceId: payload.workspaceId,
22
+ sourceConnectionId: payload.connectionId,
23
+ sourceExternalRepositoryId: payload.repository.externalRepositoryId,
24
+ sourceRepositoryOwner: payload.repository.owner,
25
+ sourceRepositoryName: payload.repository.name,
26
+ sourceDefaultBranch: payload.repository.defaultBranch
27
+ });
28
+ return updated ? 'updated' : 'missing';
29
+ });
30
+ if (outcome !== 'missing') return;
31
+ }
32
+ logger().info({
33
+ eventId: event.id,
34
+ connectionId: payload.connectionId,
35
+ externalRepositoryId: payload.repository.externalRepositoryId
36
+ }, 'source repository updated: no project bound to source, dropping');
37
+ }
38
+
39
+ //# sourceMappingURL=on-source-repository-updated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/presentation/subscribers/on-source-repository-updated.ts"],"sourcesContent":["import type {IntegrationSourceRepositoryUpdatedEvent} from '@shipfox/api-integration-core-dto';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport type {DomainEvent} from '@shipfox/node-outbox';\nimport {db} from '#db/db.js';\nimport {recordIntegrationEventForProject} from '#db/integration-event-dedup.js';\nimport {getProjectBySource, updateProjectSourceRepository} from '#db/projects.js';\n\nexport async function onSourceRepositoryUpdated(\n payload: IntegrationSourceRepositoryUpdatedEvent,\n event: DomainEvent<IntegrationSourceRepositoryUpdatedEvent>,\n): Promise<void> {\n const project = await getProjectBySource({\n workspaceId: payload.workspaceId,\n sourceConnectionId: payload.connectionId,\n sourceExternalRepositoryId: payload.repository.externalRepositoryId,\n });\n\n if (project) {\n const outcome = await db().transaction(async (tx) => {\n const {firstSeen} = await recordIntegrationEventForProject({\n tx,\n integrationEventId: event.id,\n projectId: project.id,\n });\n if (!firstSeen) return 'duplicate';\n\n const updated = await updateProjectSourceRepository({\n tx,\n workspaceId: payload.workspaceId,\n sourceConnectionId: payload.connectionId,\n sourceExternalRepositoryId: payload.repository.externalRepositoryId,\n sourceRepositoryOwner: payload.repository.owner,\n sourceRepositoryName: payload.repository.name,\n sourceDefaultBranch: payload.repository.defaultBranch,\n });\n return updated ? 'updated' : 'missing';\n });\n\n if (outcome !== 'missing') return;\n }\n\n logger().info(\n {\n eventId: event.id,\n connectionId: payload.connectionId,\n externalRepositoryId: payload.repository.externalRepositoryId,\n },\n 'source repository updated: no project bound to source, dropping',\n );\n}\n"],"names":["logger","db","recordIntegrationEventForProject","getProjectBySource","updateProjectSourceRepository","onSourceRepositoryUpdated","payload","event","project","workspaceId","sourceConnectionId","connectionId","sourceExternalRepositoryId","repository","externalRepositoryId","outcome","transaction","tx","firstSeen","integrationEventId","id","projectId","updated","sourceRepositoryOwner","owner","sourceRepositoryName","name","sourceDefaultBranch","defaultBranch","info","eventId"],"mappings":"AACA,SAAQA,MAAM,QAAO,8BAA8B;AAEnD,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,gCAAgC,QAAO,iCAAiC;AAChF,SAAQC,kBAAkB,EAAEC,6BAA6B,QAAO,kBAAkB;AAElF,OAAO,eAAeC,0BACpBC,OAAgD,EAChDC,KAA2D;IAE3D,MAAMC,UAAU,MAAML,mBAAmB;QACvCM,aAAaH,QAAQG,WAAW;QAChCC,oBAAoBJ,QAAQK,YAAY;QACxCC,4BAA4BN,QAAQO,UAAU,CAACC,oBAAoB;IACrE;IAEA,IAAIN,SAAS;QACX,MAAMO,UAAU,MAAMd,KAAKe,WAAW,CAAC,OAAOC;YAC5C,MAAM,EAACC,SAAS,EAAC,GAAG,MAAMhB,iCAAiC;gBACzDe;gBACAE,oBAAoBZ,MAAMa,EAAE;gBAC5BC,WAAWb,QAAQY,EAAE;YACvB;YACA,IAAI,CAACF,WAAW,OAAO;YAEvB,MAAMI,UAAU,MAAMlB,8BAA8B;gBAClDa;gBACAR,aAAaH,QAAQG,WAAW;gBAChCC,oBAAoBJ,QAAQK,YAAY;gBACxCC,4BAA4BN,QAAQO,UAAU,CAACC,oBAAoB;gBACnES,uBAAuBjB,QAAQO,UAAU,CAACW,KAAK;gBAC/CC,sBAAsBnB,QAAQO,UAAU,CAACa,IAAI;gBAC7CC,qBAAqBrB,QAAQO,UAAU,CAACe,aAAa;YACvD;YACA,OAAON,UAAU,YAAY;QAC/B;QAEA,IAAIP,YAAY,WAAW;IAC7B;IAEAf,SAAS6B,IAAI,CACX;QACEC,SAASvB,MAAMa,EAAE;QACjBT,cAAcL,QAAQK,YAAY;QAClCG,sBAAsBR,QAAQO,UAAU,CAACC,oBAAoB;IAC/D,GACA;AAEJ"}