@earbug/db-models 0.0.60 → 0.0.63

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 (230) hide show
  1. package/.dockerignore +10 -0
  2. package/.github/workflows/publish.yaml +266 -19
  3. package/Dockerfile.generate +19 -0
  4. package/dist/AffinityRelationshipType.d.ts +2 -2
  5. package/dist/AffinityRelationshipType.js +6 -6
  6. package/dist/AppUser.d.ts +5 -5
  7. package/dist/AppUser.js +7 -7
  8. package/dist/AppUserDevice.d.ts +2 -2
  9. package/dist/AppUserDevice.js +6 -6
  10. package/dist/AppUserDeviceClassicBackup20260906.d.ts +23 -0
  11. package/dist/AppUserDeviceClassicBackup20260906.js +46 -0
  12. package/dist/AppUserFollowRelation.d.ts +3 -3
  13. package/dist/AppUserFollowRelation.js +6 -6
  14. package/dist/AppUserPlatformRelation.d.ts +13 -13
  15. package/dist/AppUserPlatformRelation.js +25 -25
  16. package/dist/CanonAlbum.d.ts +5 -5
  17. package/dist/CanonAlbum.js +10 -10
  18. package/dist/CanonArtist.d.ts +5 -5
  19. package/dist/CanonArtist.js +11 -11
  20. package/dist/CanonGenre.d.ts +3 -3
  21. package/dist/CanonGenre.js +6 -6
  22. package/dist/CanonLabel.d.ts +2 -2
  23. package/dist/CanonLabel.js +6 -6
  24. package/dist/CanonMember.d.ts +3 -3
  25. package/dist/CanonMember.js +6 -6
  26. package/dist/CanonMemberExternalReferenceRelation.d.ts +2 -2
  27. package/dist/CanonMemberExternalReferenceRelation.js +5 -5
  28. package/dist/CanonTrack.d.ts +5 -5
  29. package/dist/CanonTrack.js +11 -11
  30. package/dist/ConfigParam.d.ts +2 -2
  31. package/dist/ConfigParam.js +5 -5
  32. package/dist/ExternalReference.d.ts +2 -2
  33. package/dist/ExternalReference.js +5 -5
  34. package/dist/FeedContentType.d.ts +2 -2
  35. package/dist/FeedContentType.js +4 -4
  36. package/dist/GuestUser.d.ts +5 -5
  37. package/dist/GuestUser.js +13 -13
  38. package/dist/JukeboxAccessType.d.ts +2 -2
  39. package/dist/JukeboxAccessType.js +4 -4
  40. package/dist/JukeboxCanonGenreRelation.d.ts +2 -2
  41. package/dist/JukeboxCanonGenreRelation.js +6 -6
  42. package/dist/JukeboxInvite.d.ts +3 -3
  43. package/dist/JukeboxInvite.js +6 -6
  44. package/dist/JukeboxQueueEntry.d.ts +9 -9
  45. package/dist/JukeboxQueueEntry.js +25 -25
  46. package/dist/JukeboxQueueMode.d.ts +2 -2
  47. package/dist/JukeboxQueueMode.js +4 -4
  48. package/dist/JukeboxSession.d.ts +9 -9
  49. package/dist/JukeboxSession.js +20 -20
  50. package/dist/JukeboxSessionArtistAffinity.d.ts +2 -2
  51. package/dist/JukeboxSessionArtistAffinity.js +6 -6
  52. package/dist/JukeboxSessionGenreAffinity.d.ts +2 -2
  53. package/dist/JukeboxSessionGenreAffinity.js +6 -6
  54. package/dist/JukeboxTerminationCondition.d.ts +2 -2
  55. package/dist/JukeboxTerminationCondition.js +4 -4
  56. package/dist/JukeboxType.d.ts +2 -2
  57. package/dist/JukeboxType.js +4 -4
  58. package/dist/JukeboxUser.d.ts +7 -7
  59. package/dist/JukeboxUser.js +20 -20
  60. package/dist/KnexMigrations.d.ts +3 -3
  61. package/dist/KnexMigrations.js +6 -6
  62. package/dist/KnexMigrationsLock.d.ts +3 -3
  63. package/dist/KnexMigrationsLock.js +5 -5
  64. package/dist/MerchItem.d.ts +3 -3
  65. package/dist/MerchItem.js +6 -6
  66. package/dist/MerchOrchestration.d.ts +3 -3
  67. package/dist/MerchOrchestration.js +6 -6
  68. package/dist/MerchPlatform.d.ts +2 -2
  69. package/dist/MerchPlatform.js +6 -6
  70. package/dist/MerchType.d.ts +2 -2
  71. package/dist/MerchType.js +4 -4
  72. package/dist/MetricsDaily.d.ts +3 -3
  73. package/dist/MetricsDaily.js +4 -4
  74. package/dist/NewsSite.d.ts +3 -3
  75. package/dist/NewsSite.js +6 -6
  76. package/dist/Notification.d.ts +13 -13
  77. package/dist/Notification.js +33 -33
  78. package/dist/Platform.d.ts +2 -2
  79. package/dist/Platform.js +7 -7
  80. package/dist/PlatformAlbum.d.ts +5 -5
  81. package/dist/PlatformAlbum.js +10 -10
  82. package/dist/PlatformArtist.d.ts +5 -5
  83. package/dist/PlatformArtist.js +10 -10
  84. package/dist/PlatformGenre.d.ts +2 -2
  85. package/dist/PlatformGenre.js +6 -6
  86. package/dist/PlatformTrack.d.ts +3 -3
  87. package/dist/PlatformTrack.js +6 -6
  88. package/dist/PlatformUserAlbum.d.ts +2 -2
  89. package/dist/PlatformUserAlbum.js +6 -6
  90. package/dist/PlatformUserAlbumTrack.d.ts +4 -4
  91. package/dist/PlatformUserAlbumTrack.js +11 -11
  92. package/dist/PlatformUserPlaylist.d.ts +5 -5
  93. package/dist/PlatformUserPlaylist.js +11 -11
  94. package/dist/PlatformUserPlaylistArtistAffinity.d.ts +4 -4
  95. package/dist/PlatformUserPlaylistArtistAffinity.js +12 -12
  96. package/dist/PlatformUserPlaylistGenreAffinity.d.ts +2 -2
  97. package/dist/PlatformUserPlaylistGenreAffinity.js +6 -6
  98. package/dist/PlatformUserPlaylistTrack.d.ts +7 -7
  99. package/dist/PlatformUserPlaylistTrack.js +17 -17
  100. package/dist/PlaybackStatus.d.ts +2 -2
  101. package/dist/PlaybackStatus.js +4 -4
  102. package/dist/RadioShow.d.ts +3 -3
  103. package/dist/RadioShow.js +6 -6
  104. package/dist/RadioShowMedia.d.ts +3 -3
  105. package/dist/RadioShowMedia.js +6 -6
  106. package/dist/RadioShowPlacement.d.ts +3 -3
  107. package/dist/RadioShowPlacement.js +6 -6
  108. package/dist/RadioShowPublishRequests.d.ts +3 -3
  109. package/dist/RadioShowPublishRequests.js +6 -6
  110. package/dist/State.d.ts +2 -2
  111. package/dist/State.js +4 -4
  112. package/dist/UnmatchedAlbum.d.ts +2 -2
  113. package/dist/UnmatchedAlbum.js +6 -6
  114. package/dist/UnmatchedArtist.d.ts +2 -2
  115. package/dist/UnmatchedArtist.js +6 -6
  116. package/dist/UserAbuseReports.d.ts +7 -7
  117. package/dist/UserAbuseReports.js +18 -18
  118. package/dist/UserAffinity.d.ts +2 -2
  119. package/dist/UserAffinity.js +6 -6
  120. package/dist/UserArtistAffinity.d.ts +2 -2
  121. package/dist/UserArtistAffinity.js +6 -6
  122. package/dist/UserBookmarks.d.ts +3 -3
  123. package/dist/UserBookmarks.js +6 -6
  124. package/dist/UserComments.d.ts +5 -5
  125. package/dist/UserComments.js +12 -12
  126. package/dist/UserContacts.d.ts +3 -3
  127. package/dist/UserContacts.js +7 -7
  128. package/dist/UserEngagementFactor.d.ts +2 -2
  129. package/dist/UserEngagementFactor.js +6 -6
  130. package/dist/UserGenreAffinity.d.ts +2 -2
  131. package/dist/UserGenreAffinity.js +6 -6
  132. package/dist/UserLikes.d.ts +3 -3
  133. package/dist/UserLikes.js +6 -6
  134. package/dist/UserMessages.d.ts +5 -5
  135. package/dist/UserMessages.js +15 -15
  136. package/dist/Versus.d.ts +5 -5
  137. package/dist/Versus.js +11 -11
  138. package/dist/VersusCoCreator.d.ts +4 -4
  139. package/dist/VersusCoCreator.js +12 -12
  140. package/dist/VersusOption.d.ts +3 -3
  141. package/dist/VersusOption.js +6 -6
  142. package/dist/VersusPublishIssue.d.ts +3 -3
  143. package/dist/VersusPublishIssue.js +6 -6
  144. package/dist/VersusQuestion.d.ts +2 -2
  145. package/dist/VersusQuestion.js +6 -6
  146. package/dist/VersusVote.d.ts +2 -2
  147. package/dist/VersusVote.js +6 -6
  148. package/dist/init-models.d.ts +349 -3
  149. package/dist/init-models.js +905 -1
  150. package/models/AffinityRelationshipType.ts +8 -8
  151. package/models/AppUser.ts +12 -12
  152. package/models/AppUserDevice.ts +8 -8
  153. package/models/AppUserDeviceClassicBackup20260906.ts +66 -0
  154. package/models/AppUserFollowRelation.ts +9 -9
  155. package/models/AppUserPlatformRelation.ts +38 -38
  156. package/models/CanonAlbum.ts +15 -15
  157. package/models/CanonArtist.ts +16 -16
  158. package/models/CanonGenre.ts +9 -9
  159. package/models/CanonLabel.ts +8 -8
  160. package/models/CanonMember.ts +9 -9
  161. package/models/CanonMemberExternalReferenceRelation.ts +7 -7
  162. package/models/CanonTrack.ts +16 -16
  163. package/models/ConfigParam.ts +7 -7
  164. package/models/ExternalReference.ts +7 -7
  165. package/models/FeedContentType.ts +6 -6
  166. package/models/GuestUser.ts +18 -18
  167. package/models/JukeboxAccessType.ts +6 -6
  168. package/models/JukeboxCanonGenreRelation.ts +8 -8
  169. package/models/JukeboxInvite.ts +9 -9
  170. package/models/JukeboxQueueEntry.ts +34 -34
  171. package/models/JukeboxQueueMode.ts +6 -6
  172. package/models/JukeboxSession.ts +29 -29
  173. package/models/JukeboxSessionArtistAffinity.ts +8 -8
  174. package/models/JukeboxSessionGenreAffinity.ts +8 -8
  175. package/models/JukeboxTerminationCondition.ts +6 -6
  176. package/models/JukeboxType.ts +6 -6
  177. package/models/JukeboxUser.ts +27 -27
  178. package/models/KnexMigrations.ts +9 -9
  179. package/models/KnexMigrationsLock.ts +8 -8
  180. package/models/MerchItem.ts +9 -9
  181. package/models/MerchOrchestration.ts +9 -9
  182. package/models/MerchPlatform.ts +8 -8
  183. package/models/MerchType.ts +6 -6
  184. package/models/MetricsDaily.ts +7 -7
  185. package/models/NewsSite.ts +9 -9
  186. package/models/Notification.ts +46 -46
  187. package/models/Platform.ts +9 -9
  188. package/models/PlatformAlbum.ts +15 -15
  189. package/models/PlatformArtist.ts +15 -15
  190. package/models/PlatformGenre.ts +8 -8
  191. package/models/PlatformTrack.ts +9 -9
  192. package/models/PlatformUserAlbum.ts +8 -8
  193. package/models/PlatformUserAlbumTrack.ts +15 -15
  194. package/models/PlatformUserPlaylist.ts +16 -16
  195. package/models/PlatformUserPlaylistArtistAffinity.ts +16 -16
  196. package/models/PlatformUserPlaylistGenreAffinity.ts +8 -8
  197. package/models/PlatformUserPlaylistTrack.ts +24 -24
  198. package/models/PlaybackStatus.ts +6 -6
  199. package/models/RadioShow.ts +9 -9
  200. package/models/RadioShowMedia.ts +9 -9
  201. package/models/RadioShowPlacement.ts +9 -9
  202. package/models/RadioShowPublishRequests.ts +9 -9
  203. package/models/State.ts +6 -6
  204. package/models/UnmatchedAlbum.ts +8 -8
  205. package/models/UnmatchedArtist.ts +8 -8
  206. package/models/UserAbuseReports.ts +25 -25
  207. package/models/UserAffinity.ts +8 -8
  208. package/models/UserArtistAffinity.ts +8 -8
  209. package/models/UserBookmarks.ts +9 -9
  210. package/models/UserComments.ts +17 -17
  211. package/models/UserContacts.ts +10 -10
  212. package/models/UserEngagementFactor.ts +8 -8
  213. package/models/UserGenreAffinity.ts +8 -8
  214. package/models/UserLikes.ts +9 -9
  215. package/models/UserMessages.ts +20 -20
  216. package/models/Versus.ts +16 -16
  217. package/models/VersusCoCreator.ts +16 -16
  218. package/models/VersusOption.ts +9 -9
  219. package/models/VersusPublishIssue.ts +9 -9
  220. package/models/VersusQuestion.ts +8 -8
  221. package/models/VersusVote.ts +8 -8
  222. package/models/init-models.ts +1245 -0
  223. package/package.json +1 -1
  224. package/scripts/generate-and-upload.mjs +123 -0
  225. package/dist/CanonAlbumImageHarvested.d.ts +0 -30
  226. package/dist/CanonAlbumImageHarvested.js +0 -70
  227. package/dist/CanonArtistImageHarvested.d.ts +0 -30
  228. package/dist/CanonArtistImageHarvested.js +0 -70
  229. package/models/CanonAlbumImageHarvested.ts +0 -98
  230. package/models/CanonArtistImageHarvested.ts +0 -98
package/.dockerignore ADDED
@@ -0,0 +1,10 @@
1
+ *
2
+ !.dockerignore
3
+ !Dockerfile.generate
4
+ !package.json
5
+ !package-lock.json
6
+ !model_options.json
7
+ !models/
8
+ !models/**
9
+ !scripts/
10
+ !scripts/generate-and-upload.mjs
@@ -4,53 +4,300 @@ on:
4
4
  repository_dispatch:
5
5
  types: [migration_completed]
6
6
 
7
+ concurrency:
8
+ group: db-models-publish
9
+ cancel-in-progress: false
10
+
7
11
  jobs:
8
12
  publish:
9
13
  name: Regenerate, Build, and Publish
10
14
  runs-on: ubuntu-latest
15
+ timeout-minutes: 30
16
+ environment: dev
17
+ env:
18
+ AWS_REGION: us-east-1
19
+ SSM_PREFIX: /earbug-dev/db-models
20
+ AWS_ACCOUNT_ID: "630596767721"
21
+ ECR_REGISTRY_ACCOUNT_ID: "146319281891"
11
22
  permissions:
12
- contents: write
23
+ contents: read
13
24
  id-token: write
14
25
  steps:
15
- - uses: actions/checkout@v6
26
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
16
27
  with:
17
- token: ${{ secrets.MODELS_DISPATCH_TOKEN }}
28
+ persist-credentials: false
18
29
 
19
- - uses: actions/setup-node@v6
30
+ - name: Configure AWS credentials
31
+ uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4
20
32
  with:
21
- node-version: 24
22
- registry-url: https://registry.npmjs.org
33
+ role-to-assume: arn:aws:iam::630596767721:role/earbug-db-models-ci-dev
34
+ aws-region: ${{ env.AWS_REGION }}
35
+
36
+ - name: Read ECS job configuration
37
+ run: |
38
+ set -euo pipefail
39
+
40
+ get_parameter() {
41
+ aws ssm get-parameter \
42
+ --name "$SSM_PREFIX/$1" \
43
+ --query Parameter.Value \
44
+ --output text
45
+ }
46
+
47
+ ECS_CLUSTER="$(get_parameter cluster-arn)"
48
+ PRIVATE_SUBNETS="$(get_parameter subnets)"
49
+ SECURITY_GROUP_ID="$(get_parameter security-group-id)"
50
+ TASK_ROLE_ARN="$(get_parameter task-role-arn)"
51
+ EXECUTION_ROLE_ARN="$(get_parameter execution-role-arn)"
52
+ LOG_GROUP_NAME="$(get_parameter log-group-name)"
53
+ ECR_REGISTRY="$(get_parameter ecr-registry)"
54
+ ECR_REPO="$(get_parameter ecr-repo)"
55
+ TASK_FAMILY="$(get_parameter task-family)"
56
+ RDS_SECRET_ARN="$(get_parameter rds-secret-arn)"
57
+ PG_SSL="$(get_parameter pg-ssl)"
58
+ ARTIFACT_BUCKET="$(get_parameter artifact-bucket)"
59
+ ARTIFACT_PREFIX="$(get_parameter artifact-prefix)"
60
+
61
+ for name in ECS_CLUSTER PRIVATE_SUBNETS SECURITY_GROUP_ID TASK_ROLE_ARN EXECUTION_ROLE_ARN \
62
+ LOG_GROUP_NAME ECR_REGISTRY ECR_REPO TASK_FAMILY RDS_SECRET_ARN PG_SSL \
63
+ ARTIFACT_BUCKET ARTIFACT_PREFIX; do
64
+ value="${!name}"
65
+ if [ -z "$value" ] || [ "$value" = "None" ] || [[ "$value" == *$'\n'* ]]; then
66
+ echo "::error::Invalid $name value from SSM"
67
+ exit 1
68
+ fi
69
+ done
23
70
 
24
- - run: npm ci
71
+ if [ "$PG_SSL" != "true" ]; then
72
+ echo "::error::PG_SSL must be true"
73
+ exit 1
74
+ fi
25
75
 
26
- - name: Patch sequelize-auto to support citext
76
+ EXPECTED_ECR_REGISTRY="${ECR_REGISTRY_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
77
+ EXPECTED_CLUSTER="arn:aws:ecs:${AWS_REGION}:${AWS_ACCOUNT_ID}:cluster/earbug-dev-cluster"
78
+ EXPECTED_TASK_ROLE="arn:aws:iam::${AWS_ACCOUNT_ID}:role/earbug-dev-db-models-ecs-task-role"
79
+ EXPECTED_EXECUTION_ROLE="arn:aws:iam::${AWS_ACCOUNT_ID}:role/earbug-dev-db-models-ecs-execution-role"
80
+
81
+ [ "$ECS_CLUSTER" = "$EXPECTED_CLUSTER" ] || { echo "::error::Unexpected ECS cluster"; exit 1; }
82
+ [ "$TASK_ROLE_ARN" = "$EXPECTED_TASK_ROLE" ] || { echo "::error::Unexpected task role"; exit 1; }
83
+ [ "$EXECUTION_ROLE_ARN" = "$EXPECTED_EXECUTION_ROLE" ] || { echo "::error::Unexpected execution role"; exit 1; }
84
+ [ "$ECR_REGISTRY" = "$EXPECTED_ECR_REGISTRY" ] || { echo "::error::Unexpected ECR registry"; exit 1; }
85
+ [ "$ECR_REPO" = "earbug/db-models-generate" ] || { echo "::error::Unexpected ECR repository"; exit 1; }
86
+ [ "$TASK_FAMILY" = "earbug-dev-db-models" ] || { echo "::error::Unexpected task family"; exit 1; }
87
+ [ "$LOG_GROUP_NAME" = "/ecs/earbug-dev-db-models" ] || { echo "::error::Unexpected log group"; exit 1; }
88
+ [[ "$PRIVATE_SUBNETS" =~ ^subnet-[a-z0-9]+(,subnet-[a-z0-9]+)*$ ]] || { echo "::error::Invalid subnet list"; exit 1; }
89
+ [[ "$SECURITY_GROUP_ID" =~ ^sg-[a-z0-9]+$ ]] || { echo "::error::Invalid security group"; exit 1; }
90
+ [[ "$RDS_SECRET_ARN" =~ ^arn:aws:secretsmanager:${AWS_REGION}:${AWS_ACCOUNT_ID}:secret:rds/earbug-dev/credentials-[A-Za-z0-9_-]+$ ]] || { echo "::error::Unexpected RDS secret ARN"; exit 1; }
91
+ [ "$ARTIFACT_BUCKET" = "earbug-dev-db-models-artifacts" ] || { echo "::error::Unexpected artifact bucket"; exit 1; }
92
+ [ "$ARTIFACT_PREFIX" = "models/" ] || { echo "::error::Unexpected artifact prefix"; exit 1; }
93
+
94
+ {
95
+ printf 'ECS_CLUSTER=%s\n' "$ECS_CLUSTER"
96
+ printf 'PRIVATE_SUBNETS=%s\n' "$PRIVATE_SUBNETS"
97
+ printf 'SECURITY_GROUP_ID=%s\n' "$SECURITY_GROUP_ID"
98
+ printf 'TASK_ROLE_ARN=%s\n' "$TASK_ROLE_ARN"
99
+ printf 'EXECUTION_ROLE_ARN=%s\n' "$EXECUTION_ROLE_ARN"
100
+ printf 'LOG_GROUP_NAME=%s\n' "$LOG_GROUP_NAME"
101
+ printf 'ECR_REGISTRY=%s\n' "$ECR_REGISTRY"
102
+ printf 'ECR_REPO=%s\n' "$ECR_REPO"
103
+ printf 'TASK_FAMILY=%s\n' "$TASK_FAMILY"
104
+ printf 'RDS_SECRET_ARN=%s\n' "$RDS_SECRET_ARN"
105
+ printf 'PG_SSL=%s\n' "$PG_SSL"
106
+ printf 'ARTIFACT_BUCKET=%s\n' "$ARTIFACT_BUCKET"
107
+ printf 'ARTIFACT_PREFIX=%s\n' "$ARTIFACT_PREFIX"
108
+ } >> "$GITHUB_ENV"
109
+
110
+ - name: Build and push generator image
27
111
  run: |
28
- sed -i 's/\^(char/\^(citext|char/' \
29
- node_modules/sequelize-auto/lib/auto-generator.js
112
+ set -euo pipefail
113
+ IMAGE_TAG="${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
114
+ IMAGE_URI="${ECR_REGISTRY}/${ECR_REPO}:${IMAGE_TAG}"
115
+ aws ecr get-login-password --region "$AWS_REGION" \
116
+ | docker login --username AWS --password-stdin "$ECR_REGISTRY"
117
+ docker build -f Dockerfile.generate -t "$IMAGE_URI" .
118
+ docker push "$IMAGE_URI"
119
+ echo "IMAGE_URI=$IMAGE_URI" >> "$GITHUB_ENV"
30
120
 
31
- - name: Generate models from dev database
121
+ - name: Register model-generation task
32
122
  run: |
33
- npx sequelize-auto -l ts --cm=p --cf=p --cp=c -o "./models" -a ./model_options.json \
34
- -d earbug_live -h "$DEV_EB_DB_HOST" -u postgres -x "$DEV_EB_DB_USER_PASSWORD" -p 5432 -e postgres \
35
- -T harvested_article article_to_artist_relation
36
- env:
37
- DEV_EB_DB_HOST: ${{ secrets.DEV_EB_DB_HOST }}
38
- DEV_EB_DB_USER_PASSWORD: ${{ secrets.DEV_EB_DB_USER_PASSWORD }}
123
+ set -euo pipefail
124
+ ARTIFACT_KEY="${ARTIFACT_PREFIX}${GITHUB_RUN_ID}-${GITHUB_SHA}/models.tgz"
125
+ jq -n \
126
+ --arg family "$TASK_FAMILY" \
127
+ --arg taskRoleArn "$TASK_ROLE_ARN" \
128
+ --arg executionRoleArn "$EXECUTION_ROLE_ARN" \
129
+ --arg image "$IMAGE_URI" \
130
+ --arg region "$AWS_REGION" \
131
+ --arg logGroup "$LOG_GROUP_NAME" \
132
+ --arg secretArn "$RDS_SECRET_ARN" \
133
+ --arg pgSsl "$PG_SSL" \
134
+ --arg artifactBucket "$ARTIFACT_BUCKET" \
135
+ --arg artifactKey "$ARTIFACT_KEY" \
136
+ '{
137
+ family: $family,
138
+ networkMode: "awsvpc",
139
+ requiresCompatibilities: ["FARGATE"],
140
+ cpu: "512",
141
+ memory: "1024",
142
+ taskRoleArn: $taskRoleArn,
143
+ executionRoleArn: $executionRoleArn,
144
+ containerDefinitions: [{
145
+ name: "db-models",
146
+ image: $image,
147
+ essential: true,
148
+ environment: [
149
+ {name: "AWS_REGION", value: $region},
150
+ {name: "PG_SSL", value: $pgSsl},
151
+ {name: "ARTIFACT_BUCKET", value: $artifactBucket},
152
+ {name: "ARTIFACT_KEY", value: $artifactKey}
153
+ ],
154
+ secrets: [
155
+ {name: "PGHOST", valueFrom: ($secretArn + ":host::")},
156
+ {name: "PGPORT", valueFrom: ($secretArn + ":port::")},
157
+ {name: "PGUSER", valueFrom: ($secretArn + ":username::")},
158
+ {name: "PGPASSWORD", valueFrom: ($secretArn + ":password::")},
159
+ {name: "PGDATABASE", valueFrom: ($secretArn + ":dbname::")}
160
+ ],
161
+ logConfiguration: {
162
+ logDriver: "awslogs",
163
+ options: {
164
+ "awslogs-group": $logGroup,
165
+ "awslogs-region": $region,
166
+ "awslogs-stream-prefix": "db-models"
167
+ }
168
+ }
169
+ }]
170
+ }' > /tmp/task-definition.json
171
+
172
+ TASK_DEFINITION_ARN=$(aws ecs register-task-definition \
173
+ --cli-input-json file:///tmp/task-definition.json \
174
+ --query taskDefinition.taskDefinitionArn \
175
+ --output text)
176
+ echo "TASK_DEFINITION_ARN=$TASK_DEFINITION_ARN" >> "$GITHUB_ENV"
177
+ echo "ARTIFACT_KEY=$ARTIFACT_KEY" >> "$GITHUB_ENV"
178
+
179
+ - name: Run model-generation task
180
+ run: |
181
+ set -euo pipefail
182
+ NETWORK_CONFIGURATION=$(jq -cn \
183
+ --arg subnets "$PRIVATE_SUBNETS" \
184
+ --arg securityGroup "$SECURITY_GROUP_ID" \
185
+ '{awsvpcConfiguration: {
186
+ subnets: ($subnets | split(",")),
187
+ securityGroups: [$securityGroup],
188
+ assignPublicIp: "DISABLED"
189
+ }}')
190
+
191
+ RUN_RESULT=$(aws ecs run-task \
192
+ --cluster "$ECS_CLUSTER" \
193
+ --launch-type FARGATE \
194
+ --task-definition "$TASK_DEFINITION_ARN" \
195
+ --network-configuration "$NETWORK_CONFIGURATION" \
196
+ --started-by "github-${GITHUB_RUN_ID}")
197
+ TASK_ARN=$(jq -r '.tasks[0].taskArn // empty' <<< "$RUN_RESULT")
198
+
199
+ if [ -z "$TASK_ARN" ]; then
200
+ jq '.failures' <<< "$RUN_RESULT"
201
+ exit 1
202
+ fi
203
+
204
+ echo "TASK_ARN=$TASK_ARN" >> "$GITHUB_ENV"
205
+ aws ecs wait tasks-stopped --cluster "$ECS_CLUSTER" --tasks "$TASK_ARN"
206
+
207
+ - name: Check model-generation result
208
+ run: |
209
+ set -euo pipefail
210
+ TASK_RESULT=$(aws ecs describe-tasks --cluster "$ECS_CLUSTER" --tasks "$TASK_ARN")
211
+ EXIT_CODE=$(jq -r '.tasks[0].containers[] | select(.name == "db-models") | .exitCode // -1' <<< "$TASK_RESULT")
212
+
213
+ if [ "$EXIT_CODE" -ne 0 ]; then
214
+ TASK_ID="${TASK_ARN##*/}"
215
+ LOG_STREAM="db-models/db-models/${TASK_ID}"
216
+ jq -r '.tasks[0] | "Stopped reason: " + (.stoppedReason // "unknown")' <<< "$TASK_RESULT"
217
+ echo "Task logs: ${LOG_GROUP_NAME}/${LOG_STREAM}"
218
+ exit 1
219
+ fi
220
+
221
+ - name: Download generated models
222
+ run: |
223
+ set -euo pipefail
224
+ aws s3 cp \
225
+ "s3://${ARTIFACT_BUCKET}/${ARTIFACT_KEY}" \
226
+ /tmp/models.tgz \
227
+ --checksum-mode ENABLED \
228
+ --only-show-errors
229
+ rm -rf /tmp/generated-models
230
+ mkdir /tmp/generated-models
231
+ tar -tzf /tmp/models.tgz > /tmp/models.members
232
+ while IFS= read -r member; do
233
+ case "$member" in
234
+ models|models/|models/*) ;;
235
+ *) echo "::error::Artifact contains files outside models/"; exit 1 ;;
236
+ esac
237
+ case "/$member/" in
238
+ */../*) echo "::error::Artifact contains a parent-directory path"; exit 1 ;;
239
+ esac
240
+ case "$member" in
241
+ models/index.ts|models/initDb.ts|models/rdsCaBundle.ts)
242
+ echo "::error::Artifact contains a hand-maintained file"
243
+ exit 1
244
+ ;;
245
+ esac
246
+ done < /tmp/models.members
247
+ tar -tvzf /tmp/models.tgz > /tmp/models.verbose
248
+ if awk 'substr($1, 1, 1) !~ /^[-d]$/ { found=1 } END { exit !found }' /tmp/models.verbose; then
249
+ echo "::error::Artifact contains a link or special file"
250
+ exit 1
251
+ fi
252
+ tar --no-same-owner --no-same-permissions -xzf /tmp/models.tgz -C /tmp/generated-models
253
+ for maintained in index.ts initDb.ts rdsCaBundle.ts; do
254
+ if [ -e "/tmp/generated-models/models/$maintained" ] || [ -L "/tmp/generated-models/models/$maintained" ]; then
255
+ echo "::error::Artifact contains hand-maintained file $maintained"
256
+ exit 1
257
+ fi
258
+ done
259
+ find models -mindepth 1 -maxdepth 1 \
260
+ ! -name index.ts ! -name initDb.ts ! -name rdsCaBundle.ts \
261
+ -exec rm -rf {} +
262
+ cp -a /tmp/generated-models/models/. models/
263
+ git diff --exit-code -- models/index.ts models/initDb.ts models/rdsCaBundle.ts
264
+
265
+ - name: Verify models were generated
266
+ run: |
267
+ set -euo pipefail
268
+ COUNT=$(grep -cE '^import \{ .* as _.* \} from "\./' models/init-models.ts || true)
269
+ echo "init-models.ts imports $COUNT models"
270
+ if [ "$COUNT" -lt 25 ]; then
271
+ echo "::error::Only $COUNT models generated (expected >= 25). Refusing to build or publish."
272
+ exit 1
273
+ fi
274
+
275
+ - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
276
+ with:
277
+ node-version: 24
278
+ registry-url: https://registry.npmjs.org
279
+
280
+ - run: npm ci --ignore-scripts
39
281
 
40
282
  - name: Build
41
283
  run: npm run build
42
284
 
43
285
  - name: Bump patch version
44
286
  id: version
45
- run: echo "version=$(npm version patch --no-git-tag-version)" >> $GITHUB_OUTPUT
287
+ run: echo "version=$(npm version patch --no-git-tag-version)" >> "$GITHUB_OUTPUT"
46
288
 
47
289
  - name: Publish to npm
48
290
  run: npm publish --access public
49
291
 
50
292
  - name: Commit and push changes
293
+ env:
294
+ GH_TOKEN: ${{ secrets.MODELS_DISPATCH_TOKEN }}
295
+ VERSION: ${{ steps.version.outputs.version }}
51
296
  run: |
297
+ set -euo pipefail
298
+ gh auth setup-git
52
299
  git config user.name "github-actions[bot]"
53
300
  git config user.email "github-actions[bot]@users.noreply.github.com"
54
301
  git add models/ package.json
55
- git commit -m "${{ steps.version.outputs.version }} — regenerate models and publish"
302
+ git commit -m "$VERSION - regenerate dev models and publish"
56
303
  git push
@@ -0,0 +1,19 @@
1
+ FROM amazon/aws-cli@sha256:92de75724b6a746951f0e8b915d86bbccd7cb55aff96cd0cb4f7017272160780 AS awscli
2
+ FROM node:24-bookworm-slim@sha256:eae779f20e0cdf264247f6f3b4e62510d91f168a615117ed38430ba295f55590
3
+
4
+ COPY --from=awscli /usr/local/aws-cli /usr/local/aws-cli
5
+ RUN ln -s /usr/local/aws-cli/v2/current/bin/aws /usr/local/bin/aws
6
+
7
+ WORKDIR /app
8
+
9
+ COPY package.json package-lock.json ./
10
+ RUN npm ci --ignore-scripts \
11
+ && sed -i 's/\^(char/\^(citext|char/' node_modules/sequelize-auto/lib/auto-generator.js
12
+
13
+ COPY --chown=node:node model_options.json ./
14
+ COPY --chown=node:node models ./models
15
+ COPY --chown=node:node scripts/generate-and-upload.mjs ./scripts/generate-and-upload.mjs
16
+
17
+ USER node
18
+
19
+ CMD ["node", "scripts/generate-and-upload.mjs"]
@@ -2,10 +2,10 @@ import * as Sequelize from 'sequelize';
2
2
  import { Model, Optional } from 'sequelize';
3
3
  import type { UserAffinity, UserAffinityId } from './UserAffinity';
4
4
  export interface AffinityRelationshipTypeAttributes {
5
+ id: string;
5
6
  name: string;
6
7
  category: string;
7
8
  tier: string;
8
- id: string;
9
9
  createDate?: Date;
10
10
  updateDate?: Date;
11
11
  }
@@ -14,10 +14,10 @@ export type AffinityRelationshipTypeId = AffinityRelationshipType[AffinityRelati
14
14
  export type AffinityRelationshipTypeOptionalAttributes = "id" | "createDate" | "updateDate";
15
15
  export type AffinityRelationshipTypeCreationAttributes = Optional<AffinityRelationshipTypeAttributes, AffinityRelationshipTypeOptionalAttributes>;
16
16
  export declare class AffinityRelationshipType extends Model<AffinityRelationshipTypeAttributes, AffinityRelationshipTypeCreationAttributes> implements AffinityRelationshipTypeAttributes {
17
+ id: string;
17
18
  name: string;
18
19
  category: string;
19
20
  tier: string;
20
- id: string;
21
21
  createDate?: Date;
22
22
  updateDate?: Date;
23
23
  userAffinities: UserAffinity[];
@@ -29,6 +29,12 @@ const sequelize_1 = require("sequelize");
29
29
  class AffinityRelationshipType extends sequelize_1.Model {
30
30
  static initModel(sequelize) {
31
31
  return AffinityRelationshipType.init({
32
+ id: {
33
+ type: sequelize_1.DataTypes.UUID,
34
+ allowNull: false,
35
+ defaultValue: sequelize_1.DataTypes.UUIDV4,
36
+ primaryKey: true
37
+ },
32
38
  name: {
33
39
  type: sequelize_1.DataTypes.STRING(50),
34
40
  allowNull: false,
@@ -42,12 +48,6 @@ class AffinityRelationshipType extends sequelize_1.Model {
42
48
  type: sequelize_1.DataTypes.STRING(20),
43
49
  allowNull: false
44
50
  },
45
- id: {
46
- type: sequelize_1.DataTypes.UUID,
47
- allowNull: false,
48
- defaultValue: sequelize_1.DataTypes.UUIDV4,
49
- primaryKey: true
50
- },
51
51
  createDate: {
52
52
  type: sequelize_1.DataTypes.DATE,
53
53
  allowNull: true,
package/dist/AppUser.d.ts CHANGED
@@ -26,9 +26,9 @@ import type { VersusCoCreator, VersusCoCreatorId } from './VersusCoCreator';
26
26
  import type { VersusOption, VersusOptionId } from './VersusOption';
27
27
  import type { VersusVote, VersusVoteId } from './VersusVote';
28
28
  export interface AppUserAttributes {
29
- firstName: string;
30
- email?: string;
31
29
  id: string;
30
+ email?: string;
31
+ firstName: string;
32
32
  createDate: Date;
33
33
  updateDate: Date;
34
34
  syncContacts?: boolean;
@@ -52,12 +52,12 @@ export interface AppUserAttributes {
52
52
  }
53
53
  export type AppUserPk = "id";
54
54
  export type AppUserId = AppUser[AppUserPk];
55
- export type AppUserOptionalAttributes = "email" | "id" | "createDate" | "updateDate" | "syncContacts" | "stateId" | "lastName" | "autoApproveFollowers" | "lastHarvested" | "lastHarvestedError" | "earbugAccessControlPreference" | "unsubscribeAll" | "unsubscribeBiweeklyEmail" | "unsubscribeFollowingNotifications" | "unsubscribeInterestNotifications" | "unsubscribeFunNotifications" | "hardBounce" | "softBounce1" | "softBounce2" | "softBounce3" | "bio";
55
+ export type AppUserOptionalAttributes = "id" | "email" | "createDate" | "updateDate" | "syncContacts" | "stateId" | "lastName" | "autoApproveFollowers" | "lastHarvested" | "lastHarvestedError" | "earbugAccessControlPreference" | "unsubscribeAll" | "unsubscribeBiweeklyEmail" | "unsubscribeFollowingNotifications" | "unsubscribeInterestNotifications" | "unsubscribeFunNotifications" | "hardBounce" | "softBounce1" | "softBounce2" | "softBounce3" | "bio";
56
56
  export type AppUserCreationAttributes = Optional<AppUserAttributes, AppUserOptionalAttributes>;
57
57
  export declare class AppUser extends Model<AppUserAttributes, AppUserCreationAttributes> implements AppUserAttributes {
58
- firstName: string;
59
- email?: string;
60
58
  id: string;
59
+ email?: string;
60
+ firstName: string;
61
61
  createDate: Date;
62
62
  updateDate: Date;
63
63
  syncContacts?: boolean;
package/dist/AppUser.js CHANGED
@@ -29,21 +29,21 @@ const sequelize_1 = require("sequelize");
29
29
  class AppUser extends sequelize_1.Model {
30
30
  static initModel(sequelize) {
31
31
  return AppUser.init({
32
- firstName: {
33
- type: sequelize_1.DataTypes.TEXT,
32
+ id: {
33
+ type: sequelize_1.DataTypes.UUID,
34
34
  allowNull: false,
35
- field: 'first_name'
35
+ defaultValue: Sequelize.Sequelize.fn('uuid_generate_v1'),
36
+ primaryKey: true
36
37
  },
37
38
  email: {
38
39
  type: sequelize_1.DataTypes.TEXT,
39
40
  allowNull: true,
40
41
  unique: "uk_app_user_email"
41
42
  },
42
- id: {
43
- type: sequelize_1.DataTypes.UUID,
43
+ firstName: {
44
+ type: sequelize_1.DataTypes.TEXT,
44
45
  allowNull: false,
45
- defaultValue: Sequelize.Sequelize.fn('uuid_generate_v1'),
46
- primaryKey: true
46
+ field: 'first_name'
47
47
  },
48
48
  createDate: {
49
49
  type: sequelize_1.DataTypes.DATE,
@@ -3,10 +3,10 @@ import { Model, Optional } from 'sequelize';
3
3
  import type { AppUser, AppUserId } from './AppUser';
4
4
  export interface AppUserDeviceAttributes {
5
5
  id: string;
6
- createdAt: Date;
7
6
  appUserId: string;
8
7
  devicePlatformId: number;
9
8
  endpointArn: string;
9
+ createdAt: Date;
10
10
  platformApplicationArn?: string;
11
11
  }
12
12
  export type AppUserDevicePk = "id";
@@ -15,10 +15,10 @@ export type AppUserDeviceOptionalAttributes = "id" | "createdAt" | "platformAppl
15
15
  export type AppUserDeviceCreationAttributes = Optional<AppUserDeviceAttributes, AppUserDeviceOptionalAttributes>;
16
16
  export declare class AppUserDevice extends Model<AppUserDeviceAttributes, AppUserDeviceCreationAttributes> implements AppUserDeviceAttributes {
17
17
  id: string;
18
- createdAt: Date;
19
18
  appUserId: string;
20
19
  devicePlatformId: number;
21
20
  endpointArn: string;
21
+ createdAt: Date;
22
22
  platformApplicationArn?: string;
23
23
  appUser: AppUser;
24
24
  getAppUser: Sequelize.BelongsToGetAssociationMixin<AppUser>;
@@ -35,12 +35,6 @@ class AppUserDevice extends sequelize_1.Model {
35
35
  defaultValue: sequelize_1.DataTypes.UUIDV4,
36
36
  primaryKey: true
37
37
  },
38
- createdAt: {
39
- type: sequelize_1.DataTypes.DATE,
40
- allowNull: false,
41
- defaultValue: Sequelize.Sequelize.literal('CURRENT_TIMESTAMP'),
42
- field: 'created_at'
43
- },
44
38
  appUserId: {
45
39
  type: sequelize_1.DataTypes.UUID,
46
40
  allowNull: false,
@@ -61,6 +55,12 @@ class AppUserDevice extends sequelize_1.Model {
61
55
  unique: "unique_app_user_device_endpoint_arn",
62
56
  field: 'endpoint_arn'
63
57
  },
58
+ createdAt: {
59
+ type: sequelize_1.DataTypes.DATE,
60
+ allowNull: false,
61
+ defaultValue: Sequelize.Sequelize.literal('CURRENT_TIMESTAMP'),
62
+ field: 'created_at'
63
+ },
64
64
  platformApplicationArn: {
65
65
  type: sequelize_1.DataTypes.TEXT,
66
66
  allowNull: true,
@@ -0,0 +1,23 @@
1
+ import * as Sequelize from 'sequelize';
2
+ import { Model, Optional } from 'sequelize';
3
+ export interface AppUserDeviceClassicBackup20260906Attributes {
4
+ id?: string;
5
+ appUserId?: string;
6
+ devicePlatformId?: number;
7
+ endpointArn?: string;
8
+ createdAt?: Date;
9
+ platformApplicationArn?: string;
10
+ }
11
+ export type AppUserDeviceClassicBackup20260906Pk = "id";
12
+ export type AppUserDeviceClassicBackup20260906Id = AppUserDeviceClassicBackup20260906[AppUserDeviceClassicBackup20260906Pk];
13
+ export type AppUserDeviceClassicBackup20260906OptionalAttributes = "id" | "appUserId" | "devicePlatformId" | "endpointArn" | "createdAt" | "platformApplicationArn";
14
+ export type AppUserDeviceClassicBackup20260906CreationAttributes = Optional<AppUserDeviceClassicBackup20260906Attributes, AppUserDeviceClassicBackup20260906OptionalAttributes>;
15
+ export declare class AppUserDeviceClassicBackup20260906 extends Model<AppUserDeviceClassicBackup20260906Attributes, AppUserDeviceClassicBackup20260906CreationAttributes> implements AppUserDeviceClassicBackup20260906Attributes {
16
+ id?: string;
17
+ appUserId?: string;
18
+ devicePlatformId?: number;
19
+ endpointArn?: string;
20
+ createdAt?: Date;
21
+ platformApplicationArn?: string;
22
+ static initModel(sequelize: Sequelize.Sequelize): typeof AppUserDeviceClassicBackup20260906;
23
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AppUserDeviceClassicBackup20260906 = void 0;
4
+ const sequelize_1 = require("sequelize");
5
+ class AppUserDeviceClassicBackup20260906 extends sequelize_1.Model {
6
+ static initModel(sequelize) {
7
+ return AppUserDeviceClassicBackup20260906.init({
8
+ id: {
9
+ type: sequelize_1.DataTypes.UUID,
10
+ allowNull: true,
11
+ primaryKey: true
12
+ },
13
+ appUserId: {
14
+ type: sequelize_1.DataTypes.UUID,
15
+ allowNull: true,
16
+ field: 'app_user_id'
17
+ },
18
+ devicePlatformId: {
19
+ type: sequelize_1.DataTypes.SMALLINT,
20
+ allowNull: true,
21
+ field: 'device_platform_id'
22
+ },
23
+ endpointArn: {
24
+ type: sequelize_1.DataTypes.TEXT,
25
+ allowNull: true,
26
+ field: 'endpoint_arn'
27
+ },
28
+ createdAt: {
29
+ type: sequelize_1.DataTypes.DATE,
30
+ allowNull: true,
31
+ field: 'created_at'
32
+ },
33
+ platformApplicationArn: {
34
+ type: sequelize_1.DataTypes.TEXT,
35
+ allowNull: true,
36
+ field: 'platform_application_arn'
37
+ }
38
+ }, {
39
+ sequelize,
40
+ tableName: 'app_user_device_classic_backup_20260906',
41
+ schema: 'eb',
42
+ timestamps: false
43
+ });
44
+ }
45
+ }
46
+ exports.AppUserDeviceClassicBackup20260906 = AppUserDeviceClassicBackup20260906;
@@ -2,26 +2,26 @@ import * as Sequelize from 'sequelize';
2
2
  import { Model, Optional } from 'sequelize';
3
3
  import type { AppUser, AppUserId } from './AppUser';
4
4
  export interface AppUserFollowRelationAttributes {
5
+ id: string;
5
6
  appUserId: string;
6
7
  followingAppUserId: string;
7
8
  stateId: number;
8
9
  isBlocked: boolean;
9
10
  createdAt: Date;
10
11
  updatedAt: Date;
11
- id: string;
12
12
  }
13
13
  export type AppUserFollowRelationPk = "id";
14
14
  export type AppUserFollowRelationId = AppUserFollowRelation[AppUserFollowRelationPk];
15
- export type AppUserFollowRelationOptionalAttributes = "stateId" | "createdAt" | "updatedAt" | "id";
15
+ export type AppUserFollowRelationOptionalAttributes = "id" | "stateId" | "createdAt" | "updatedAt";
16
16
  export type AppUserFollowRelationCreationAttributes = Optional<AppUserFollowRelationAttributes, AppUserFollowRelationOptionalAttributes>;
17
17
  export declare class AppUserFollowRelation extends Model<AppUserFollowRelationAttributes, AppUserFollowRelationCreationAttributes> implements AppUserFollowRelationAttributes {
18
+ id: string;
18
19
  appUserId: string;
19
20
  followingAppUserId: string;
20
21
  stateId: number;
21
22
  isBlocked: boolean;
22
23
  createdAt: Date;
23
24
  updatedAt: Date;
24
- id: string;
25
25
  appUser: AppUser;
26
26
  getAppUser: Sequelize.BelongsToGetAssociationMixin<AppUser>;
27
27
  setAppUser: Sequelize.BelongsToSetAssociationMixin<AppUser, AppUserId>;
@@ -29,6 +29,12 @@ const sequelize_1 = require("sequelize");
29
29
  class AppUserFollowRelation extends sequelize_1.Model {
30
30
  static initModel(sequelize) {
31
31
  return AppUserFollowRelation.init({
32
+ id: {
33
+ type: sequelize_1.DataTypes.UUID,
34
+ allowNull: false,
35
+ defaultValue: sequelize_1.DataTypes.UUIDV4,
36
+ primaryKey: true
37
+ },
32
38
  appUserId: {
33
39
  type: sequelize_1.DataTypes.UUID,
34
40
  allowNull: false,
@@ -72,12 +78,6 @@ class AppUserFollowRelation extends sequelize_1.Model {
72
78
  allowNull: false,
73
79
  defaultValue: Sequelize.Sequelize.literal('CURRENT_TIMESTAMP'),
74
80
  field: 'updated_at'
75
- },
76
- id: {
77
- type: sequelize_1.DataTypes.UUID,
78
- allowNull: false,
79
- defaultValue: sequelize_1.DataTypes.UUIDV4,
80
- primaryKey: true
81
81
  }
82
82
  }, {
83
83
  sequelize,