unoverse 0.1.104 → 0.1.106

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.
@@ -167,15 +167,28 @@
167
167
  # PACKAGES_PATH any more and docker-compose.yml has no such volume, so the check could
168
168
  # only ever report 0 and tell the operator to run a command that would not fix it.
169
169
 
170
+ # SINCE THE SERVICES RESTARTED, NOT SINCE FIVE MINUTES AGO.
171
+ #
172
+ # A first setup necessarily boots the services before the schema exists — migrations run
173
+ # THROUGH the unoverse container, so there is nothing to run them in until it is up — and
174
+ # db-setup restarts everything afterwards. A fixed five-minute window straddles that
175
+ # restart and reports the pre-migration errors as if they were current: every first
176
+ # deploy ended with 'relation "memories" does not exist' in red, describing a state that
177
+ # had already been fixed two minutes earlier by this very playbook.
178
+ #
179
+ # The question is "is anything wrong NOW", so the window starts when the services did.
170
180
  - name: "[12/14] Check for errors in service logs"
171
181
  shell: |
172
182
  cd /opt/gravity
173
- ERRORS=$(docker compose logs --tail=50 --since=5m 2>&1 | grep -iE 'error|fatal|panic|does not exist|ECONNREFUSED' | grep -v 'NOGROUP' | tail -10)
183
+ # Newest container start: everything before it belongs to a previous run.
184
+ SINCE=$(docker compose ps -q 2>/dev/null | xargs -r docker inspect -f '{{.State.StartedAt}}' 2>/dev/null | sort | tail -1)
185
+ [ -n "$SINCE" ] || SINCE=5m
186
+ ERRORS=$(docker compose logs --tail=50 --since="$SINCE" 2>&1 | grep -iE 'error|fatal|panic|does not exist|ECONNREFUSED' | grep -v 'NOGROUP' | tail -10)
174
187
  if [ -n "$ERRORS" ]; then
175
188
  echo "$ERRORS"
176
189
  exit 1
177
190
  else
178
- echo "No recent errors"
191
+ echo "No errors since the services started"
179
192
  fi
180
193
  register: log_errors
181
194
  ignore_errors: yes
@@ -109,6 +109,9 @@ locals {
109
109
  # no cert, the ALB speaks plain HTTP on its DNS name. Setting domain later and
110
110
  # re-applying upgrades the SAME ALB in place — ACM cert, HTTPS listener, redirect.
111
111
  has_domain = var.domain != ""
112
+ # Where a person actually goes. Shared by the invitation email and the canvas_url output
113
+ # so the address in the email can never drift from the address in the deploy summary.
114
+ canvas_entry = var.domain != "" ? "https://canvas.${var.domain}" : "http://${aws_lb.public.dns_name}:3001"
112
115
  api_host = "api.${var.domain}"
113
116
  dns_auto = local.has_domain && var.route53_zone_id != ""
114
117
  }
@@ -419,6 +422,31 @@ resource "aws_cognito_user_pool" "pool" {
419
422
  lambda_version = "V2_0"
420
423
  }
421
424
  }
425
+
426
+ # THE INVITATION HAS TO SAY WHERE TO GO. Cognito's default message is a username and a
427
+ # temporary password and no address: the first administrator of a brand new universe
428
+ # receives credentials for a login page they have never been told the name of, and the
429
+ # hosted UI URL is buried in a terraform output they have no reason to read.
430
+ #
431
+ # The domain is built from the same random_id the domain resource uses, so this can name
432
+ # the URL without depending on that resource and creating a cycle back to this pool.
433
+ admin_create_user_config {
434
+ allow_admin_create_user_only = true
435
+ invite_message_template {
436
+ # LINK TO THE APP, NOT TO COGNITO. The hosted sign-in page needs a client_id, and the
437
+ # client is created FROM this pool — referencing it here is a dependency cycle. Canvas
438
+ # is also simply the better destination: it redirects to Cognito itself, and the
439
+ # administrator ends up where they were trying to go rather than on a login screen with
440
+ # nowhere to land afterwards.
441
+ email_subject = "Your ${var.name} universe is ready"
442
+ email_message = <<-MSG
443
+ <p>Your universe is deployed, and this account administers it.</p>
444
+ <p><b>Open it:</b> <a href="${local.canvas_entry}">${local.canvas_entry}</a></p>
445
+ <p>Username: <b>{username}</b><br/>Temporary password: <b>{####}</b></p>
446
+ <p>You will be asked to choose a new password the first time you sign in.</p>
447
+ MSG
448
+ }
449
+ }
422
450
  }
423
451
 
424
452
  # Groups ARE the RBAC surface: membership becomes the `roles`/`permissions`
@@ -24,7 +24,7 @@ output "acm_validation_records" {
24
24
 
25
25
  output "canvas_url" {
26
26
  description = "Public Canvas URL (canvas_public = true only) — add it to the client origins."
27
- value = var.canvas_public ? (local.has_domain ? "https://canvas.${var.domain}" : "http://${aws_lb.public.dns_name}:3001") : "canvas is admin-only (direct http://<instance-ip>:3001 from admin_cidr)"
27
+ value = var.canvas_public ? local.canvas_entry : "canvas is admin-only (direct http://<instance-ip>:3001 from admin_cidr)"
28
28
  }
29
29
 
30
30
  output "api_url" {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unoverse",
3
- "version": "0.1.104",
3
+ "version": "0.1.106",
4
4
  "description": "The Unoverse front door — create a Studio project, a universe, or a client app, and launch Studio.",
5
5
  "license": "SEE LICENSE IN README.md",
6
6
  "type": "module",