thinkwork-cli 0.12.9 → 0.12.10

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.
@@ -42,14 +42,26 @@ variable "admin_cloudfront_domain_name" {
42
42
  default = ""
43
43
  }
44
44
 
45
+ variable "include_app" {
46
+ description = "When true, add app.<domain> to the ACM cert SANs and create a Cloudflare CNAME for the canonical end-user app."
47
+ type = bool
48
+ default = false
49
+ }
50
+
51
+ variable "app_cloudfront_domain_name" {
52
+ description = "CloudFront distribution domain name for the canonical end-user app. Used as the target for the app.<domain> Cloudflare CNAME when include_app is true."
53
+ type = string
54
+ default = ""
55
+ }
56
+
45
57
  variable "include_computer" {
46
- description = "When true, add computer.<domain> to the ACM cert SANs and create a Cloudflare CNAME for it. Same cycle-avoidance rationale as include_docs."
58
+ description = "When true, add computer.<domain> to the ACM cert SANs. With include_app=true this creates a compatibility redirect to app.<domain>; otherwise it creates the legacy CNAME to computer_cloudfront_domain_name."
47
59
  type = bool
48
60
  default = false
49
61
  }
50
62
 
51
63
  variable "computer_cloudfront_domain_name" {
52
- description = "CloudFront distribution domain name for the computer SPA. Used as the target for the computer.<domain> Cloudflare CNAME when include_computer is true."
64
+ description = "Deprecated CloudFront distribution domain name for the legacy computer SPA. Only used when include_computer=true and include_app=false."
53
65
  type = string
54
66
  default = ""
55
67
  }
@@ -37,6 +37,51 @@ locals {
37
37
  ? "agentcore"
38
38
  : local.hindsight_enabled ? "hindsight" : "agentcore"
39
39
  )
40
+
41
+ # The end-user app is now canonically hosted at app.<domain>. Keep
42
+ # computer_domain as a compatibility fallback so older module callers and
43
+ # stages can upgrade without a flag-day.
44
+ end_user_app_domain = var.app_domain != "" ? var.app_domain : var.computer_domain
45
+ end_user_app_certificate_arn = var.app_certificate_arn != "" ? var.app_certificate_arn : var.computer_certificate_arn
46
+ computer_compat_redirect_enabled = (
47
+ var.app_domain != "" &&
48
+ var.computer_domain != "" &&
49
+ var.computer_domain != local.end_user_app_domain
50
+ )
51
+ computer_compat_redirect_function_code = local.computer_compat_redirect_enabled ? trimspace(<<-EOF
52
+ function handler(event) {
53
+ var request = event.request;
54
+ var host = request.headers.host && request.headers.host.value;
55
+ if (host === "${var.computer_domain}") {
56
+ var parts = [];
57
+ var querystring = request.querystring || {};
58
+ for (var key in querystring) {
59
+ if (!querystring.hasOwnProperty(key)) continue;
60
+ var item = querystring[key];
61
+ if (item.multiValue) {
62
+ for (var i = 0; i < item.multiValue.length; i++) {
63
+ parts.push(key + '=' + item.multiValue[i].value);
64
+ }
65
+ } else if (item.value === '') {
66
+ parts.push(key);
67
+ } else {
68
+ parts.push(key + '=' + item.value);
69
+ }
70
+ }
71
+ return {
72
+ statusCode: 301,
73
+ statusDescription: 'Moved Permanently',
74
+ headers: {
75
+ location: {
76
+ value: "https://${local.end_user_app_domain}" + request.uri + (parts.length ? '?' + parts.join('&') : '')
77
+ }
78
+ }
79
+ };
80
+ }
81
+ return request;
82
+ }
83
+ EOF
84
+ ) : ""
40
85
  }
41
86
 
42
87
  ################################################################################
@@ -84,29 +129,31 @@ module "cognito" {
84
129
  google_oauth_client_secret = var.google_oauth_client_secret
85
130
  pre_signup_lambda_zip = var.pre_signup_lambda_zip
86
131
 
87
- # Single ThinkworkAdmin Cognito client serves both admin and computer SPAs.
132
+ # Single ThinkworkAdmin Cognito client serves both admin and end-user SPAs.
88
133
  # apps/computer reuses this client by design — same humans, same tenant
89
134
  # invitations, single sign-in across both surfaces. Each origin (admin
90
- # distribution, admin custom domain, computer distribution, computer custom
91
- # domain, plus localhost dev for both) needs both bare and /auth/callback
92
- # entries because the OAuth flow lands on /auth/callback and the SPA's
93
- # post-OAuth redirect lands on the bare origin.
94
- admin_callback_urls = concat(
135
+ # distribution, admin custom domain, app distribution, app custom domain,
136
+ # compatibility computer domain, plus localhost dev for both) needs both
137
+ # bare and /auth/callback entries because the OAuth flow lands on
138
+ # /auth/callback and the SPA's post-OAuth redirect lands on the bare origin.
139
+ admin_callback_urls = distinct(concat(
95
140
  var.admin_callback_urls,
96
141
  ["https://${module.admin_site.distribution_domain}", "https://${module.admin_site.distribution_domain}/auth/callback"],
97
142
  var.admin_domain != "" ? ["https://${var.admin_domain}", "https://${var.admin_domain}/auth/callback"] : [],
98
143
  ["https://${module.computer_site.distribution_domain}", "https://${module.computer_site.distribution_domain}/auth/callback"],
144
+ local.end_user_app_domain != "" ? ["https://${local.end_user_app_domain}", "https://${local.end_user_app_domain}/auth/callback"] : [],
99
145
  var.computer_domain != "" ? ["https://${var.computer_domain}", "https://${var.computer_domain}/auth/callback"] : [],
100
146
  ["http://localhost:5180", "http://localhost:5180/auth/callback"]
101
- )
102
- admin_logout_urls = concat(
147
+ ))
148
+ admin_logout_urls = distinct(concat(
103
149
  var.admin_logout_urls,
104
150
  ["https://${module.admin_site.distribution_domain}"],
105
151
  var.admin_domain != "" ? ["https://${var.admin_domain}"] : [],
106
152
  ["https://${module.computer_site.distribution_domain}"],
153
+ local.end_user_app_domain != "" ? ["https://${local.end_user_app_domain}"] : [],
107
154
  var.computer_domain != "" ? ["https://${var.computer_domain}"] : [],
108
155
  ["http://localhost:5180"]
109
- )
156
+ ))
110
157
  mobile_callback_urls = var.mobile_callback_urls
111
158
  mobile_logout_urls = var.mobile_logout_urls
112
159
  }
@@ -585,7 +632,7 @@ module "admin_site" {
585
632
  }
586
633
 
587
634
  ################################################################################
588
- # Computer Static Site (apps/computer — end-user surface at computer.thinkwork.ai)
635
+ # End-User App Static Site (apps/computer — canonical surface at app.thinkwork.ai)
589
636
  ################################################################################
590
637
 
591
638
  locals {
@@ -607,11 +654,15 @@ locals {
607
654
  module "computer_site" {
608
655
  source = "../app/static-site"
609
656
 
610
- stage = var.stage
611
- site_name = "computer"
612
- is_spa = true
613
- custom_domain = var.computer_domain
614
- certificate_arn = var.computer_certificate_arn
657
+ stage = var.stage
658
+ site_name = "computer"
659
+ is_spa = true
660
+ custom_domain = local.end_user_app_domain
661
+ custom_domain_aliases = local.computer_compat_redirect_enabled ? [
662
+ var.computer_domain,
663
+ ] : []
664
+ certificate_arn = local.end_user_app_certificate_arn
665
+ viewer_request_function_code = local.computer_compat_redirect_function_code
615
666
 
616
667
  # Plan-012 U10: host CSP defends the parent origin. Iframe-shell's
617
668
  # own CSP (set on computer_sandbox_site below) carries the
@@ -148,25 +148,51 @@ output "admin_url" {
148
148
  value = var.admin_domain != "" ? "https://${var.admin_domain}" : "https://${module.admin_site.distribution_domain}"
149
149
  }
150
150
 
151
- # Computer static site (apps/computer — end-user surface)
151
+ locals {
152
+ end_user_app_url = local.end_user_app_domain != "" ? "https://${local.end_user_app_domain}" : "https://${module.computer_site.distribution_domain}"
153
+ }
154
+
155
+ # End-user app static site (apps/computer — internal package name retained)
156
+ output "app_distribution_id" {
157
+ description = "CloudFront distribution ID for the end-user app"
158
+ value = module.computer_site.distribution_id
159
+ }
160
+
161
+ output "app_distribution_domain" {
162
+ description = "CloudFront domain for the end-user app"
163
+ value = module.computer_site.distribution_domain
164
+ }
165
+
166
+ output "app_bucket_name" {
167
+ description = "S3 bucket for end-user app assets"
168
+ value = module.computer_site.bucket_name
169
+ }
170
+
171
+ output "app_url" {
172
+ description = "Public URL for the end-user app (custom app domain when set, CloudFront default otherwise)"
173
+ value = local.end_user_app_url
174
+ }
175
+
176
+ # Deprecated compatibility aliases. Keep these stable for existing scripts and
177
+ # external callers while the source package remains apps/computer.
152
178
  output "computer_distribution_id" {
153
- description = "CloudFront distribution ID for the computer app"
179
+ description = "Deprecated alias for app_distribution_id"
154
180
  value = module.computer_site.distribution_id
155
181
  }
156
182
 
157
183
  output "computer_distribution_domain" {
158
- description = "CloudFront domain for the computer app"
184
+ description = "Deprecated alias for app_distribution_domain"
159
185
  value = module.computer_site.distribution_domain
160
186
  }
161
187
 
162
188
  output "computer_bucket_name" {
163
- description = "S3 bucket for computer app assets"
189
+ description = "Deprecated alias for app_bucket_name"
164
190
  value = module.computer_site.bucket_name
165
191
  }
166
192
 
167
193
  output "computer_url" {
168
- description = "Public URL for the computer app (custom domain when set, CloudFront default otherwise)"
169
- value = var.computer_domain != "" ? "https://${var.computer_domain}" : "https://${module.computer_site.distribution_domain}"
194
+ description = "Deprecated alias for app_url"
195
+ value = local.end_user_app_url
170
196
  }
171
197
 
172
198
  # Computer sandbox subdomain (plan-012 U3 / U11.5 — iframe-isolated
@@ -350,14 +350,26 @@ variable "admin_certificate_arn" {
350
350
  default = ""
351
351
  }
352
352
 
353
+ variable "app_domain" {
354
+ description = "Canonical custom domain for the end-user app (e.g. app.thinkwork.ai). Leave empty to fall back to computer_domain for compatibility."
355
+ type = string
356
+ default = ""
357
+ }
358
+
359
+ variable "app_certificate_arn" {
360
+ description = "ACM certificate ARN for the canonical end-user app domain (us-east-1, required for CloudFront custom domains). Leave empty to fall back to computer_certificate_arn for compatibility."
361
+ type = string
362
+ default = ""
363
+ }
364
+
353
365
  variable "computer_domain" {
354
- description = "Custom domain for the computer SPA (e.g. computer.thinkwork.ai). Leave empty for CloudFront default."
366
+ description = "Deprecated compatibility domain for the end-user app (e.g. computer.thinkwork.ai). When app_domain is set, this domain should redirect to app_domain instead of serving the SPA directly."
355
367
  type = string
356
368
  default = ""
357
369
  }
358
370
 
359
371
  variable "computer_certificate_arn" {
360
- description = "ACM certificate ARN for the computer domain (us-east-1, required for CloudFront custom domains)."
372
+ description = "Deprecated ACM certificate ARN for the compatibility computer domain. Prefer app_certificate_arn for new deployments."
361
373
  type = string
362
374
  default = ""
363
375
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkwork-cli",
3
- "version": "0.12.9",
3
+ "version": "0.12.10",
4
4
  "description": "Thinkwork CLI — deploy, manage, and interact with your Thinkwork stack",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",