@topolo/cli 0.1.23 → 0.1.24
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/README.md +8 -2
- package/dist/index.js +1244 -319
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -67,6 +67,7 @@ var TopoloHttpError = class extends TopoloSdkError {
|
|
|
67
67
|
var SERVICES = {
|
|
68
68
|
agent: "https://agent-api.topolo.app",
|
|
69
69
|
auth: "https://auth.topolo.app",
|
|
70
|
+
backup: "https://backup.topolo.app",
|
|
70
71
|
books: "https://books.topolo.app",
|
|
71
72
|
bugfix: "https://bugfix.topolo.app",
|
|
72
73
|
bytes: "https://bytes-api.topolo.app",
|
|
@@ -77,7 +78,6 @@ var SERVICES = {
|
|
|
77
78
|
compose: "https://compose.topolo.app",
|
|
78
79
|
consent: "https://consent.topolo.app",
|
|
79
80
|
crm: "https://crm-api.topolo.app",
|
|
80
|
-
customer_success: "https://success.topolo.app",
|
|
81
81
|
developers: "https://developers.topolo.app",
|
|
82
82
|
director: "https://director.topolo.app",
|
|
83
83
|
feed: "https://feed-api.topolo.app",
|
|
@@ -91,9 +91,10 @@ var SERVICES = {
|
|
|
91
91
|
localize: "https://localize.topolo.app",
|
|
92
92
|
mail: "https://mail.topolo.app",
|
|
93
93
|
mdm: "https://mdm-api.topolo.app",
|
|
94
|
-
|
|
94
|
+
messages: "https://messages.topolo.app",
|
|
95
95
|
nexus: "https://nexus-api.topolo.app",
|
|
96
96
|
notify: "https://notify.topolo.app",
|
|
97
|
+
observability_watch: "https://observability-watch.topolo.app",
|
|
97
98
|
one: "https://one.topolo.app",
|
|
98
99
|
p2p: "https://p2p.topolo.app",
|
|
99
100
|
pay: "https://pay.topolo.app",
|
|
@@ -107,6 +108,7 @@ var SERVICES = {
|
|
|
107
108
|
socialize: "https://socialize-api.topolo.app",
|
|
108
109
|
spaces: "https://spaces.topolo.app",
|
|
109
110
|
status: "https://status.topolo.app",
|
|
111
|
+
success: "https://success.topolo.app",
|
|
110
112
|
support: "https://support.topolo.app",
|
|
111
113
|
survey: "https://survey.topolo.app",
|
|
112
114
|
voice: "https://voice.topolo.app",
|
|
@@ -123,13 +125,21 @@ var APPLICATIONS = {
|
|
|
123
125
|
"deployTargets": [
|
|
124
126
|
{
|
|
125
127
|
"name": "topolo-admin",
|
|
126
|
-
"kind": "
|
|
127
|
-
"apiUrl":
|
|
128
|
+
"kind": "worker",
|
|
129
|
+
"apiUrl": "https://admin.topolo.app",
|
|
128
130
|
"domains": [
|
|
129
131
|
"admin.topolo.app"
|
|
130
132
|
],
|
|
131
133
|
"routes": [],
|
|
132
134
|
"serviceId": null
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"name": "topolo-admin-api",
|
|
138
|
+
"kind": "worker",
|
|
139
|
+
"apiUrl": null,
|
|
140
|
+
"domains": [],
|
|
141
|
+
"routes": [],
|
|
142
|
+
"serviceId": null
|
|
133
143
|
}
|
|
134
144
|
]
|
|
135
145
|
},
|
|
@@ -146,7 +156,7 @@ var APPLICATIONS = {
|
|
|
146
156
|
{
|
|
147
157
|
"name": "topolo-agent",
|
|
148
158
|
"kind": "worker",
|
|
149
|
-
"apiUrl":
|
|
159
|
+
"apiUrl": "https://agent.topolo.app",
|
|
150
160
|
"domains": [
|
|
151
161
|
"agent.topolo.app"
|
|
152
162
|
],
|
|
@@ -154,7 +164,7 @@ var APPLICATIONS = {
|
|
|
154
164
|
"serviceId": null
|
|
155
165
|
},
|
|
156
166
|
{
|
|
157
|
-
"name": "topolo-agent-
|
|
167
|
+
"name": "topolo-agent-api",
|
|
158
168
|
"kind": "worker",
|
|
159
169
|
"apiUrl": "https://agent-api.topolo.app",
|
|
160
170
|
"domains": [
|
|
@@ -194,16 +204,20 @@ var APPLICATIONS = {
|
|
|
194
204
|
"appDir": "TopoloBackup",
|
|
195
205
|
"name": "topolo-backup",
|
|
196
206
|
"packageName": "topolo-backup",
|
|
197
|
-
"productionUrl":
|
|
198
|
-
"services": [
|
|
207
|
+
"productionUrl": "https://backup.topolo.app",
|
|
208
|
+
"services": [
|
|
209
|
+
"backup"
|
|
210
|
+
],
|
|
199
211
|
"deployTargets": [
|
|
200
212
|
{
|
|
201
213
|
"name": "topolo-backup",
|
|
202
214
|
"kind": "worker",
|
|
203
|
-
"apiUrl":
|
|
204
|
-
"domains": [
|
|
215
|
+
"apiUrl": "https://backup.topolo.app",
|
|
216
|
+
"domains": [
|
|
217
|
+
"backup.topolo.app"
|
|
218
|
+
],
|
|
205
219
|
"routes": [],
|
|
206
|
-
"serviceId":
|
|
220
|
+
"serviceId": "backup"
|
|
207
221
|
}
|
|
208
222
|
]
|
|
209
223
|
},
|
|
@@ -224,10 +238,16 @@ var APPLICATIONS = {
|
|
|
224
238
|
"domains": [
|
|
225
239
|
"books.topolo.app"
|
|
226
240
|
],
|
|
227
|
-
"routes": [
|
|
228
|
-
"books.topolo.app"
|
|
229
|
-
],
|
|
241
|
+
"routes": [],
|
|
230
242
|
"serviceId": "books"
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"name": "topolo-books-api",
|
|
246
|
+
"kind": "worker",
|
|
247
|
+
"apiUrl": null,
|
|
248
|
+
"domains": [],
|
|
249
|
+
"routes": [],
|
|
250
|
+
"serviceId": null
|
|
231
251
|
}
|
|
232
252
|
]
|
|
233
253
|
},
|
|
@@ -248,9 +268,7 @@ var APPLICATIONS = {
|
|
|
248
268
|
"domains": [
|
|
249
269
|
"bugfix.topolo.app"
|
|
250
270
|
],
|
|
251
|
-
"routes": [
|
|
252
|
-
"bugfix.topolo.app"
|
|
253
|
-
],
|
|
271
|
+
"routes": [],
|
|
254
272
|
"serviceId": "bugfix"
|
|
255
273
|
}
|
|
256
274
|
]
|
|
@@ -267,8 +285,8 @@ var APPLICATIONS = {
|
|
|
267
285
|
"deployTargets": [
|
|
268
286
|
{
|
|
269
287
|
"name": "topolo-bytes",
|
|
270
|
-
"kind": "
|
|
271
|
-
"apiUrl":
|
|
288
|
+
"kind": "worker",
|
|
289
|
+
"apiUrl": "https://bytes.topolo.app",
|
|
272
290
|
"domains": [
|
|
273
291
|
"bytes.topolo.app"
|
|
274
292
|
],
|
|
@@ -304,10 +322,16 @@ var APPLICATIONS = {
|
|
|
304
322
|
"domains": [
|
|
305
323
|
"calendar.topolo.app"
|
|
306
324
|
],
|
|
307
|
-
"routes": [
|
|
308
|
-
"calendar.topolo.app"
|
|
309
|
-
],
|
|
325
|
+
"routes": [],
|
|
310
326
|
"serviceId": "calendar"
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
"name": "topolo-calendar-api",
|
|
330
|
+
"kind": "worker",
|
|
331
|
+
"apiUrl": null,
|
|
332
|
+
"domains": [],
|
|
333
|
+
"routes": [],
|
|
334
|
+
"serviceId": null
|
|
311
335
|
}
|
|
312
336
|
]
|
|
313
337
|
},
|
|
@@ -350,22 +374,19 @@ var APPLICATIONS = {
|
|
|
350
374
|
"domains": [
|
|
351
375
|
"chat.topolo.app"
|
|
352
376
|
],
|
|
353
|
-
"routes": [
|
|
354
|
-
"chat.topolo.app"
|
|
355
|
-
],
|
|
377
|
+
"routes": [],
|
|
356
378
|
"serviceId": "chat"
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
"name": "topolo-chat-api",
|
|
382
|
+
"kind": "worker",
|
|
383
|
+
"apiUrl": null,
|
|
384
|
+
"domains": [],
|
|
385
|
+
"routes": [],
|
|
386
|
+
"serviceId": null
|
|
357
387
|
}
|
|
358
388
|
]
|
|
359
389
|
},
|
|
360
|
-
"cloudcontrol": {
|
|
361
|
-
"id": "cloudcontrol",
|
|
362
|
-
"appDir": "TopoloCloudControl",
|
|
363
|
-
"name": "cloudcontrol",
|
|
364
|
-
"packageName": "topolo-cloudcontrol",
|
|
365
|
-
"productionUrl": null,
|
|
366
|
-
"services": [],
|
|
367
|
-
"deployTargets": []
|
|
368
|
-
},
|
|
369
390
|
"commerce": {
|
|
370
391
|
"id": "commerce",
|
|
371
392
|
"appDir": "TopoloCommerce",
|
|
@@ -388,8 +409,8 @@ var APPLICATIONS = {
|
|
|
388
409
|
},
|
|
389
410
|
{
|
|
390
411
|
"name": "topolo-commerce-guest-web",
|
|
391
|
-
"kind": "
|
|
392
|
-
"apiUrl":
|
|
412
|
+
"kind": "worker",
|
|
413
|
+
"apiUrl": "https://guest.topolo.app",
|
|
393
414
|
"domains": [
|
|
394
415
|
"guest.topolo.app"
|
|
395
416
|
],
|
|
@@ -398,8 +419,8 @@ var APPLICATIONS = {
|
|
|
398
419
|
},
|
|
399
420
|
{
|
|
400
421
|
"name": "topolo-commerce-ops-web",
|
|
401
|
-
"kind": "
|
|
402
|
-
"apiUrl":
|
|
422
|
+
"kind": "worker",
|
|
423
|
+
"apiUrl": "https://commerce.topolo.app",
|
|
403
424
|
"domains": [
|
|
404
425
|
"commerce.topolo.app"
|
|
405
426
|
],
|
|
@@ -408,8 +429,8 @@ var APPLICATIONS = {
|
|
|
408
429
|
},
|
|
409
430
|
{
|
|
410
431
|
"name": "topolo-commerce-station-web",
|
|
411
|
-
"kind": "
|
|
412
|
-
"apiUrl":
|
|
432
|
+
"kind": "worker",
|
|
433
|
+
"apiUrl": "https://station-commerce.topolo.app",
|
|
413
434
|
"domains": [
|
|
414
435
|
"station-commerce.topolo.app"
|
|
415
436
|
],
|
|
@@ -435,10 +456,16 @@ var APPLICATIONS = {
|
|
|
435
456
|
"domains": [
|
|
436
457
|
"compose.topolo.app"
|
|
437
458
|
],
|
|
438
|
-
"routes": [
|
|
439
|
-
"compose.topolo.app"
|
|
440
|
-
],
|
|
459
|
+
"routes": [],
|
|
441
460
|
"serviceId": "compose"
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
"name": "topolo-compose-api",
|
|
464
|
+
"kind": "worker",
|
|
465
|
+
"apiUrl": null,
|
|
466
|
+
"domains": [],
|
|
467
|
+
"routes": [],
|
|
468
|
+
"serviceId": null
|
|
442
469
|
}
|
|
443
470
|
]
|
|
444
471
|
},
|
|
@@ -459,10 +486,16 @@ var APPLICATIONS = {
|
|
|
459
486
|
"domains": [
|
|
460
487
|
"consent.topolo.app"
|
|
461
488
|
],
|
|
462
|
-
"routes": [
|
|
463
|
-
"consent.topolo.app"
|
|
464
|
-
],
|
|
489
|
+
"routes": [],
|
|
465
490
|
"serviceId": "consent"
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
"name": "topolo-consent-api",
|
|
494
|
+
"kind": "worker",
|
|
495
|
+
"apiUrl": null,
|
|
496
|
+
"domains": [],
|
|
497
|
+
"routes": [],
|
|
498
|
+
"serviceId": null
|
|
466
499
|
}
|
|
467
500
|
]
|
|
468
501
|
},
|
|
@@ -489,7 +522,7 @@ var APPLICATIONS = {
|
|
|
489
522
|
{
|
|
490
523
|
"name": "topolo-crm-app",
|
|
491
524
|
"kind": "worker",
|
|
492
|
-
"apiUrl":
|
|
525
|
+
"apiUrl": "https://crm.topolo.app",
|
|
493
526
|
"domains": [
|
|
494
527
|
"crm.topolo.app"
|
|
495
528
|
],
|
|
@@ -498,30 +531,6 @@ var APPLICATIONS = {
|
|
|
498
531
|
}
|
|
499
532
|
]
|
|
500
533
|
},
|
|
501
|
-
"customer_success": {
|
|
502
|
-
"id": "customer_success",
|
|
503
|
-
"appDir": "TopoloSuccess",
|
|
504
|
-
"name": "topolo-success",
|
|
505
|
-
"packageName": "topolo-success",
|
|
506
|
-
"productionUrl": "https://success.topolo.app",
|
|
507
|
-
"services": [
|
|
508
|
-
"customer_success"
|
|
509
|
-
],
|
|
510
|
-
"deployTargets": [
|
|
511
|
-
{
|
|
512
|
-
"name": "topolo-success",
|
|
513
|
-
"kind": "worker",
|
|
514
|
-
"apiUrl": "https://success.topolo.app",
|
|
515
|
-
"domains": [
|
|
516
|
-
"success.topolo.app"
|
|
517
|
-
],
|
|
518
|
-
"routes": [
|
|
519
|
-
"success.topolo.app"
|
|
520
|
-
],
|
|
521
|
-
"serviceId": "customer_success"
|
|
522
|
-
}
|
|
523
|
-
]
|
|
524
|
-
},
|
|
525
534
|
"developers": {
|
|
526
535
|
"id": "developers",
|
|
527
536
|
"appDir": "TopoloDevelopers",
|
|
@@ -549,6 +558,14 @@ var APPLICATIONS = {
|
|
|
549
558
|
],
|
|
550
559
|
"routes": [],
|
|
551
560
|
"serviceId": "developers"
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
"name": "topolo-developers-api",
|
|
564
|
+
"kind": "worker",
|
|
565
|
+
"apiUrl": null,
|
|
566
|
+
"domains": [],
|
|
567
|
+
"routes": [],
|
|
568
|
+
"serviceId": null
|
|
552
569
|
}
|
|
553
570
|
]
|
|
554
571
|
},
|
|
@@ -569,10 +586,16 @@ var APPLICATIONS = {
|
|
|
569
586
|
"domains": [
|
|
570
587
|
"director.topolo.app"
|
|
571
588
|
],
|
|
572
|
-
"routes": [
|
|
573
|
-
"director.topolo.app"
|
|
574
|
-
],
|
|
589
|
+
"routes": [],
|
|
575
590
|
"serviceId": "director"
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
"name": "topolo-director-api",
|
|
594
|
+
"kind": "worker",
|
|
595
|
+
"apiUrl": null,
|
|
596
|
+
"domains": [],
|
|
597
|
+
"routes": [],
|
|
598
|
+
"serviceId": null
|
|
576
599
|
}
|
|
577
600
|
]
|
|
578
601
|
},
|
|
@@ -586,13 +609,21 @@ var APPLICATIONS = {
|
|
|
586
609
|
"deployTargets": [
|
|
587
610
|
{
|
|
588
611
|
"name": "topolo-docs",
|
|
589
|
-
"kind": "
|
|
590
|
-
"apiUrl":
|
|
612
|
+
"kind": "worker",
|
|
613
|
+
"apiUrl": "https://docs.topolo.app",
|
|
591
614
|
"domains": [
|
|
592
615
|
"docs.topolo.app"
|
|
593
616
|
],
|
|
594
617
|
"routes": [],
|
|
595
618
|
"serviceId": null
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
"name": "topolo-docs-api",
|
|
622
|
+
"kind": "worker",
|
|
623
|
+
"apiUrl": null,
|
|
624
|
+
"domains": [],
|
|
625
|
+
"routes": [],
|
|
626
|
+
"serviceId": null
|
|
596
627
|
}
|
|
597
628
|
]
|
|
598
629
|
},
|
|
@@ -601,7 +632,7 @@ var APPLICATIONS = {
|
|
|
601
632
|
"appDir": "TopoloFeed",
|
|
602
633
|
"name": "TopoloFeed",
|
|
603
634
|
"packageName": "topolo-feed",
|
|
604
|
-
"productionUrl": "https://feed
|
|
635
|
+
"productionUrl": "https://feed.topolo.app",
|
|
605
636
|
"services": [
|
|
606
637
|
"feed"
|
|
607
638
|
],
|
|
@@ -613,9 +644,7 @@ var APPLICATIONS = {
|
|
|
613
644
|
"domains": [
|
|
614
645
|
"feed-analytics-api.topolo.app"
|
|
615
646
|
],
|
|
616
|
-
"routes": [
|
|
617
|
-
"feed-analytics-api.topolo.app"
|
|
618
|
-
],
|
|
647
|
+
"routes": [],
|
|
619
648
|
"serviceId": null
|
|
620
649
|
},
|
|
621
650
|
{
|
|
@@ -625,10 +654,18 @@ var APPLICATIONS = {
|
|
|
625
654
|
"domains": [
|
|
626
655
|
"feed-api.topolo.app"
|
|
627
656
|
],
|
|
628
|
-
"routes": [
|
|
629
|
-
"feed-api.topolo.app"
|
|
630
|
-
],
|
|
657
|
+
"routes": [],
|
|
631
658
|
"serviceId": "feed"
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
"name": "topolo-feed-web",
|
|
662
|
+
"kind": "worker",
|
|
663
|
+
"apiUrl": "https://feed.topolo.app",
|
|
664
|
+
"domains": [
|
|
665
|
+
"feed.topolo.app"
|
|
666
|
+
],
|
|
667
|
+
"routes": [],
|
|
668
|
+
"serviceId": null
|
|
632
669
|
}
|
|
633
670
|
]
|
|
634
671
|
},
|
|
@@ -649,17 +686,23 @@ var APPLICATIONS = {
|
|
|
649
686
|
"domains": [
|
|
650
687
|
"flow.topolo.app"
|
|
651
688
|
],
|
|
652
|
-
"routes": [
|
|
653
|
-
"flow.topolo.app"
|
|
654
|
-
],
|
|
689
|
+
"routes": [],
|
|
655
690
|
"serviceId": "flow"
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
"name": "topolo-flow-api",
|
|
694
|
+
"kind": "worker",
|
|
695
|
+
"apiUrl": null,
|
|
696
|
+
"domains": [],
|
|
697
|
+
"routes": [],
|
|
698
|
+
"serviceId": null
|
|
656
699
|
}
|
|
657
700
|
]
|
|
658
701
|
},
|
|
659
702
|
"forecast": {
|
|
660
703
|
"id": "forecast",
|
|
661
704
|
"appDir": "TopoloForecast",
|
|
662
|
-
"name": "forecast
|
|
705
|
+
"name": "topolo-forecast",
|
|
663
706
|
"packageName": "topolo-forecast",
|
|
664
707
|
"productionUrl": "https://forecast.topolo.app",
|
|
665
708
|
"services": [
|
|
@@ -669,7 +712,7 @@ var APPLICATIONS = {
|
|
|
669
712
|
{
|
|
670
713
|
"name": "topolo-forecast",
|
|
671
714
|
"kind": "worker",
|
|
672
|
-
"apiUrl":
|
|
715
|
+
"apiUrl": "https://forecast.topolo.app",
|
|
673
716
|
"domains": [
|
|
674
717
|
"forecast.topolo.app"
|
|
675
718
|
],
|
|
@@ -705,10 +748,16 @@ var APPLICATIONS = {
|
|
|
705
748
|
"domains": [
|
|
706
749
|
"forms.topolo.app"
|
|
707
750
|
],
|
|
708
|
-
"routes": [
|
|
709
|
-
"forms.topolo.app"
|
|
710
|
-
],
|
|
751
|
+
"routes": [],
|
|
711
752
|
"serviceId": "forms"
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
"name": "topolo-forms-api",
|
|
756
|
+
"kind": "worker",
|
|
757
|
+
"apiUrl": null,
|
|
758
|
+
"domains": [],
|
|
759
|
+
"routes": [],
|
|
760
|
+
"serviceId": null
|
|
712
761
|
}
|
|
713
762
|
]
|
|
714
763
|
},
|
|
@@ -729,10 +778,16 @@ var APPLICATIONS = {
|
|
|
729
778
|
"domains": [
|
|
730
779
|
"home.topolo.app"
|
|
731
780
|
],
|
|
732
|
-
"routes": [
|
|
733
|
-
"home.topolo.app"
|
|
734
|
-
],
|
|
781
|
+
"routes": [],
|
|
735
782
|
"serviceId": "home"
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
"name": "topolo-home-api",
|
|
786
|
+
"kind": "worker",
|
|
787
|
+
"apiUrl": null,
|
|
788
|
+
"domains": [],
|
|
789
|
+
"routes": [],
|
|
790
|
+
"serviceId": null
|
|
736
791
|
}
|
|
737
792
|
]
|
|
738
793
|
},
|
|
@@ -753,10 +808,16 @@ var APPLICATIONS = {
|
|
|
753
808
|
"domains": [
|
|
754
809
|
"insights.topolo.app"
|
|
755
810
|
],
|
|
756
|
-
"routes": [
|
|
757
|
-
"insights.topolo.app"
|
|
758
|
-
],
|
|
811
|
+
"routes": [],
|
|
759
812
|
"serviceId": "insights"
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
"name": "topolo-insights-api",
|
|
816
|
+
"kind": "worker",
|
|
817
|
+
"apiUrl": null,
|
|
818
|
+
"domains": [],
|
|
819
|
+
"routes": [],
|
|
820
|
+
"serviceId": null
|
|
760
821
|
}
|
|
761
822
|
]
|
|
762
823
|
},
|
|
@@ -777,10 +838,16 @@ var APPLICATIONS = {
|
|
|
777
838
|
"domains": [
|
|
778
839
|
"inventory.topolo.app"
|
|
779
840
|
],
|
|
780
|
-
"routes": [
|
|
781
|
-
"inventory.topolo.app"
|
|
782
|
-
],
|
|
841
|
+
"routes": [],
|
|
783
842
|
"serviceId": "inventory"
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
"name": "topolo-inventory-api",
|
|
846
|
+
"kind": "worker",
|
|
847
|
+
"apiUrl": null,
|
|
848
|
+
"domains": [],
|
|
849
|
+
"routes": [],
|
|
850
|
+
"serviceId": null
|
|
784
851
|
}
|
|
785
852
|
]
|
|
786
853
|
},
|
|
@@ -797,7 +864,7 @@ var APPLICATIONS = {
|
|
|
797
864
|
{
|
|
798
865
|
"name": "topolo-learn",
|
|
799
866
|
"kind": "worker",
|
|
800
|
-
"apiUrl":
|
|
867
|
+
"apiUrl": "https://learn.topolo.app",
|
|
801
868
|
"domains": [
|
|
802
869
|
"learn.topolo.app"
|
|
803
870
|
],
|
|
@@ -857,10 +924,16 @@ var APPLICATIONS = {
|
|
|
857
924
|
"domains": [
|
|
858
925
|
"mail.topolo.app"
|
|
859
926
|
],
|
|
860
|
-
"routes": [
|
|
861
|
-
"mail.topolo.app"
|
|
862
|
-
],
|
|
927
|
+
"routes": [],
|
|
863
928
|
"serviceId": "mail"
|
|
929
|
+
},
|
|
930
|
+
{
|
|
931
|
+
"name": "topolo-mail-api",
|
|
932
|
+
"kind": "worker",
|
|
933
|
+
"apiUrl": null,
|
|
934
|
+
"domains": [],
|
|
935
|
+
"routes": [],
|
|
936
|
+
"serviceId": null
|
|
864
937
|
}
|
|
865
938
|
]
|
|
866
939
|
},
|
|
@@ -881,47 +954,51 @@ var APPLICATIONS = {
|
|
|
881
954
|
"domains": [
|
|
882
955
|
"mdm-api.topolo.app"
|
|
883
956
|
],
|
|
884
|
-
"routes": [
|
|
885
|
-
"mdm-api.topolo.app"
|
|
886
|
-
],
|
|
957
|
+
"routes": [],
|
|
887
958
|
"serviceId": "mdm"
|
|
888
959
|
},
|
|
889
960
|
{
|
|
890
961
|
"name": "topolo-mdm-console",
|
|
891
962
|
"kind": "worker",
|
|
892
|
-
"apiUrl":
|
|
963
|
+
"apiUrl": "https://mdm.topolo.app",
|
|
893
964
|
"domains": [
|
|
894
965
|
"mdm.topolo.app"
|
|
895
966
|
],
|
|
896
|
-
"routes": [
|
|
897
|
-
"mdm.topolo.app"
|
|
898
|
-
],
|
|
967
|
+
"routes": [],
|
|
899
968
|
"serviceId": null
|
|
900
969
|
}
|
|
901
970
|
]
|
|
902
971
|
},
|
|
903
|
-
"
|
|
904
|
-
"id": "
|
|
905
|
-
"appDir": "
|
|
906
|
-
"name": "topolo-
|
|
907
|
-
"packageName": "topolo-
|
|
972
|
+
"messages": {
|
|
973
|
+
"id": "messages",
|
|
974
|
+
"appDir": "TopoloMessages",
|
|
975
|
+
"name": "topolo-messages",
|
|
976
|
+
"packageName": "topolo-messages",
|
|
908
977
|
"productionUrl": "https://messages.topolo.app",
|
|
909
978
|
"services": [
|
|
910
|
-
"
|
|
979
|
+
"messages"
|
|
911
980
|
],
|
|
912
981
|
"deployTargets": [
|
|
913
982
|
{
|
|
914
|
-
"name": "topolo-
|
|
983
|
+
"name": "topolo-messages",
|
|
915
984
|
"kind": "worker",
|
|
916
985
|
"apiUrl": "https://messages.topolo.app",
|
|
917
986
|
"domains": [
|
|
918
987
|
"messages.topolo.app"
|
|
919
988
|
],
|
|
920
989
|
"routes": [],
|
|
921
|
-
"serviceId": "
|
|
990
|
+
"serviceId": "messages"
|
|
991
|
+
},
|
|
992
|
+
{
|
|
993
|
+
"name": "topolo-messages-api",
|
|
994
|
+
"kind": "worker",
|
|
995
|
+
"apiUrl": null,
|
|
996
|
+
"domains": [],
|
|
997
|
+
"routes": [],
|
|
998
|
+
"serviceId": null
|
|
922
999
|
},
|
|
923
1000
|
{
|
|
924
|
-
"name": "topolo-
|
|
1001
|
+
"name": "topolo-messages-dispatch",
|
|
925
1002
|
"kind": "worker",
|
|
926
1003
|
"apiUrl": null,
|
|
927
1004
|
"domains": [],
|
|
@@ -991,9 +1068,22 @@ var APPLICATIONS = {
|
|
|
991
1068
|
"appDir": "TopoloObservabilityWatch",
|
|
992
1069
|
"name": "topolo-observability-watch",
|
|
993
1070
|
"packageName": "topolo-observability-watch",
|
|
994
|
-
"productionUrl":
|
|
995
|
-
"services": [
|
|
996
|
-
|
|
1071
|
+
"productionUrl": "https://observability-watch.topolo.app",
|
|
1072
|
+
"services": [
|
|
1073
|
+
"observability_watch"
|
|
1074
|
+
],
|
|
1075
|
+
"deployTargets": [
|
|
1076
|
+
{
|
|
1077
|
+
"name": "topolo-observability-watch",
|
|
1078
|
+
"kind": "worker",
|
|
1079
|
+
"apiUrl": "https://observability-watch.topolo.app",
|
|
1080
|
+
"domains": [
|
|
1081
|
+
"observability-watch.topolo.app"
|
|
1082
|
+
],
|
|
1083
|
+
"routes": [],
|
|
1084
|
+
"serviceId": "observability_watch"
|
|
1085
|
+
}
|
|
1086
|
+
]
|
|
997
1087
|
},
|
|
998
1088
|
"one": {
|
|
999
1089
|
"id": "one",
|
|
@@ -1007,40 +1097,37 @@ var APPLICATIONS = {
|
|
|
1007
1097
|
"deployTargets": [
|
|
1008
1098
|
{
|
|
1009
1099
|
"name": "topolo-one",
|
|
1010
|
-
"kind": "pages",
|
|
1011
|
-
"apiUrl": null,
|
|
1012
|
-
"domains": [
|
|
1013
|
-
"one.topolo.app"
|
|
1014
|
-
],
|
|
1015
|
-
"routes": [],
|
|
1016
|
-
"serviceId": null
|
|
1017
|
-
},
|
|
1018
|
-
{
|
|
1019
|
-
"name": "topolo-one-website",
|
|
1020
1100
|
"kind": "worker",
|
|
1021
1101
|
"apiUrl": null,
|
|
1022
|
-
"domains": [
|
|
1023
|
-
"topolo.io",
|
|
1024
|
-
"www.topolo.io"
|
|
1025
|
-
],
|
|
1102
|
+
"domains": [],
|
|
1026
1103
|
"routes": [],
|
|
1027
1104
|
"serviceId": null
|
|
1028
1105
|
},
|
|
1029
1106
|
{
|
|
1030
|
-
"name": "topolo-one-
|
|
1107
|
+
"name": "topolo-one-api",
|
|
1031
1108
|
"kind": "worker",
|
|
1032
1109
|
"apiUrl": "https://one.topolo.app",
|
|
1033
1110
|
"domains": [
|
|
1034
|
-
"one.topolo.app"
|
|
1035
|
-
"topolo.app",
|
|
1036
|
-
"www.topolo.app"
|
|
1111
|
+
"one.topolo.app"
|
|
1037
1112
|
],
|
|
1038
1113
|
"routes": [
|
|
1039
1114
|
"one.topolo.app/*",
|
|
1040
|
-
"topolo.app",
|
|
1041
1115
|
"www.topolo.app/*"
|
|
1042
1116
|
],
|
|
1043
1117
|
"serviceId": "one"
|
|
1118
|
+
},
|
|
1119
|
+
{
|
|
1120
|
+
"name": "topolo-one-website",
|
|
1121
|
+
"kind": "worker",
|
|
1122
|
+
"apiUrl": "https://topolo.io",
|
|
1123
|
+
"domains": [
|
|
1124
|
+
"topolo.io"
|
|
1125
|
+
],
|
|
1126
|
+
"routes": [
|
|
1127
|
+
"topolo.io",
|
|
1128
|
+
"www.topolo.io"
|
|
1129
|
+
],
|
|
1130
|
+
"serviceId": null
|
|
1044
1131
|
}
|
|
1045
1132
|
]
|
|
1046
1133
|
},
|
|
@@ -1061,10 +1148,16 @@ var APPLICATIONS = {
|
|
|
1061
1148
|
"domains": [
|
|
1062
1149
|
"p2p.topolo.app"
|
|
1063
1150
|
],
|
|
1064
|
-
"routes": [
|
|
1065
|
-
"p2p.topolo.app"
|
|
1066
|
-
],
|
|
1151
|
+
"routes": [],
|
|
1067
1152
|
"serviceId": "p2p"
|
|
1153
|
+
},
|
|
1154
|
+
{
|
|
1155
|
+
"name": "topolo-p2p-api",
|
|
1156
|
+
"kind": "worker",
|
|
1157
|
+
"apiUrl": null,
|
|
1158
|
+
"domains": [],
|
|
1159
|
+
"routes": [],
|
|
1160
|
+
"serviceId": null
|
|
1068
1161
|
}
|
|
1069
1162
|
]
|
|
1070
1163
|
},
|
|
@@ -1087,6 +1180,14 @@ var APPLICATIONS = {
|
|
|
1087
1180
|
],
|
|
1088
1181
|
"routes": [],
|
|
1089
1182
|
"serviceId": "pay"
|
|
1183
|
+
},
|
|
1184
|
+
{
|
|
1185
|
+
"name": "topolo-pay-api",
|
|
1186
|
+
"kind": "worker",
|
|
1187
|
+
"apiUrl": null,
|
|
1188
|
+
"domains": [],
|
|
1189
|
+
"routes": [],
|
|
1190
|
+
"serviceId": null
|
|
1090
1191
|
}
|
|
1091
1192
|
]
|
|
1092
1193
|
},
|
|
@@ -1107,10 +1208,16 @@ var APPLICATIONS = {
|
|
|
1107
1208
|
"domains": [
|
|
1108
1209
|
"people.topolo.app"
|
|
1109
1210
|
],
|
|
1110
|
-
"routes": [
|
|
1111
|
-
"people.topolo.app"
|
|
1112
|
-
],
|
|
1211
|
+
"routes": [],
|
|
1113
1212
|
"serviceId": "people"
|
|
1213
|
+
},
|
|
1214
|
+
{
|
|
1215
|
+
"name": "topolo-people-api",
|
|
1216
|
+
"kind": "worker",
|
|
1217
|
+
"apiUrl": null,
|
|
1218
|
+
"domains": [],
|
|
1219
|
+
"routes": [],
|
|
1220
|
+
"serviceId": null
|
|
1114
1221
|
}
|
|
1115
1222
|
]
|
|
1116
1223
|
},
|
|
@@ -1131,10 +1238,16 @@ var APPLICATIONS = {
|
|
|
1131
1238
|
"domains": [
|
|
1132
1239
|
"pulse.topolo.app"
|
|
1133
1240
|
],
|
|
1134
|
-
"routes": [
|
|
1135
|
-
"pulse.topolo.app"
|
|
1136
|
-
],
|
|
1241
|
+
"routes": [],
|
|
1137
1242
|
"serviceId": "pulse"
|
|
1243
|
+
},
|
|
1244
|
+
{
|
|
1245
|
+
"name": "topolo-pulse-api",
|
|
1246
|
+
"kind": "worker",
|
|
1247
|
+
"apiUrl": null,
|
|
1248
|
+
"domains": [],
|
|
1249
|
+
"routes": [],
|
|
1250
|
+
"serviceId": null
|
|
1138
1251
|
}
|
|
1139
1252
|
]
|
|
1140
1253
|
},
|
|
@@ -1156,7 +1269,9 @@ var APPLICATIONS = {
|
|
|
1156
1269
|
"domains": [
|
|
1157
1270
|
"api.ol0.me"
|
|
1158
1271
|
],
|
|
1159
|
-
"routes": [
|
|
1272
|
+
"routes": [
|
|
1273
|
+
"api.ol0.me/*"
|
|
1274
|
+
],
|
|
1160
1275
|
"serviceId": "quro.api"
|
|
1161
1276
|
},
|
|
1162
1277
|
{
|
|
@@ -1174,7 +1289,7 @@ var APPLICATIONS = {
|
|
|
1174
1289
|
{
|
|
1175
1290
|
"name": "quro-ui",
|
|
1176
1291
|
"kind": "worker",
|
|
1177
|
-
"apiUrl":
|
|
1292
|
+
"apiUrl": "https://quro.topolo.app",
|
|
1178
1293
|
"domains": [
|
|
1179
1294
|
"quro.topolo.app"
|
|
1180
1295
|
],
|
|
@@ -1196,7 +1311,7 @@ var APPLICATIONS = {
|
|
|
1196
1311
|
{
|
|
1197
1312
|
"name": "topolo-roadmapper",
|
|
1198
1313
|
"kind": "worker",
|
|
1199
|
-
"apiUrl":
|
|
1314
|
+
"apiUrl": "https://roadmapper.topolo.app",
|
|
1200
1315
|
"domains": [
|
|
1201
1316
|
"roadmapper.topolo.app"
|
|
1202
1317
|
],
|
|
@@ -1232,10 +1347,16 @@ var APPLICATIONS = {
|
|
|
1232
1347
|
"domains": [
|
|
1233
1348
|
"sign.topolo.app"
|
|
1234
1349
|
],
|
|
1235
|
-
"routes": [
|
|
1236
|
-
"sign.topolo.app"
|
|
1237
|
-
],
|
|
1350
|
+
"routes": [],
|
|
1238
1351
|
"serviceId": "sign"
|
|
1352
|
+
},
|
|
1353
|
+
{
|
|
1354
|
+
"name": "topolo-sign-api",
|
|
1355
|
+
"kind": "worker",
|
|
1356
|
+
"apiUrl": null,
|
|
1357
|
+
"domains": [],
|
|
1358
|
+
"routes": [],
|
|
1359
|
+
"serviceId": null
|
|
1239
1360
|
}
|
|
1240
1361
|
]
|
|
1241
1362
|
},
|
|
@@ -1252,7 +1373,7 @@ var APPLICATIONS = {
|
|
|
1252
1373
|
{
|
|
1253
1374
|
"name": "topolo-social-studio",
|
|
1254
1375
|
"kind": "worker",
|
|
1255
|
-
"apiUrl":
|
|
1376
|
+
"apiUrl": "https://studio.topolo.app",
|
|
1256
1377
|
"domains": [
|
|
1257
1378
|
"studio.topolo.app"
|
|
1258
1379
|
],
|
|
@@ -1291,8 +1412,8 @@ var APPLICATIONS = {
|
|
|
1291
1412
|
"deployTargets": [
|
|
1292
1413
|
{
|
|
1293
1414
|
"name": "topolo-socialize",
|
|
1294
|
-
"kind": "
|
|
1295
|
-
"apiUrl":
|
|
1415
|
+
"kind": "worker",
|
|
1416
|
+
"apiUrl": "https://socialize.topolo.app",
|
|
1296
1417
|
"domains": [
|
|
1297
1418
|
"socialize.topolo.app"
|
|
1298
1419
|
],
|
|
@@ -1336,10 +1457,16 @@ var APPLICATIONS = {
|
|
|
1336
1457
|
"domains": [
|
|
1337
1458
|
"spaces.topolo.app"
|
|
1338
1459
|
],
|
|
1339
|
-
"routes": [
|
|
1340
|
-
"spaces.topolo.app"
|
|
1341
|
-
],
|
|
1460
|
+
"routes": [],
|
|
1342
1461
|
"serviceId": "spaces"
|
|
1462
|
+
},
|
|
1463
|
+
{
|
|
1464
|
+
"name": "topolo-spaces-api",
|
|
1465
|
+
"kind": "worker",
|
|
1466
|
+
"apiUrl": null,
|
|
1467
|
+
"domains": [],
|
|
1468
|
+
"routes": [],
|
|
1469
|
+
"serviceId": null
|
|
1343
1470
|
}
|
|
1344
1471
|
]
|
|
1345
1472
|
},
|
|
@@ -1360,10 +1487,40 @@ var APPLICATIONS = {
|
|
|
1360
1487
|
"domains": [
|
|
1361
1488
|
"status.topolo.app"
|
|
1362
1489
|
],
|
|
1490
|
+
"routes": [],
|
|
1491
|
+
"serviceId": "status"
|
|
1492
|
+
}
|
|
1493
|
+
]
|
|
1494
|
+
},
|
|
1495
|
+
"success": {
|
|
1496
|
+
"id": "success",
|
|
1497
|
+
"appDir": "TopoloSuccess",
|
|
1498
|
+
"name": "topolo-success",
|
|
1499
|
+
"packageName": "topolo-success",
|
|
1500
|
+
"productionUrl": "https://success.topolo.app",
|
|
1501
|
+
"services": [
|
|
1502
|
+
"success"
|
|
1503
|
+
],
|
|
1504
|
+
"deployTargets": [
|
|
1505
|
+
{
|
|
1506
|
+
"name": "topolo-success",
|
|
1507
|
+
"kind": "worker",
|
|
1508
|
+
"apiUrl": "https://success.topolo.app",
|
|
1509
|
+
"domains": [
|
|
1510
|
+
"success.topolo.app"
|
|
1511
|
+
],
|
|
1363
1512
|
"routes": [
|
|
1364
|
-
"
|
|
1513
|
+
"success.topolo.app"
|
|
1365
1514
|
],
|
|
1366
|
-
"serviceId": "
|
|
1515
|
+
"serviceId": "success"
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
"name": "topolo-success-api",
|
|
1519
|
+
"kind": "worker",
|
|
1520
|
+
"apiUrl": null,
|
|
1521
|
+
"domains": [],
|
|
1522
|
+
"routes": [],
|
|
1523
|
+
"serviceId": null
|
|
1367
1524
|
}
|
|
1368
1525
|
]
|
|
1369
1526
|
},
|
|
@@ -1388,6 +1545,14 @@ var APPLICATIONS = {
|
|
|
1388
1545
|
"support.topolo.app/*"
|
|
1389
1546
|
],
|
|
1390
1547
|
"serviceId": "support"
|
|
1548
|
+
},
|
|
1549
|
+
{
|
|
1550
|
+
"name": "topolo-support-api",
|
|
1551
|
+
"kind": "worker",
|
|
1552
|
+
"apiUrl": null,
|
|
1553
|
+
"domains": [],
|
|
1554
|
+
"routes": [],
|
|
1555
|
+
"serviceId": null
|
|
1391
1556
|
}
|
|
1392
1557
|
]
|
|
1393
1558
|
},
|
|
@@ -1408,10 +1573,16 @@ var APPLICATIONS = {
|
|
|
1408
1573
|
"domains": [
|
|
1409
1574
|
"survey.topolo.app"
|
|
1410
1575
|
],
|
|
1411
|
-
"routes": [
|
|
1412
|
-
"survey.topolo.app"
|
|
1413
|
-
],
|
|
1576
|
+
"routes": [],
|
|
1414
1577
|
"serviceId": "survey"
|
|
1578
|
+
},
|
|
1579
|
+
{
|
|
1580
|
+
"name": "topolo-survey-api",
|
|
1581
|
+
"kind": "worker",
|
|
1582
|
+
"apiUrl": null,
|
|
1583
|
+
"domains": [],
|
|
1584
|
+
"routes": [],
|
|
1585
|
+
"serviceId": null
|
|
1415
1586
|
}
|
|
1416
1587
|
]
|
|
1417
1588
|
},
|
|
@@ -1432,10 +1603,16 @@ var APPLICATIONS = {
|
|
|
1432
1603
|
"domains": [
|
|
1433
1604
|
"voice.topolo.app"
|
|
1434
1605
|
],
|
|
1435
|
-
"routes": [
|
|
1436
|
-
"voice.topolo.app"
|
|
1437
|
-
],
|
|
1606
|
+
"routes": [],
|
|
1438
1607
|
"serviceId": "voice"
|
|
1608
|
+
},
|
|
1609
|
+
{
|
|
1610
|
+
"name": "topolo-voice-api",
|
|
1611
|
+
"kind": "worker",
|
|
1612
|
+
"apiUrl": null,
|
|
1613
|
+
"domains": [],
|
|
1614
|
+
"routes": [],
|
|
1615
|
+
"serviceId": null
|
|
1439
1616
|
}
|
|
1440
1617
|
]
|
|
1441
1618
|
},
|
|
@@ -1466,13 +1643,16 @@ var APPLICATIONS = {
|
|
|
1466
1643
|
"domains": [
|
|
1467
1644
|
"sites.topolo.app"
|
|
1468
1645
|
],
|
|
1469
|
-
"routes": [
|
|
1646
|
+
"routes": [
|
|
1647
|
+
"*.sites.topolo.app/*",
|
|
1648
|
+
"sites.topolo.app"
|
|
1649
|
+
],
|
|
1470
1650
|
"serviceId": null
|
|
1471
1651
|
},
|
|
1472
1652
|
{
|
|
1473
1653
|
"name": "topolo-web-studio",
|
|
1474
1654
|
"kind": "worker",
|
|
1475
|
-
"apiUrl":
|
|
1655
|
+
"apiUrl": "https://web.topolo.app",
|
|
1476
1656
|
"domains": [
|
|
1477
1657
|
"web.topolo.app"
|
|
1478
1658
|
],
|
|
@@ -1522,12 +1702,12 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1522
1702
|
summary: "Applications must derive identity, organization, scopes, and service entitlement from TopoloAuth rather than inventing parallel auth state.",
|
|
1523
1703
|
appliesTo: ["browser", "api", "tooling", "agent_surface"],
|
|
1524
1704
|
evidence: [
|
|
1525
|
-
"@topolo/auth-client or @topolo/
|
|
1705
|
+
"@topolo/auth-client or @topolo-io/worker-runtime is used where applicable",
|
|
1526
1706
|
"No public command, tool, or SDK method accepts orgId",
|
|
1527
1707
|
"Service slug and Auth service registration are documented for protected services"
|
|
1528
1708
|
],
|
|
1529
1709
|
implementation: [
|
|
1530
|
-
"Use shared auth packages instead of copying token parsing or browser storage flows",
|
|
1710
|
+
"Use shared auth/runtime packages instead of copying token parsing, gateway, or browser storage flows",
|
|
1531
1711
|
"Derive organization from the credential on every request",
|
|
1532
1712
|
"Route OAuth, refresh, logout, and SSO paths according to the shared Auth contract"
|
|
1533
1713
|
]
|
|
@@ -1560,11 +1740,13 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1560
1740
|
evidence: [
|
|
1561
1741
|
"Auth service catalog contains the service ID and slug",
|
|
1562
1742
|
"Permissions, role bundles, and API-key scopes exist for the service",
|
|
1563
|
-
"SDK, CLI, and MCP service discovery include the callable production API"
|
|
1743
|
+
"SDK, CLI, and MCP service discovery include the callable production API",
|
|
1744
|
+
"CloudControl production HTTP targets classify agent reachability with sdk_service_id or agent_callable:false"
|
|
1564
1745
|
],
|
|
1565
1746
|
implementation: [
|
|
1566
|
-
"Add production Worker api_url metadata
|
|
1567
|
-
"
|
|
1747
|
+
"Add production Worker api_url metadata and sdk_service_id for every agent-callable API target",
|
|
1748
|
+
"Mark browser, documentation, and runtime-only Worker targets with agent_callable:false",
|
|
1749
|
+
"Expose stable service IDs through generated DEFAULT_SERVICE_URLS and live catalog discovery",
|
|
1568
1750
|
"Keep typed SDK/CLI/MCP surfaces in sync when an API contract stabilizes"
|
|
1569
1751
|
]
|
|
1570
1752
|
},
|
|
@@ -1668,8 +1850,10 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1668
1850
|
function applicationRequirementScopes(application) {
|
|
1669
1851
|
const scopes = /* @__PURE__ */ new Set(["all"]);
|
|
1670
1852
|
const appId = application.id;
|
|
1671
|
-
const hasBrowserSurface = Boolean(application.productionUrl) ||
|
|
1672
|
-
|
|
1853
|
+
const hasBrowserSurface = Boolean(application.productionUrl) || // String() keeps this guard valid after the Pages->Worker migration narrowed
|
|
1854
|
+
// the generated kind union to "worker" (no "pages" literal remains).
|
|
1855
|
+
application.deployTargets.some((target) => String(target.kind) === "pages");
|
|
1856
|
+
const hasApiSurface = application.services.length > 0 || application.deployTargets.some((target) => Boolean(target.serviceId));
|
|
1673
1857
|
if (hasBrowserSurface) scopes.add("browser");
|
|
1674
1858
|
if (hasApiSurface) scopes.add("api");
|
|
1675
1859
|
if (appId === "cli" || appId === "mcp" || appId === "cloudcontrol") {
|
|
@@ -1786,7 +1970,7 @@ function evaluateRequirement(application, requirement) {
|
|
|
1786
1970
|
evidence
|
|
1787
1971
|
);
|
|
1788
1972
|
case "cloudflare-deployment-contract": {
|
|
1789
|
-
if (application.deployTargets.length
|
|
1973
|
+
if (application.deployTargets.length < 1) {
|
|
1790
1974
|
return finding(requirement, "missing", "No CloudControl deploy targets are registered.", evidence);
|
|
1791
1975
|
}
|
|
1792
1976
|
evidence.push(`deployTargets=${application.deployTargets.length}`);
|
|
@@ -1873,6 +2057,7 @@ function resolveServiceUrl(service, overrides) {
|
|
|
1873
2057
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
1874
2058
|
var POSITIVE_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
1875
2059
|
var NEGATIVE_CACHE_TTL_MS = 60 * 1e3;
|
|
2060
|
+
var CATALOG_CACHE_TTL_MS = 60 * 1e3;
|
|
1876
2061
|
var TopoloClient = class _TopoloClient {
|
|
1877
2062
|
credential;
|
|
1878
2063
|
agent;
|
|
@@ -1882,6 +2067,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1882
2067
|
timeoutMs;
|
|
1883
2068
|
fetchImpl;
|
|
1884
2069
|
debug;
|
|
2070
|
+
serviceCatalogCache = null;
|
|
1885
2071
|
/**
|
|
1886
2072
|
* Process-wide cache for slug → service-id lookups. Keyed by
|
|
1887
2073
|
* `${authBaseUrl}|${slug}` so multiple `TopoloClient` instances pointing at
|
|
@@ -1927,7 +2113,8 @@ var TopoloClient = class _TopoloClient {
|
|
|
1927
2113
|
`Mutating ${method} requests require { confirm: true }. This guardrail prevents agents from issuing writes without an explicit human-in-the-loop acknowledgement.`
|
|
1928
2114
|
);
|
|
1929
2115
|
}
|
|
1930
|
-
const
|
|
2116
|
+
const resolvedService = await this.resolveRequestService(opts.service);
|
|
2117
|
+
const baseUrl = resolvedService.baseUrl;
|
|
1931
2118
|
const url = new URL(opts.path, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
|
|
1932
2119
|
if (opts.query) {
|
|
1933
2120
|
for (const [k, v] of Object.entries(opts.query)) {
|
|
@@ -1937,7 +2124,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1937
2124
|
const headers = new Headers();
|
|
1938
2125
|
headers.set("Accept", "application/json");
|
|
1939
2126
|
if (opts.body !== void 0) headers.set("Content-Type", "application/json");
|
|
1940
|
-
const platformServiceId = resolveConfiguredServiceId(
|
|
2127
|
+
const platformServiceId = resolveConfiguredServiceId(resolvedService.serviceKey, this.serviceIds);
|
|
1941
2128
|
if (platformServiceId) headers.set("X-Service-ID", platformServiceId);
|
|
1942
2129
|
applyAuthHeaders(headers, this.credential);
|
|
1943
2130
|
const requestId = generateRequestId();
|
|
@@ -1950,7 +2137,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1950
2137
|
const signal = opts.signal ? mergeSignals(opts.signal, controller.signal) : controller.signal;
|
|
1951
2138
|
const urlStr = url.toString();
|
|
1952
2139
|
const startedAt = Date.now();
|
|
1953
|
-
this.emit({ phase: "request", method, service:
|
|
2140
|
+
this.emit({ phase: "request", method, service: resolvedService.serviceKey, path: opts.path, url: urlStr, requestId });
|
|
1954
2141
|
let res;
|
|
1955
2142
|
try {
|
|
1956
2143
|
res = await this.fetchImpl(urlStr, {
|
|
@@ -1963,7 +2150,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1963
2150
|
this.emit({
|
|
1964
2151
|
phase: "error",
|
|
1965
2152
|
method,
|
|
1966
|
-
service:
|
|
2153
|
+
service: resolvedService.serviceKey,
|
|
1967
2154
|
path: opts.path,
|
|
1968
2155
|
url: urlStr,
|
|
1969
2156
|
requestId,
|
|
@@ -1982,7 +2169,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
1982
2169
|
this.emit({
|
|
1983
2170
|
phase: "error",
|
|
1984
2171
|
method,
|
|
1985
|
-
service:
|
|
2172
|
+
service: resolvedService.serviceKey,
|
|
1986
2173
|
path: opts.path,
|
|
1987
2174
|
url: urlStr,
|
|
1988
2175
|
requestId,
|
|
@@ -1997,12 +2184,12 @@ var TopoloClient = class _TopoloClient {
|
|
|
1997
2184
|
extractRequired(parsed)
|
|
1998
2185
|
);
|
|
1999
2186
|
}
|
|
2000
|
-
throw new TopoloHttpError(
|
|
2187
|
+
throw new TopoloHttpError(resolvedService.serviceKey, opts.path, res.status, parsed);
|
|
2001
2188
|
}
|
|
2002
2189
|
this.emit({
|
|
2003
2190
|
phase: "response",
|
|
2004
2191
|
method,
|
|
2005
|
-
service:
|
|
2192
|
+
service: resolvedService.serviceKey,
|
|
2006
2193
|
path: opts.path,
|
|
2007
2194
|
url: urlStr,
|
|
2008
2195
|
requestId,
|
|
@@ -2011,6 +2198,31 @@ var TopoloClient = class _TopoloClient {
|
|
|
2011
2198
|
});
|
|
2012
2199
|
return parsed;
|
|
2013
2200
|
}
|
|
2201
|
+
async resolveRequestService(service) {
|
|
2202
|
+
const serviceKey = normalizeLookupKey(service);
|
|
2203
|
+
if (!serviceKey) {
|
|
2204
|
+
throw new TopoloSdkError("unknown_service", "service is required");
|
|
2205
|
+
}
|
|
2206
|
+
const overrideUrl = resolveConfiguredServiceUrl(serviceKey, this.serviceUrls);
|
|
2207
|
+
if (overrideUrl) return { serviceKey, baseUrl: overrideUrl };
|
|
2208
|
+
const staticUrl = DEFAULT_SERVICE_URLS[serviceKey];
|
|
2209
|
+
if (staticUrl) return { serviceKey, baseUrl: staticUrl };
|
|
2210
|
+
const live = await this.resolveLiveCallableService(serviceKey);
|
|
2211
|
+
if (live) return live;
|
|
2212
|
+
throw new TopoloSdkError(
|
|
2213
|
+
"unknown_service",
|
|
2214
|
+
`Unknown Topolo service "${service}". Run service discovery first and pass a callable service id or slug.`
|
|
2215
|
+
);
|
|
2216
|
+
}
|
|
2217
|
+
async resolveLiveCallableService(serviceKey) {
|
|
2218
|
+
const catalog = await this.listServices();
|
|
2219
|
+
const match = catalog.find((entry) => catalogEntryMatches(entry, serviceKey));
|
|
2220
|
+
if (!match?.baseUrl || !isCallableCatalogEntry(match)) return null;
|
|
2221
|
+
return {
|
|
2222
|
+
serviceKey: normalizeLookupKey(match.slug || match.name || match.serviceId) || serviceKey,
|
|
2223
|
+
baseUrl: match.baseUrl
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2014
2226
|
/**
|
|
2015
2227
|
* Resolve a service-slug → opaque service-id via caller config or TopoloAuth.
|
|
2016
2228
|
*
|
|
@@ -2068,6 +2280,68 @@ var TopoloClient = class _TopoloClient {
|
|
|
2068
2280
|
});
|
|
2069
2281
|
return value;
|
|
2070
2282
|
}
|
|
2283
|
+
/**
|
|
2284
|
+
* List the platform service catalog from the live registry
|
|
2285
|
+
* (`GET /api/services/catalog` on TopoloAuth). Credential-aware: the
|
|
2286
|
+
* caller's credential is attached, so an authenticated caller in an
|
|
2287
|
+
* entitled org also receives the `developer_only` services its role
|
|
2288
|
+
* permits; an unauthenticated/agent caller receives `active` only.
|
|
2289
|
+
*
|
|
2290
|
+
* Resilient: on any network/HTTP failure this falls back to the
|
|
2291
|
+
* build-time generated `APPLICATIONS` snapshot so offline/degraded
|
|
2292
|
+
* callers still get a usable (if static) catalog. The live result is
|
|
2293
|
+
* authoritative; the snapshot is a floor, not a cap.
|
|
2294
|
+
*/
|
|
2295
|
+
async listServices() {
|
|
2296
|
+
const now = Date.now();
|
|
2297
|
+
if (this.serviceCatalogCache && this.serviceCatalogCache.expiresAt > now) {
|
|
2298
|
+
return this.serviceCatalogCache.entries;
|
|
2299
|
+
}
|
|
2300
|
+
try {
|
|
2301
|
+
const res = await this.request({ service: "auth", method: "GET", path: "/api/services/catalog" });
|
|
2302
|
+
const raw = res.data?.services ?? res.services;
|
|
2303
|
+
if (Array.isArray(raw) && raw.length > 0) {
|
|
2304
|
+
const entries = [];
|
|
2305
|
+
for (const item of raw) {
|
|
2306
|
+
const s = item;
|
|
2307
|
+
const serviceId = typeof s.service_id === "string" ? s.service_id : typeof s.id === "string" ? s.id : null;
|
|
2308
|
+
if (!serviceId) continue;
|
|
2309
|
+
entries.push({
|
|
2310
|
+
serviceId,
|
|
2311
|
+
slug: typeof s.app_slug === "string" ? s.app_slug : null,
|
|
2312
|
+
name: typeof s.name === "string" ? s.name : null,
|
|
2313
|
+
description: typeof s.description === "string" ? s.description : null,
|
|
2314
|
+
baseUrl: typeof s.base_url === "string" ? s.base_url : null,
|
|
2315
|
+
status: typeof s.status === "string" ? s.status : null,
|
|
2316
|
+
surfaceKind: typeof s.surface_kind === "string" ? s.surface_kind : null,
|
|
2317
|
+
launchable: s.launchable === true
|
|
2318
|
+
});
|
|
2319
|
+
}
|
|
2320
|
+
if (entries.length > 0) {
|
|
2321
|
+
this.serviceCatalogCache = {
|
|
2322
|
+
entries,
|
|
2323
|
+
expiresAt: now + CATALOG_CACHE_TTL_MS
|
|
2324
|
+
};
|
|
2325
|
+
return entries;
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
} catch {
|
|
2329
|
+
}
|
|
2330
|
+
return this.generatedCatalogFallback();
|
|
2331
|
+
}
|
|
2332
|
+
generatedCatalogFallback() {
|
|
2333
|
+
const apps = Object.values(APPLICATIONS);
|
|
2334
|
+
return apps.map((app) => ({
|
|
2335
|
+
serviceId: app.id,
|
|
2336
|
+
slug: app.id,
|
|
2337
|
+
name: app.name ?? app.id,
|
|
2338
|
+
description: null,
|
|
2339
|
+
baseUrl: app.productionUrl ?? null,
|
|
2340
|
+
status: "active",
|
|
2341
|
+
surfaceKind: "application",
|
|
2342
|
+
launchable: Boolean(app.productionUrl)
|
|
2343
|
+
}));
|
|
2344
|
+
}
|
|
2071
2345
|
/**
|
|
2072
2346
|
* Introspect the current credential. Returns the caller's resolved identity,
|
|
2073
2347
|
* organization, and permission set. Used by CLI `whoami` and by MCP to gate
|
|
@@ -2114,8 +2388,18 @@ function resolveConfiguredServiceId(slug, serviceIds) {
|
|
|
2114
2388
|
}
|
|
2115
2389
|
return null;
|
|
2116
2390
|
}
|
|
2391
|
+
function resolveConfiguredServiceUrl(slug, serviceUrls) {
|
|
2392
|
+
for (const serviceKey of serviceKeyCandidates(slug)) {
|
|
2393
|
+
const configured = serviceUrls?.[serviceKey];
|
|
2394
|
+
if (typeof configured === "string" && configured.trim()) return configured.trim();
|
|
2395
|
+
const envKey = `TOPOLO_SERVICE_URL_${serviceKey.replace(/\./g, "_").toUpperCase()}`;
|
|
2396
|
+
const envValue = typeof process !== "undefined" ? process.env?.[envKey] : void 0;
|
|
2397
|
+
if (typeof envValue === "string" && envValue.trim()) return envValue.trim();
|
|
2398
|
+
}
|
|
2399
|
+
return null;
|
|
2400
|
+
}
|
|
2117
2401
|
function serviceKeyCandidates(slug) {
|
|
2118
|
-
const normalized = slug
|
|
2402
|
+
const normalized = normalizeLookupKey(slug);
|
|
2119
2403
|
const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
|
|
2120
2404
|
return [.../* @__PURE__ */ new Set([
|
|
2121
2405
|
normalized,
|
|
@@ -2124,6 +2408,33 @@ function serviceKeyCandidates(slug) {
|
|
|
2124
2408
|
withoutTopolo.replace(/-/g, "_")
|
|
2125
2409
|
])];
|
|
2126
2410
|
}
|
|
2411
|
+
function normalizeLookupKey(value) {
|
|
2412
|
+
return String(value || "").trim().toLowerCase();
|
|
2413
|
+
}
|
|
2414
|
+
function catalogEntryMatches(entry, needle) {
|
|
2415
|
+
return catalogEntryLookupKeys(entry).includes(needle);
|
|
2416
|
+
}
|
|
2417
|
+
function catalogEntryLookupKeys(entry) {
|
|
2418
|
+
const values = [entry.serviceId, entry.slug, entry.name].filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
2419
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2420
|
+
for (const value of values) {
|
|
2421
|
+
const normalized = normalizeLookupKey(value);
|
|
2422
|
+
if (!normalized) continue;
|
|
2423
|
+
keys.add(normalized);
|
|
2424
|
+
keys.add(normalized.replace(/-/g, "_"));
|
|
2425
|
+
if (normalized.startsWith("topolo-")) {
|
|
2426
|
+
const withoutTopolo = normalized.slice("topolo-".length);
|
|
2427
|
+
keys.add(withoutTopolo);
|
|
2428
|
+
keys.add(withoutTopolo.replace(/-/g, "_"));
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2431
|
+
return [...keys];
|
|
2432
|
+
}
|
|
2433
|
+
function isCallableCatalogEntry(entry) {
|
|
2434
|
+
const kind = normalizeLookupKey(entry.surfaceKind || "");
|
|
2435
|
+
if (kind === "api" || kind === "technical_service" || kind === "service") return true;
|
|
2436
|
+
return Boolean(entry.slug && Object.prototype.hasOwnProperty.call(DEFAULT_SERVICE_URLS, catalogEntryLookupKeys(entry)[0] ?? ""));
|
|
2437
|
+
}
|
|
2127
2438
|
function describeError(body, fallback) {
|
|
2128
2439
|
if (body && typeof body === "object") {
|
|
2129
2440
|
const maybe = body;
|
|
@@ -2961,12 +3272,12 @@ function formatContact(c) {
|
|
|
2961
3272
|
}
|
|
2962
3273
|
|
|
2963
3274
|
// src/commands/api.ts
|
|
2964
|
-
var
|
|
3275
|
+
var STATIC_SERVICE_IDS = new Set(Object.keys(DEFAULT_SERVICE_URLS));
|
|
2965
3276
|
var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
2966
3277
|
var WRITE_METHODS2 = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
2967
3278
|
function registerApiCommand(program2) {
|
|
2968
3279
|
program2.command("api <service> <method> <path>").description(
|
|
2969
|
-
|
|
3280
|
+
"Generic passthrough to a Topolo service. Run `topolo services --json` to discover callable services."
|
|
2970
3281
|
).option("-d, --data <json>", "JSON body (for POST/PUT/PATCH)").option(
|
|
2971
3282
|
"-q, --query <kv...>",
|
|
2972
3283
|
"Query params as key=value (repeatable), e.g. --query source=cli page=2"
|
|
@@ -2981,22 +3292,17 @@ function registerApiCommand(program2) {
|
|
|
2981
3292
|
);
|
|
2982
3293
|
}
|
|
2983
3294
|
const httpMethod = upperMethod;
|
|
2984
|
-
if (!KNOWN_SERVICES.includes(service)) {
|
|
2985
|
-
throw new Error(
|
|
2986
|
-
`Unknown service "${service}". Known services: ${KNOWN_SERVICES.join(", ")}`
|
|
2987
|
-
);
|
|
2988
|
-
}
|
|
2989
3295
|
if (WRITE_METHODS2.has(httpMethod) && !opts.confirm) {
|
|
2990
3296
|
throw new Error(`Mutating ${httpMethod} requires --confirm.`);
|
|
2991
3297
|
}
|
|
2992
3298
|
const environment = selectedEnvironment();
|
|
2993
3299
|
const config = await readConfig();
|
|
2994
3300
|
const profile = resolvedProfileConfig(config, environment);
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
environment
|
|
2999
|
-
|
|
3301
|
+
const configuredUrl = resolveConfiguredServiceUrl2(service, profile.serviceUrls);
|
|
3302
|
+
const staticUrl = STATIC_SERVICE_IDS.has(service) ? DEFAULT_SERVICE_URLS[service] : void 0;
|
|
3303
|
+
if (configuredUrl || staticUrl) {
|
|
3304
|
+
assertServiceUrlForEnvironment(service, configuredUrl ?? staticUrl, environment);
|
|
3305
|
+
}
|
|
3000
3306
|
let body = void 0;
|
|
3001
3307
|
if (opts.data) {
|
|
3002
3308
|
try {
|
|
@@ -3027,6 +3333,21 @@ function registerApiCommand(program2) {
|
|
|
3027
3333
|
}
|
|
3028
3334
|
);
|
|
3029
3335
|
}
|
|
3336
|
+
function resolveConfiguredServiceUrl2(service, serviceUrls) {
|
|
3337
|
+
const normalized = service.trim().toLowerCase();
|
|
3338
|
+
const withoutTopolo = normalized.startsWith("topolo-") ? normalized.slice("topolo-".length) : normalized;
|
|
3339
|
+
const candidates = [
|
|
3340
|
+
normalized,
|
|
3341
|
+
normalized.replace(/-/g, "_"),
|
|
3342
|
+
withoutTopolo,
|
|
3343
|
+
withoutTopolo.replace(/-/g, "_")
|
|
3344
|
+
];
|
|
3345
|
+
for (const candidate of candidates) {
|
|
3346
|
+
const url = serviceUrls?.[candidate];
|
|
3347
|
+
if (typeof url === "string" && url.trim()) return url.trim();
|
|
3348
|
+
}
|
|
3349
|
+
return void 0;
|
|
3350
|
+
}
|
|
3030
3351
|
function parseQueryPairs(pairs) {
|
|
3031
3352
|
if (!pairs || pairs.length === 0) return void 0;
|
|
3032
3353
|
const out = {};
|
|
@@ -3056,8 +3377,8 @@ import {
|
|
|
3056
3377
|
} from "fs";
|
|
3057
3378
|
import path from "path";
|
|
3058
3379
|
var EVIDENCE_FRESHNESS_MS = 36 * 60 * 60 * 1e3;
|
|
3059
|
-
var REQUIRED_AUTH_CLIENT_VERSION = "1.1.
|
|
3060
|
-
var REQUIRED_UI_KIT_VERSION = "0.4.
|
|
3380
|
+
var REQUIRED_AUTH_CLIENT_VERSION = "1.1.9";
|
|
3381
|
+
var REQUIRED_UI_KIT_VERSION = "0.4.67";
|
|
3061
3382
|
function readEvidenceFile(appRoot) {
|
|
3062
3383
|
const candidate = path.join(appRoot, ".topolo", "evidence.json");
|
|
3063
3384
|
if (!isFile(candidate)) return null;
|
|
@@ -3264,11 +3585,12 @@ function enrichFinding(application, finding2, evidence) {
|
|
|
3264
3585
|
case "service-registration-and-scopes": {
|
|
3265
3586
|
const declaredServices = application.services ?? [];
|
|
3266
3587
|
if (declaredServices.length === 0) {
|
|
3267
|
-
|
|
3588
|
+
const applicationId = String(application.id);
|
|
3589
|
+
if (applicationId === "cloudcontrol") {
|
|
3268
3590
|
return mergeFinding(finding2, {
|
|
3269
3591
|
status: "met",
|
|
3270
3592
|
reason: "This application is itself a tooling/agent surface and does not register a callable platform service.",
|
|
3271
|
-
evidence: [`tooling=${
|
|
3593
|
+
evidence: [`tooling=${applicationId}`],
|
|
3272
3594
|
nextActions: []
|
|
3273
3595
|
});
|
|
3274
3596
|
}
|
|
@@ -3442,6 +3764,7 @@ function enrichFinding(application, finding2, evidence) {
|
|
|
3442
3764
|
case "agent-and-operator-surfaces": {
|
|
3443
3765
|
const declaredServices = application.services ?? [];
|
|
3444
3766
|
const text = evidence.source.text;
|
|
3767
|
+
const applicationId = String(application.id);
|
|
3445
3768
|
const items = [];
|
|
3446
3769
|
if (declaredServices.length > 0) items.push(`services=${declaredServices.join(",")}`);
|
|
3447
3770
|
if (text.includes("TopoloClient")) items.push("source=TopoloClient");
|
|
@@ -3449,11 +3772,11 @@ function enrichFinding(application, finding2, evidence) {
|
|
|
3449
3772
|
items.push("source=confirm-write-gate");
|
|
3450
3773
|
}
|
|
3451
3774
|
if (text.includes("@topolo/sdk")) items.push("source=@topolo/sdk");
|
|
3452
|
-
if (
|
|
3775
|
+
if (applicationId === "cloudcontrol") {
|
|
3453
3776
|
return mergeFinding(finding2, {
|
|
3454
3777
|
status: "met",
|
|
3455
3778
|
reason: "This application is itself an agent/operator surface (CloudControl).",
|
|
3456
|
-
evidence: [`tooling=${
|
|
3779
|
+
evidence: [`tooling=${applicationId}`, ...items],
|
|
3457
3780
|
nextActions: []
|
|
3458
3781
|
});
|
|
3459
3782
|
}
|
|
@@ -4231,6 +4554,8 @@ function scaffoldFiles(options) {
|
|
|
4231
4554
|
const { application, target } = options;
|
|
4232
4555
|
const slug = toSlug(application.id);
|
|
4233
4556
|
const base = target === "platform" ? firstPartyAppPath(application.appDir, options.payload.audience) : application.appDir;
|
|
4557
|
+
const browserBase = target === "platform" ? `${base}/apps/web` : base;
|
|
4558
|
+
const apiBase = target === "platform" ? `${base}/apps/api` : base;
|
|
4234
4559
|
const files = [
|
|
4235
4560
|
{
|
|
4236
4561
|
path: `${base}/package.json`,
|
|
@@ -4277,10 +4602,10 @@ function scaffoldFiles(options) {
|
|
|
4277
4602
|
"uses strict mode",
|
|
4278
4603
|
"includes browser DOM types for React and Worker types for API-backed apps"
|
|
4279
4604
|
],
|
|
4280
|
-
content: tsconfigJson(options.api)
|
|
4605
|
+
content: tsconfigJson(options.api, target)
|
|
4281
4606
|
},
|
|
4282
4607
|
{
|
|
4283
|
-
path: `${
|
|
4608
|
+
path: `${browserBase}/vite.config.ts`,
|
|
4284
4609
|
purpose: "Vite browser build configuration.",
|
|
4285
4610
|
requiredSignals: [
|
|
4286
4611
|
"builds the authenticated browser surface",
|
|
@@ -4289,7 +4614,7 @@ function scaffoldFiles(options) {
|
|
|
4289
4614
|
content: viteConfig(target)
|
|
4290
4615
|
},
|
|
4291
4616
|
{
|
|
4292
|
-
path: `${
|
|
4617
|
+
path: `${browserBase}/index.html`,
|
|
4293
4618
|
purpose: "Browser entry document.",
|
|
4294
4619
|
requiredSignals: [
|
|
4295
4620
|
"mounts the React app at #root",
|
|
@@ -4298,7 +4623,7 @@ function scaffoldFiles(options) {
|
|
|
4298
4623
|
content: indexHtml(application.name)
|
|
4299
4624
|
},
|
|
4300
4625
|
{
|
|
4301
|
-
path: `${
|
|
4626
|
+
path: `${browserBase}/src/main.tsx`,
|
|
4302
4627
|
purpose: "React app entrypoint.",
|
|
4303
4628
|
requiredSignals: [
|
|
4304
4629
|
"renders the generated app component",
|
|
@@ -4307,7 +4632,7 @@ function scaffoldFiles(options) {
|
|
|
4307
4632
|
content: mainTsx()
|
|
4308
4633
|
},
|
|
4309
4634
|
{
|
|
4310
|
-
path: `${
|
|
4635
|
+
path: `${browserBase}/src/env.d.ts`,
|
|
4311
4636
|
purpose: "Vite environment variable typing.",
|
|
4312
4637
|
requiredSignals: [
|
|
4313
4638
|
"loads vite/client import.meta.env types",
|
|
@@ -4327,7 +4652,7 @@ function scaffoldFiles(options) {
|
|
|
4327
4652
|
}
|
|
4328
4653
|
] : [],
|
|
4329
4654
|
{
|
|
4330
|
-
path: `${
|
|
4655
|
+
path: `${browserBase}/src/styles.css`,
|
|
4331
4656
|
purpose: "Minimal app-local styles outside the shared Topolo shell.",
|
|
4332
4657
|
requiredSignals: [
|
|
4333
4658
|
"does not fork the shared shell chrome",
|
|
@@ -4338,6 +4663,19 @@ function scaffoldFiles(options) {
|
|
|
4338
4663
|
];
|
|
4339
4664
|
if (target === "platform") {
|
|
4340
4665
|
files.push(
|
|
4666
|
+
{
|
|
4667
|
+
path: `${base}/topolo.app.json`,
|
|
4668
|
+
purpose: "Canonical app manifest that drives generated Wrangler and CloudControl metadata.",
|
|
4669
|
+
requiredSignals: [
|
|
4670
|
+
"declares web/api targets with canonical names and app-local target directories",
|
|
4671
|
+
"keeps Cloudflare account, domain, service id, and bindings in one manifest source of truth"
|
|
4672
|
+
],
|
|
4673
|
+
content: topoloAppManifestJson(application, {
|
|
4674
|
+
api: options.api,
|
|
4675
|
+
resources: options.payload.resources,
|
|
4676
|
+
profile: options.payload.profile
|
|
4677
|
+
})
|
|
4678
|
+
},
|
|
4341
4679
|
{
|
|
4342
4680
|
path: `${base}/topolo.cloudcontrol.json`,
|
|
4343
4681
|
purpose: "CloudControl source of truth for deploy targets, routes, bindings, and CI metadata.",
|
|
@@ -4463,7 +4801,7 @@ function scaffoldFiles(options) {
|
|
|
4463
4801
|
if (options.browser) {
|
|
4464
4802
|
if (target === "platform") {
|
|
4465
4803
|
files.push({
|
|
4466
|
-
path: `${
|
|
4804
|
+
path: `${browserBase}/src/service-identity.ts`,
|
|
4467
4805
|
purpose: "Central service identity resolver shared by browser and Worker runtime surfaces.",
|
|
4468
4806
|
requiredSignals: [
|
|
4469
4807
|
"exports the generated app id, display name, and stable Auth service slug",
|
|
@@ -4473,7 +4811,7 @@ function scaffoldFiles(options) {
|
|
|
4473
4811
|
});
|
|
4474
4812
|
}
|
|
4475
4813
|
files.push({
|
|
4476
|
-
path: `${
|
|
4814
|
+
path: `${browserBase}/src/App.tsx`,
|
|
4477
4815
|
purpose: "Authenticated browser surface.",
|
|
4478
4816
|
requiredSignals: [
|
|
4479
4817
|
"imports shared TopoloAppShell from @topolo-io/ui-kit",
|
|
@@ -4490,16 +4828,16 @@ function scaffoldFiles(options) {
|
|
|
4490
4828
|
if (options.api) {
|
|
4491
4829
|
files.push(
|
|
4492
4830
|
{
|
|
4493
|
-
path: `${
|
|
4831
|
+
path: `${apiBase}/wrangler.toml`,
|
|
4494
4832
|
purpose: "Cloudflare Worker runtime configuration.",
|
|
4495
4833
|
requiredSignals: [
|
|
4496
4834
|
"bindings match topolo.cloudcontrol.json or topolo.app.json",
|
|
4497
4835
|
"secrets are referenced by name only"
|
|
4498
4836
|
],
|
|
4499
|
-
content: wranglerToml(application, target, options.payload.resources, options.payload.profile)
|
|
4837
|
+
content: target === "platform" ? platformApiWranglerToml(application, options.payload.resources, options.payload.profile) : wranglerToml(application, target, options.payload.resources, options.payload.profile)
|
|
4500
4838
|
},
|
|
4501
4839
|
{
|
|
4502
|
-
path: `${
|
|
4840
|
+
path: `${apiBase}/src/worker.ts`,
|
|
4503
4841
|
purpose: "Protected service boundary.",
|
|
4504
4842
|
requiredSignals: [
|
|
4505
4843
|
"uses @topolo-io/worker-runtime for Worker auth, gatewaying, headers, and request helpers",
|
|
@@ -4514,6 +4852,37 @@ function scaffoldFiles(options) {
|
|
|
4514
4852
|
})
|
|
4515
4853
|
}
|
|
4516
4854
|
);
|
|
4855
|
+
if (target === "platform") {
|
|
4856
|
+
files.push(
|
|
4857
|
+
{
|
|
4858
|
+
path: `${apiBase}/src/service-identity.ts`,
|
|
4859
|
+
purpose: "Runtime service identity resolver for the API Worker.",
|
|
4860
|
+
requiredSignals: [
|
|
4861
|
+
"resolves the concrete Auth service id from Worker vars",
|
|
4862
|
+
"keeps the API Worker independent from browser-only import.meta usage"
|
|
4863
|
+
],
|
|
4864
|
+
content: apiServiceIdentityTs(application)
|
|
4865
|
+
},
|
|
4866
|
+
{
|
|
4867
|
+
path: `${browserBase}/src/worker.ts`,
|
|
4868
|
+
purpose: "Browser Worker that serves assets and forwards API paths to the API Worker binding.",
|
|
4869
|
+
requiredSignals: [
|
|
4870
|
+
"keeps the frontend Worker thin",
|
|
4871
|
+
"routes /api/* to the API service binding instead of owning backend routes locally"
|
|
4872
|
+
],
|
|
4873
|
+
content: webWorkerTs(application)
|
|
4874
|
+
},
|
|
4875
|
+
{
|
|
4876
|
+
path: `${browserBase}/wrangler.toml`,
|
|
4877
|
+
purpose: "Cloudflare Worker static-assets configuration for the browser surface.",
|
|
4878
|
+
requiredSignals: [
|
|
4879
|
+
"serves Vite assets through a Worker with assets",
|
|
4880
|
+
"binds the frontend Worker to the API Worker for /api/* requests"
|
|
4881
|
+
],
|
|
4882
|
+
content: platformWebWranglerToml(application)
|
|
4883
|
+
}
|
|
4884
|
+
);
|
|
4885
|
+
}
|
|
4517
4886
|
}
|
|
4518
4887
|
return files;
|
|
4519
4888
|
}
|
|
@@ -4543,20 +4912,22 @@ function topoloConformanceWorkflow(options) {
|
|
|
4543
4912
|
const docsCheckoutStep = options.appDir === "TopoloDocs" ? [] : [
|
|
4544
4913
|
"",
|
|
4545
4914
|
" - name: Checkout TopoloDocs",
|
|
4915
|
+
` if: steps.app-token.outputs.token != '' || env.HAS_TOPOLO_CI_REPO_TOKEN == 'true'`,
|
|
4546
4916
|
" uses: actions/checkout@v4",
|
|
4547
4917
|
" with:",
|
|
4548
|
-
" repository: Topolo-io/
|
|
4918
|
+
" repository: Topolo-io/TopoloDocs",
|
|
4549
4919
|
" path: Apps/system/TopoloDocs",
|
|
4550
|
-
" token: ${{
|
|
4920
|
+
" token: ${{ steps.app-token.outputs.token || secrets.TOPOLO_CI_REPO_TOKEN }}"
|
|
4551
4921
|
];
|
|
4552
4922
|
const cliCheckoutStep = options.appDir === "TopoloCLI" || options.appDir === "TopoloCli" ? [] : [
|
|
4553
4923
|
"",
|
|
4554
4924
|
" - name: Checkout Topolo CLI",
|
|
4925
|
+
` if: steps.app-token.outputs.token != '' || env.HAS_TOPOLO_CI_REPO_TOKEN == 'true'`,
|
|
4555
4926
|
" uses: actions/checkout@v4",
|
|
4556
4927
|
" with:",
|
|
4557
4928
|
" repository: Topolo-io/TopoloCli",
|
|
4558
4929
|
" path: Apps/system/TopoloCLI",
|
|
4559
|
-
" token: ${{
|
|
4930
|
+
" token: ${{ steps.app-token.outputs.token || secrets.TOPOLO_CI_REPO_TOKEN }}"
|
|
4560
4931
|
];
|
|
4561
4932
|
return [
|
|
4562
4933
|
"name: Topolo App Conformance",
|
|
@@ -4574,44 +4945,66 @@ function topoloConformanceWorkflow(options) {
|
|
|
4574
4945
|
"jobs:",
|
|
4575
4946
|
" conformance:",
|
|
4576
4947
|
" runs-on: ubuntu-latest",
|
|
4948
|
+
" env:",
|
|
4949
|
+
` HAS_TOPOLO_PACKAGES_APP: \${{ secrets.TOPOLO_PACKAGES_APP_ID != '' && secrets.TOPOLO_PACKAGES_APP_PRIVATE_KEY != '' }}`,
|
|
4950
|
+
` HAS_TOPOLO_CI_REPO_TOKEN: \${{ secrets.TOPOLO_CI_REPO_TOKEN != '' }}`,
|
|
4577
4951
|
" steps:",
|
|
4578
4952
|
" - name: Checkout application",
|
|
4579
4953
|
" uses: actions/checkout@v4",
|
|
4580
4954
|
" with:",
|
|
4581
4955
|
` path: ${appPath}`,
|
|
4956
|
+
"",
|
|
4957
|
+
" - name: Mint Topolo cross-repo token",
|
|
4958
|
+
" id: app-token",
|
|
4959
|
+
` if: env.HAS_TOPOLO_PACKAGES_APP == 'true'`,
|
|
4960
|
+
" uses: actions/create-github-app-token@v1",
|
|
4961
|
+
" with:",
|
|
4962
|
+
` app-id: \${{ secrets.TOPOLO_PACKAGES_APP_ID }}`,
|
|
4963
|
+
` private-key: \${{ secrets.TOPOLO_PACKAGES_APP_PRIVATE_KEY }}`,
|
|
4964
|
+
" owner: Topolo-io",
|
|
4582
4965
|
...docsCheckoutStep,
|
|
4583
4966
|
"",
|
|
4584
4967
|
" - name: Checkout Topolo SDK",
|
|
4968
|
+
` if: steps.app-token.outputs.token != '' || env.HAS_TOPOLO_CI_REPO_TOKEN == 'true'`,
|
|
4585
4969
|
" uses: actions/checkout@v4",
|
|
4586
4970
|
" with:",
|
|
4587
4971
|
" repository: Topolo-io/topolo-sdk",
|
|
4588
4972
|
" path: Apps/packages/topolo-sdk",
|
|
4589
|
-
" token: ${{
|
|
4973
|
+
" token: ${{ steps.app-token.outputs.token || secrets.TOPOLO_CI_REPO_TOKEN }}",
|
|
4590
4974
|
...cliCheckoutStep,
|
|
4591
4975
|
"",
|
|
4976
|
+
" - name: Skip conformance without cross-repo token",
|
|
4977
|
+
` if: steps.app-token.outputs.token == '' && env.HAS_TOPOLO_CI_REPO_TOKEN != 'true'`,
|
|
4978
|
+
" run: |",
|
|
4979
|
+
' echo "::warning::Skipping Topolo app conformance because no Topolo cross-repo token is available to this workflow context."',
|
|
4980
|
+
"",
|
|
4592
4981
|
" - name: Setup Node.js",
|
|
4982
|
+
` if: steps.app-token.outputs.token != '' || env.HAS_TOPOLO_CI_REPO_TOKEN == 'true'`,
|
|
4593
4983
|
" uses: actions/setup-node@v4",
|
|
4594
4984
|
" with:",
|
|
4595
4985
|
" node-version: 20",
|
|
4596
4986
|
"",
|
|
4597
4987
|
" - name: Build Topolo SDK",
|
|
4988
|
+
` if: steps.app-token.outputs.token != '' || env.HAS_TOPOLO_CI_REPO_TOKEN == 'true'`,
|
|
4598
4989
|
" working-directory: Apps/packages/topolo-sdk",
|
|
4599
4990
|
" run: |",
|
|
4600
4991
|
" npm install --no-audit --no-fund",
|
|
4601
4992
|
" npm run build",
|
|
4602
4993
|
"",
|
|
4603
4994
|
" - name: Build Topolo CLI",
|
|
4995
|
+
` if: steps.app-token.outputs.token != '' || env.HAS_TOPOLO_CI_REPO_TOKEN == 'true'`,
|
|
4604
4996
|
" working-directory: Apps/system/TopoloCLI",
|
|
4605
4997
|
" run: |",
|
|
4606
4998
|
" npm install --no-audit --no-fund",
|
|
4607
4999
|
" npm run build",
|
|
4608
5000
|
"",
|
|
4609
5001
|
" - name: Run Topolo app conformance audit",
|
|
5002
|
+
` if: steps.app-token.outputs.token != '' || env.HAS_TOPOLO_CI_REPO_TOKEN == 'true'`,
|
|
4610
5003
|
" run: |",
|
|
4611
5004
|
` node Apps/system/TopoloCLI/dist/index.js apps audit ${options.id} --local --repo-root "$GITHUB_WORKSPACE" --fail-on needs_review --json`,
|
|
4612
5005
|
"",
|
|
4613
5006
|
" - name: Record green CI evidence",
|
|
4614
|
-
` if: \${{ success() }}`,
|
|
5007
|
+
` if: \${{ success() && (steps.app-token.outputs.token != '' || env.HAS_TOPOLO_CI_REPO_TOKEN == 'true') }}`,
|
|
4615
5008
|
` working-directory: ${appPath}`,
|
|
4616
5009
|
" run: |",
|
|
4617
5010
|
` node "$GITHUB_WORKSPACE/Apps/system/TopoloCLI/dist/index.js" apps record-evidence ${options.id} --build --typecheck --test --commit "$GITHUB_SHA"`
|
|
@@ -4625,9 +5018,9 @@ function packageJson(application, target, options) {
|
|
|
4625
5018
|
vite: "^5.4.0"
|
|
4626
5019
|
};
|
|
4627
5020
|
const scripts = {
|
|
4628
|
-
dev: "vite --host 0.0.0.0",
|
|
4629
|
-
build: "vite build",
|
|
4630
|
-
preview: "vite preview --host 0.0.0.0",
|
|
5021
|
+
dev: target === "platform" ? "vite --config apps/web/vite.config.ts --host 0.0.0.0" : "vite --host 0.0.0.0",
|
|
5022
|
+
build: target === "platform" ? "vite build --config apps/web/vite.config.ts" : "vite build",
|
|
5023
|
+
preview: target === "platform" ? "vite preview --config apps/web/vite.config.ts --host 0.0.0.0" : "vite preview --host 0.0.0.0",
|
|
4631
5024
|
typecheck: "tsc --noEmit"
|
|
4632
5025
|
};
|
|
4633
5026
|
if (options.browser) {
|
|
@@ -4639,27 +5032,30 @@ function packageJson(application, target, options) {
|
|
|
4639
5032
|
if (target === "platform") {
|
|
4640
5033
|
dependencies["@topolo-io/auth-client"] = topoloPackageVersion("@topolo-io/auth-client", target);
|
|
4641
5034
|
dependencies["@topolo-io/design-tokens"] = topoloPackageVersion("@topolo-io/design-tokens", target);
|
|
5035
|
+
dependencies["@topolo-io/onboarding"] = topoloPackageVersion("@topolo-io/onboarding", target);
|
|
5036
|
+
dependencies["@topolo-io/tour"] = topoloPackageVersion("@topolo-io/tour", target);
|
|
4642
5037
|
dependencies["@topolo-io/ui-kit"] = topoloPackageVersion("@topolo-io/ui-kit", target);
|
|
4643
5038
|
} else {
|
|
4644
5039
|
dependencies["@topolo/login"] = topoloPackageVersion("@topolo/login", target);
|
|
4645
5040
|
}
|
|
4646
5041
|
}
|
|
4647
5042
|
if (options.api) {
|
|
5043
|
+
devDependencies["@cloudflare/workers-types"] = "^4.20260413.1";
|
|
4648
5044
|
if (target === "platform") {
|
|
4649
5045
|
dependencies["@topolo-io/worker-runtime"] = topoloPackageVersion("@topolo-io/worker-runtime", target);
|
|
4650
|
-
dependencies["@topolo-io/widget-server"] = topoloPackageVersion("@topolo-io/widget-server", target);
|
|
4651
5046
|
dependencies["@topolo/sdk"] = topoloPackageVersion("@topolo/sdk", target);
|
|
5047
|
+
dependencies.hono = "^4";
|
|
4652
5048
|
scripts.deploy = `node -e 'console.error("\\nX Bare deploy is disabled. Use deploy:staging or deploy:production.\\n"); process.exit(1)'`;
|
|
4653
|
-
scripts["deploy:staging"] = "DEPLOY_ENVIRONMENT=staging VITE_TOPOLO_AUTH_URL=https://auth.stg.topolo.us npm run build && wrangler deploy --env staging";
|
|
4654
|
-
scripts["deploy:production"] = "DEPLOY_ENVIRONMENT=production VITE_TOPOLO_AUTH_URL=https://auth.topolo.app npm run build && wrangler deploy";
|
|
5049
|
+
scripts["deploy:staging"] = "DEPLOY_ENVIRONMENT=staging VITE_TOPOLO_AUTH_URL=https://auth.stg.topolo.us npm run build && wrangler deploy --config apps/api/wrangler.toml --env staging && wrangler deploy --config apps/web/wrangler.toml --env staging";
|
|
5050
|
+
scripts["deploy:production"] = "DEPLOY_ENVIRONMENT=production VITE_TOPOLO_AUTH_URL=https://auth.topolo.app npm run build && wrangler deploy --config apps/api/wrangler.toml --env production && wrangler deploy --config apps/web/wrangler.toml --env production";
|
|
4655
5051
|
} else {
|
|
4656
|
-
dependencies["@topolo
|
|
5052
|
+
dependencies["@topolo/sdk"] = topoloPackageVersion("@topolo/sdk", target);
|
|
4657
5053
|
scripts.deploy = "npm run build && wrangler deploy";
|
|
4658
5054
|
}
|
|
4659
5055
|
devDependencies.wrangler = "^4.40.2";
|
|
4660
5056
|
}
|
|
4661
5057
|
if (target === "platform" && hasScaffoldResources(options.resources)) {
|
|
4662
|
-
scripts["check:deploy-config"] = "wrangler deploy --dry-run --outdir .wrangler/build";
|
|
5058
|
+
scripts["check:deploy-config"] = "wrangler deploy --config apps/api/wrangler.toml --env staging --dry-run --outdir .wrangler/api-build && wrangler deploy --config apps/web/wrangler.toml --env staging --dry-run --outdir .wrangler/web-build";
|
|
4663
5059
|
}
|
|
4664
5060
|
return `${json({
|
|
4665
5061
|
name: application.packageName,
|
|
@@ -4676,7 +5072,7 @@ function topoloPackageVersion(packageName, target) {
|
|
|
4676
5072
|
if (target === "developer") {
|
|
4677
5073
|
if (packageName === "@topolo/login") return "^0.1.0";
|
|
4678
5074
|
if (packageName === "@topolo-io/auth-client") return "^1.0.0";
|
|
4679
|
-
if (packageName === "@topolo
|
|
5075
|
+
if (packageName === "@topolo/sdk") return "^0.4.1";
|
|
4680
5076
|
return "^0.1.0";
|
|
4681
5077
|
}
|
|
4682
5078
|
const platformPackageFolders = {
|
|
@@ -4686,8 +5082,9 @@ function topoloPackageVersion(packageName, target) {
|
|
|
4686
5082
|
"@topolo-io/auth-middleware": "topolo-auth-middleware",
|
|
4687
5083
|
"@topolo-io/worker-runtime": "topolo-worker-runtime",
|
|
4688
5084
|
"@topolo-io/design-tokens": "topolo-design-tokens",
|
|
4689
|
-
"@topolo-io/
|
|
4690
|
-
"@topolo-io/
|
|
5085
|
+
"@topolo-io/onboarding": "topolo-onboarding",
|
|
5086
|
+
"@topolo-io/tour": "topolo-tour",
|
|
5087
|
+
"@topolo-io/ui-kit": "topolo-ui-kit"
|
|
4691
5088
|
};
|
|
4692
5089
|
const folder = platformPackageFolders[packageName];
|
|
4693
5090
|
if (!folder) {
|
|
@@ -4772,7 +5169,7 @@ function readme(application, target, options) {
|
|
|
4772
5169
|
"- `vite.config.ts` includes the standard React plugin plus React runtime dedupe so linked Topolo packages resolve one browser React runtime."
|
|
4773
5170
|
);
|
|
4774
5171
|
if (options.api) {
|
|
4775
|
-
lines.push("- `@topolo-io/worker-runtime` owns Worker auth validation, `/api/auth/*` gatewaying, security headers, request ids, and BugFix reporting.");
|
|
5172
|
+
lines.push("- `@topolo-io/worker-runtime` owns Worker auth validation, `/api/auth/*` gatewaying, security headers, request ids, Nexus API-call usage monitoring, and BugFix reporting.");
|
|
4776
5173
|
}
|
|
4777
5174
|
if (hasScaffoldResources(options.resources)) {
|
|
4778
5175
|
lines.push(
|
|
@@ -4816,7 +5213,8 @@ function readme(application, target, options) {
|
|
|
4816
5213
|
return `${lines.join("\n")}
|
|
4817
5214
|
`;
|
|
4818
5215
|
}
|
|
4819
|
-
function tsconfigJson(api) {
|
|
5216
|
+
function tsconfigJson(api, target) {
|
|
5217
|
+
const include = target === "platform" ? ["apps/web/src", ...api ? ["apps/api/src"] : []] : ["src"];
|
|
4820
5218
|
return `${json({
|
|
4821
5219
|
compilerOptions: {
|
|
4822
5220
|
target: "ES2022",
|
|
@@ -4834,9 +5232,9 @@ function tsconfigJson(api) {
|
|
|
4834
5232
|
isolatedModules: true,
|
|
4835
5233
|
noEmit: true,
|
|
4836
5234
|
jsx: "react-jsx",
|
|
4837
|
-
types: ["vite/client"]
|
|
5235
|
+
types: api ? ["vite/client", "@cloudflare/workers-types"] : ["vite/client"]
|
|
4838
5236
|
},
|
|
4839
|
-
include
|
|
5237
|
+
include,
|
|
4840
5238
|
references: []
|
|
4841
5239
|
})}
|
|
4842
5240
|
`;
|
|
@@ -4958,6 +5356,32 @@ function serviceIdentityTs(application) {
|
|
|
4958
5356
|
""
|
|
4959
5357
|
].join("\n");
|
|
4960
5358
|
}
|
|
5359
|
+
function apiServiceIdentityTs(application) {
|
|
5360
|
+
const appName = toTitle(application.name);
|
|
5361
|
+
const serviceSlug = application.serviceSlug ?? `topolo-${toSlug(application.id)}`;
|
|
5362
|
+
return [
|
|
5363
|
+
`export const SCAFFOLD_APP_ID = '${application.id}';`,
|
|
5364
|
+
`export const SCAFFOLD_APP_NAME = '${escapeSingleQuoted(appName)}';`,
|
|
5365
|
+
`export const SCAFFOLD_SERVICE_SLUG = '${escapeSingleQuoted(serviceSlug)}';`,
|
|
5366
|
+
"",
|
|
5367
|
+
"interface ServiceIdentityEnv {",
|
|
5368
|
+
" SERVICE_ID?: string;",
|
|
5369
|
+
"}",
|
|
5370
|
+
"",
|
|
5371
|
+
"function requireServiceId(value: unknown): string {",
|
|
5372
|
+
" const serviceId = typeof value === 'string' ? value.trim() : '';",
|
|
5373
|
+
" if (!serviceId) {",
|
|
5374
|
+
" throw new Error(`SERVICE_ID is required for ${SCAFFOLD_SERVICE_SLUG}`);",
|
|
5375
|
+
" }",
|
|
5376
|
+
" return serviceId;",
|
|
5377
|
+
"}",
|
|
5378
|
+
"",
|
|
5379
|
+
"export function resolveRuntimeServiceId(env: ServiceIdentityEnv): Promise<string> {",
|
|
5380
|
+
" return Promise.resolve(requireServiceId(env.SERVICE_ID));",
|
|
5381
|
+
"}",
|
|
5382
|
+
""
|
|
5383
|
+
].join("\n");
|
|
5384
|
+
}
|
|
4961
5385
|
function cloudflareWorkersDts() {
|
|
4962
5386
|
return [
|
|
4963
5387
|
"declare module 'cloudflare:workers' {",
|
|
@@ -5025,10 +5449,11 @@ function viteConfig(target) {
|
|
|
5025
5449
|
" process.env.VITE_TOPOLO_AUTH_URL === 'https://auth.stg.topolo.us';",
|
|
5026
5450
|
"",
|
|
5027
5451
|
" return {",
|
|
5452
|
+
" root: fileURLToPath(new URL('.', import.meta.url)),",
|
|
5028
5453
|
" plugins: [react(), ...(isStagingBuild ? [stagingUrlRewrite()] : [])],",
|
|
5029
5454
|
" resolve: {",
|
|
5030
5455
|
" alias: {",
|
|
5031
|
-
" '@topolo-io/auth-client': fileURLToPath(new URL('
|
|
5456
|
+
" '@topolo-io/auth-client': fileURLToPath(new URL('../../node_modules/@topolo-io/auth-client/dist/index.js', import.meta.url)),",
|
|
5032
5457
|
" },",
|
|
5033
5458
|
" dedupe: ['react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime'],",
|
|
5034
5459
|
" },",
|
|
@@ -5060,6 +5485,8 @@ function mainTsx() {
|
|
|
5060
5485
|
"import React from 'react';",
|
|
5061
5486
|
"import { createRoot } from 'react-dom/client';",
|
|
5062
5487
|
"import '@topolo-io/design-tokens/tokens.css';",
|
|
5488
|
+
"import '@topolo-io/tour/styles.css';",
|
|
5489
|
+
"import '@topolo-io/onboarding/styles.css';",
|
|
5063
5490
|
"import App from './App';",
|
|
5064
5491
|
"import './styles.css';",
|
|
5065
5492
|
"",
|
|
@@ -5162,16 +5589,19 @@ function platformAppTsx(application, options) {
|
|
|
5162
5589
|
const baselineHeading = isPersonal ? "Shared personal baseline" : "Shared workspace baseline";
|
|
5163
5590
|
const baselineDescription = isPersonal ? "This scaffold starts on the shared landing and login surfaces, completes sign-in on the shared callback path, and renders the signed personal app inside the shared Topolo shell." : "This scaffold starts on the shared landing and login surfaces, completes sign-in on the shared callback path, and renders the signed workspace inside the shared Topolo shell.";
|
|
5164
5591
|
return [
|
|
5165
|
-
"import { Component, useEffect, useMemo, useState, type ErrorInfo, type ReactNode } from 'react';",
|
|
5592
|
+
"import { Component, useCallback, useEffect, useMemo, useState, type ErrorInfo, type ReactNode } from 'react';",
|
|
5166
5593
|
"import { createBrowserAuthSessionController, type AuthUser } from '@topolo-io/auth-client';",
|
|
5167
5594
|
"import { LandingPage, LoginPage, TopoloAppShell, TopoloAuthFlowScreen, TopoloLoadingScreen, setupBugReporterErrorCapture, type TopoloAppShellUser } from '@topolo-io/ui-kit';",
|
|
5595
|
+
"import { GettingStarted, type OnboardingGuideStep } from '@topolo-io/onboarding';",
|
|
5596
|
+
"import { IntroTour } from '@topolo-io/tour';",
|
|
5168
5597
|
"import { SCAFFOLD_APP_ID, SCAFFOLD_APP_NAME, SCAFFOLD_SERVICE_SLUG, getBrowserAuthBaseUrl, resolveAppServiceId } from './service-identity';",
|
|
5169
5598
|
"",
|
|
5170
5599
|
"// Wire global error/console capture so BugReporter (enabled in TopoloAppShell below)",
|
|
5171
5600
|
"// can attach the last few errors to any submitted bug report.",
|
|
5172
5601
|
"setupBugReporterErrorCapture();",
|
|
5173
5602
|
"",
|
|
5174
|
-
"type NavItem = 'home';",
|
|
5603
|
+
"type NavItem = 'home' | 'getting-started';",
|
|
5604
|
+
"type WorkspaceView = 'workspace' | 'getting-started';",
|
|
5175
5605
|
"type AppRoute = { kind: 'root' } | { kind: 'login' } | { kind: 'callback' };",
|
|
5176
5606
|
"type BrowserAuthModule = ReturnType<typeof createBrowserAuthSessionController>;",
|
|
5177
5607
|
"",
|
|
@@ -5248,7 +5678,17 @@ function platformAppTsx(application, options) {
|
|
|
5248
5678
|
" const [loading, setLoading] = useState(true);",
|
|
5249
5679
|
" const [authError, setAuthError] = useState('');",
|
|
5250
5680
|
" const [loginAttempted, setLoginAttempted] = useState(false);",
|
|
5681
|
+
" const [view, setView] = useState<WorkspaceView>('workspace');",
|
|
5251
5682
|
" const auth = useMemo(() => serviceId ? getAuthModule(serviceId) : null, [serviceId]);",
|
|
5683
|
+
" const openWorkspace = useCallback(() => setView('workspace'), []);",
|
|
5684
|
+
" const openGettingStarted = useCallback(() => {",
|
|
5685
|
+
" setView('getting-started');",
|
|
5686
|
+
" if (typeof window !== 'undefined') window.scrollTo({ top: 0, behavior: 'smooth' });",
|
|
5687
|
+
" }, []);",
|
|
5688
|
+
" const handleNavSelect = useCallback((id: NavItem) => {",
|
|
5689
|
+
" if (id === 'getting-started') openGettingStarted();",
|
|
5690
|
+
" else openWorkspace();",
|
|
5691
|
+
" }, [openGettingStarted, openWorkspace]);",
|
|
5252
5692
|
"",
|
|
5253
5693
|
" useEffect(() => {",
|
|
5254
5694
|
" let active = true;",
|
|
@@ -5447,11 +5887,11 @@ function platformAppTsx(application, options) {
|
|
|
5447
5887
|
" orgId={user.activeContextType === 'organization' ? user.activeContextId ?? user.orgId ?? null : null}",
|
|
5448
5888
|
" activeContextType={user.activeContextType}",
|
|
5449
5889
|
" activeContextId={user.activeContextId}",
|
|
5450
|
-
|
|
5451
|
-
` navItems={[{ id: 'home', label: '${escapeSingleQuoted(workspaceTitle)}' }]}`,
|
|
5890
|
+
" activeNavItemId={view === 'getting-started' ? 'getting-started' : 'home'}",
|
|
5891
|
+
` navItems={[{ id: 'home', label: '${escapeSingleQuoted(workspaceTitle)}' }, { id: 'getting-started', label: 'Getting started' }]}`,
|
|
5452
5892
|
' navigationMode="topbar"',
|
|
5453
|
-
" onNavItemSelect={
|
|
5454
|
-
` title=
|
|
5893
|
+
" onNavItemSelect={handleNavSelect}",
|
|
5894
|
+
` title={view === 'getting-started' ? 'Getting started' : '${escapeSingleQuoted(workspaceTitle)}'}`,
|
|
5455
5895
|
" authUrl={AUTH_URL}",
|
|
5456
5896
|
" getAccessToken={getAccessToken}",
|
|
5457
5897
|
" onSignOut={async () => {",
|
|
@@ -5463,18 +5903,94 @@ function platformAppTsx(application, options) {
|
|
|
5463
5903
|
" enableCommandPalette",
|
|
5464
5904
|
" enableBugReporter",
|
|
5465
5905
|
" >",
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
"
|
|
5470
|
-
|
|
5471
|
-
"
|
|
5472
|
-
"
|
|
5473
|
-
"
|
|
5906
|
+
" {view === 'getting-started' ? (",
|
|
5907
|
+
" <ScaffoldGettingStarted",
|
|
5908
|
+
" serviceId={activeServiceId}",
|
|
5909
|
+
" organizationId={user.organization?.id ?? user.orgId ?? ''}",
|
|
5910
|
+
" role={user.role}",
|
|
5911
|
+
" onOpenWorkspace={openWorkspace}",
|
|
5912
|
+
" />",
|
|
5913
|
+
" ) : (",
|
|
5914
|
+
' <div className="topolo-starter-workspace">',
|
|
5915
|
+
' <section className="topolo-starter-card" data-tour="workspace-card">',
|
|
5916
|
+
` <h2>${baselineHeading}</h2>`,
|
|
5917
|
+
" <p>",
|
|
5918
|
+
` ${baselineDescription}`,
|
|
5919
|
+
" </p>",
|
|
5920
|
+
" </section>",
|
|
5921
|
+
" </div>",
|
|
5922
|
+
" )}",
|
|
5923
|
+
" <IntroTour",
|
|
5924
|
+
" appName={APP_NAME}",
|
|
5925
|
+
" role={user.role}",
|
|
5926
|
+
" onOpenGettingStarted={openGettingStarted}",
|
|
5927
|
+
" extraSteps={[",
|
|
5928
|
+
" {",
|
|
5929
|
+
" id: 'workspace-card',",
|
|
5930
|
+
` target: '[data-tour="workspace-card"]',`,
|
|
5931
|
+
" title: 'Your workspace',",
|
|
5932
|
+
" content: 'Everything you build renders here, inside the shared Topolo shell.',",
|
|
5933
|
+
" placement: 'bottom' as const,",
|
|
5934
|
+
" beforeStep: () => openWorkspace(),",
|
|
5935
|
+
" },",
|
|
5936
|
+
" ]}",
|
|
5937
|
+
" />",
|
|
5474
5938
|
" </TopoloAppShell>",
|
|
5475
5939
|
" );",
|
|
5476
5940
|
"}",
|
|
5477
5941
|
"",
|
|
5942
|
+
"function ScaffoldGettingStarted(props: {",
|
|
5943
|
+
" serviceId: string;",
|
|
5944
|
+
" organizationId: string;",
|
|
5945
|
+
" role?: string;",
|
|
5946
|
+
" onOpenWorkspace: () => void;",
|
|
5947
|
+
"}) {",
|
|
5948
|
+
" const { serviceId, organizationId, role, onOpenWorkspace } = props;",
|
|
5949
|
+
" const steps: OnboardingGuideStep[] = [",
|
|
5950
|
+
" {",
|
|
5951
|
+
" id: 'explore-workspace',",
|
|
5952
|
+
" title: 'Explore your workspace',",
|
|
5953
|
+
" description:",
|
|
5954
|
+
" 'Your app renders inside the shared Topolo shell \u2014 launcher, command palette, and account menu are already wired in.',",
|
|
5955
|
+
" actionLabel: 'Open workspace',",
|
|
5956
|
+
" onAction: onOpenWorkspace,",
|
|
5957
|
+
" },",
|
|
5958
|
+
" {",
|
|
5959
|
+
" id: 'discover-platform',",
|
|
5960
|
+
" title: 'Move between your Topolo apps',",
|
|
5961
|
+
" description:",
|
|
5962
|
+
" 'Use the launcher to switch between your Topolo apps, and the command palette (Cmd/Ctrl-K) to jump anywhere fast.',",
|
|
5963
|
+
" optional: true,",
|
|
5964
|
+
" },",
|
|
5965
|
+
" {",
|
|
5966
|
+
" id: 'build-feature',",
|
|
5967
|
+
" title: 'Build your first feature',",
|
|
5968
|
+
" description:",
|
|
5969
|
+
" 'Replace the starter card with your product surface, and gate write actions with service scopes before you ship.',",
|
|
5970
|
+
" },",
|
|
5971
|
+
" ];",
|
|
5972
|
+
" return (",
|
|
5973
|
+
' <div className="topolo-starter-workspace">',
|
|
5974
|
+
" <GettingStarted",
|
|
5975
|
+
" authApiBaseUrl={`${AUTH_URL}/api`}",
|
|
5976
|
+
" organizationId={organizationId}",
|
|
5977
|
+
" serviceId={serviceId}",
|
|
5978
|
+
" getAccessToken={() => getAccessToken()}",
|
|
5979
|
+
" role={role || undefined}",
|
|
5980
|
+
" steps={steps}",
|
|
5981
|
+
" eyebrow={`Welcome to ${APP_NAME}`}",
|
|
5982
|
+
" title={`Get started with ${APP_NAME}`}",
|
|
5983
|
+
' subtitle="A short checklist to orient you in your new Topolo workspace."',
|
|
5984
|
+
' completeLabel="Mark done"',
|
|
5985
|
+
' dismissLabel="Skip for now"',
|
|
5986
|
+
" completedContent={`You're all set \u2014 ${APP_NAME} is ready to build on.`}",
|
|
5987
|
+
" completeAction={{ label: 'Go to workspace', onClick: onOpenWorkspace }}",
|
|
5988
|
+
" onDismiss={onOpenWorkspace}",
|
|
5989
|
+
" />",
|
|
5990
|
+
" </div>",
|
|
5991
|
+
" );",
|
|
5992
|
+
"}",
|
|
5993
|
+
"",
|
|
5478
5994
|
"function getRoute(): AppRoute {",
|
|
5479
5995
|
" const pathname = window.location.pathname.replace(/\\/+$/, '') || '/';",
|
|
5480
5996
|
" if (pathname === '/login') return { kind: 'login' };",
|
|
@@ -5627,6 +6143,208 @@ function developerAppTsx(application) {
|
|
|
5627
6143
|
""
|
|
5628
6144
|
].join("\n");
|
|
5629
6145
|
}
|
|
6146
|
+
function webWorkerTs(application) {
|
|
6147
|
+
const serviceName = toTitle(application.name);
|
|
6148
|
+
return [
|
|
6149
|
+
"interface Env {",
|
|
6150
|
+
" API: { fetch(request: Request): Promise<Response> };",
|
|
6151
|
+
"}",
|
|
6152
|
+
"",
|
|
6153
|
+
`const SERVICE_NAME = '${escapeSingleQuoted(serviceName)}';`,
|
|
6154
|
+
"",
|
|
6155
|
+
"export default {",
|
|
6156
|
+
" async fetch(request: Request, env: Env): Promise<Response> {",
|
|
6157
|
+
" const url = new URL(request.url);",
|
|
6158
|
+
" if (url.pathname.startsWith('/api/')) {",
|
|
6159
|
+
" return env.API.fetch(request);",
|
|
6160
|
+
" }",
|
|
6161
|
+
" return Response.json({ ok: true, service: SERVICE_NAME }, { status: 200 });",
|
|
6162
|
+
" },",
|
|
6163
|
+
"};",
|
|
6164
|
+
""
|
|
6165
|
+
].join("\n");
|
|
6166
|
+
}
|
|
6167
|
+
function platformWebWranglerToml(application) {
|
|
6168
|
+
const slug = toSlug(application.id);
|
|
6169
|
+
const host = application.productionUrl ? new URL(application.productionUrl).host : `${slug}.topolo.app`;
|
|
6170
|
+
return [
|
|
6171
|
+
`name = "topolo-${slug}"`,
|
|
6172
|
+
'main = "src/worker.ts"',
|
|
6173
|
+
`compatibility_date = "${CLOUDFLARE_COMPATIBILITY_DATE}"`,
|
|
6174
|
+
'compatibility_flags = ["nodejs_compat"]',
|
|
6175
|
+
`account_id = "${CLOUDFLARE_ACCOUNT_ID}"`,
|
|
6176
|
+
"workers_dev = false",
|
|
6177
|
+
"",
|
|
6178
|
+
"[assets]",
|
|
6179
|
+
'directory = "./dist"',
|
|
6180
|
+
'binding = "ASSETS"',
|
|
6181
|
+
'not_found_handling = "single-page-application"',
|
|
6182
|
+
'run_worker_first = ["/api/*"]',
|
|
6183
|
+
"",
|
|
6184
|
+
"[observability]",
|
|
6185
|
+
"enabled = true",
|
|
6186
|
+
"",
|
|
6187
|
+
"[[routes]]",
|
|
6188
|
+
`pattern = "${host}"`,
|
|
6189
|
+
"custom_domain = true",
|
|
6190
|
+
"",
|
|
6191
|
+
"[vars]",
|
|
6192
|
+
`SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6193
|
+
`VITE_TOPOLO_SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6194
|
+
"",
|
|
6195
|
+
"[[services]]",
|
|
6196
|
+
'binding = "API"',
|
|
6197
|
+
`service = "topolo-${slug}-api"`,
|
|
6198
|
+
"",
|
|
6199
|
+
"[env.staging]",
|
|
6200
|
+
`name = "topolo-${slug}-staging"`,
|
|
6201
|
+
`account_id = "${STAGING_CLOUDFLARE_ACCOUNT_ID}"`,
|
|
6202
|
+
"workers_dev = true",
|
|
6203
|
+
"",
|
|
6204
|
+
"[env.staging.vars]",
|
|
6205
|
+
`SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6206
|
+
`VITE_TOPOLO_SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6207
|
+
"",
|
|
6208
|
+
"[[env.staging.routes]]",
|
|
6209
|
+
`pattern = "${slug}.stg.topolo.us"`,
|
|
6210
|
+
"custom_domain = true",
|
|
6211
|
+
"",
|
|
6212
|
+
"[env.staging.assets]",
|
|
6213
|
+
'directory = "./dist"',
|
|
6214
|
+
'binding = "ASSETS"',
|
|
6215
|
+
'not_found_handling = "single-page-application"',
|
|
6216
|
+
'run_worker_first = ["/api/*"]',
|
|
6217
|
+
"",
|
|
6218
|
+
"[[env.staging.services]]",
|
|
6219
|
+
'binding = "API"',
|
|
6220
|
+
`service = "topolo-${slug}-api-staging"`,
|
|
6221
|
+
"",
|
|
6222
|
+
"[env.production]",
|
|
6223
|
+
`name = "topolo-${slug}-production"`,
|
|
6224
|
+
`account_id = "${CLOUDFLARE_ACCOUNT_ID}"`,
|
|
6225
|
+
"workers_dev = false",
|
|
6226
|
+
"",
|
|
6227
|
+
"[env.production.vars]",
|
|
6228
|
+
`SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6229
|
+
`VITE_TOPOLO_SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6230
|
+
"",
|
|
6231
|
+
"[[env.production.routes]]",
|
|
6232
|
+
`pattern = "${host}"`,
|
|
6233
|
+
"custom_domain = true",
|
|
6234
|
+
"",
|
|
6235
|
+
"[env.production.assets]",
|
|
6236
|
+
'directory = "./dist"',
|
|
6237
|
+
'binding = "ASSETS"',
|
|
6238
|
+
'not_found_handling = "single-page-application"',
|
|
6239
|
+
'run_worker_first = ["/api/*"]',
|
|
6240
|
+
"",
|
|
6241
|
+
"[[env.production.services]]",
|
|
6242
|
+
'binding = "API"',
|
|
6243
|
+
`service = "topolo-${slug}-api-production"`,
|
|
6244
|
+
""
|
|
6245
|
+
].join("\n");
|
|
6246
|
+
}
|
|
6247
|
+
function platformApiWranglerToml(application, resources, profile) {
|
|
6248
|
+
const slug = toSlug(application.id);
|
|
6249
|
+
const resource = resourceConfig(application, profile);
|
|
6250
|
+
const lines = [
|
|
6251
|
+
`name = "topolo-${slug}-api"`,
|
|
6252
|
+
'main = "src/worker.ts"',
|
|
6253
|
+
`compatibility_date = "${CLOUDFLARE_COMPATIBILITY_DATE}"`,
|
|
6254
|
+
'compatibility_flags = ["nodejs_compat"]',
|
|
6255
|
+
`account_id = "${CLOUDFLARE_ACCOUNT_ID}"`,
|
|
6256
|
+
"workers_dev = true",
|
|
6257
|
+
"",
|
|
6258
|
+
"[observability]",
|
|
6259
|
+
"enabled = true",
|
|
6260
|
+
"",
|
|
6261
|
+
"[vars]",
|
|
6262
|
+
'AUTH_BASE_URL = "https://auth.topolo.app"',
|
|
6263
|
+
'NEXUS_GATEWAY_URL = "https://nexus-api.topolo.app"',
|
|
6264
|
+
`NEXUS_APP_ID = "${slug}"`,
|
|
6265
|
+
`SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6266
|
+
`VITE_TOPOLO_SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6267
|
+
""
|
|
6268
|
+
];
|
|
6269
|
+
appendResourceWranglerBlocks(lines, resources, resource, "production");
|
|
6270
|
+
lines.push(
|
|
6271
|
+
"[env.staging]",
|
|
6272
|
+
`name = "topolo-${slug}-api-staging"`,
|
|
6273
|
+
`account_id = "${STAGING_CLOUDFLARE_ACCOUNT_ID}"`,
|
|
6274
|
+
"workers_dev = true",
|
|
6275
|
+
"",
|
|
6276
|
+
"[env.staging.vars]",
|
|
6277
|
+
'AUTH_BASE_URL = "https://auth.stg.topolo.us"',
|
|
6278
|
+
'NEXUS_GATEWAY_URL = "https://nexus-api.stg.topolo.us"',
|
|
6279
|
+
`NEXUS_APP_ID = "${slug}"`,
|
|
6280
|
+
`SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6281
|
+
`VITE_TOPOLO_SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6282
|
+
""
|
|
6283
|
+
);
|
|
6284
|
+
appendResourceWranglerBlocks(lines, resources, resource, "staging");
|
|
6285
|
+
lines.push(
|
|
6286
|
+
"[env.production]",
|
|
6287
|
+
`name = "topolo-${slug}-api-production"`,
|
|
6288
|
+
`account_id = "${CLOUDFLARE_ACCOUNT_ID}"`,
|
|
6289
|
+
"workers_dev = false",
|
|
6290
|
+
"",
|
|
6291
|
+
"[env.production.vars]",
|
|
6292
|
+
'AUTH_BASE_URL = "https://auth.topolo.app"',
|
|
6293
|
+
'NEXUS_GATEWAY_URL = "https://nexus-api.topolo.app"',
|
|
6294
|
+
`NEXUS_APP_ID = "${slug}"`,
|
|
6295
|
+
`SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6296
|
+
`VITE_TOPOLO_SERVICE_ID = "${application.serviceId ?? ""}"`,
|
|
6297
|
+
""
|
|
6298
|
+
);
|
|
6299
|
+
appendResourceWranglerBlocks(lines, resources, resource, "production-env");
|
|
6300
|
+
return lines.join("\n");
|
|
6301
|
+
}
|
|
6302
|
+
function appendResourceWranglerBlocks(lines, resources, resource, environment) {
|
|
6303
|
+
const prefix = environment === "staging" ? "env.staging." : environment === "production-env" ? "env.production." : "";
|
|
6304
|
+
const envName = environment === "staging" ? "Staging" : "Production";
|
|
6305
|
+
if (resources.d1) {
|
|
6306
|
+
lines.push(
|
|
6307
|
+
`[[${prefix}d1_databases]]`,
|
|
6308
|
+
`binding = "${resource.d1Binding}"`,
|
|
6309
|
+
`database_name = "${environment === "staging" ? resource.d1StagingName : resource.d1ProductionName}"`,
|
|
6310
|
+
'database_id = "provision-after-scaffold"',
|
|
6311
|
+
'migrations_dir = "migrations"',
|
|
6312
|
+
""
|
|
6313
|
+
);
|
|
6314
|
+
}
|
|
6315
|
+
if (resources.r2) {
|
|
6316
|
+
lines.push(
|
|
6317
|
+
`[[${prefix}r2_buckets]]`,
|
|
6318
|
+
`binding = "${resource.r2Binding}"`,
|
|
6319
|
+
`bucket_name = "${environment === "staging" ? resource.r2StagingName : resource.r2ProductionName}"`,
|
|
6320
|
+
""
|
|
6321
|
+
);
|
|
6322
|
+
}
|
|
6323
|
+
if (resources.queue) {
|
|
6324
|
+
lines.push(
|
|
6325
|
+
`[[${prefix}queues.producers]]`,
|
|
6326
|
+
`binding = "${resource.queueBinding}"`,
|
|
6327
|
+
`queue = "${environment === "staging" ? resource.queueStagingName : resource.queueProductionName}"`,
|
|
6328
|
+
"",
|
|
6329
|
+
`[[${prefix}queues.consumers]]`,
|
|
6330
|
+
`queue = "${environment === "staging" ? resource.queueStagingName : resource.queueProductionName}"`,
|
|
6331
|
+
""
|
|
6332
|
+
);
|
|
6333
|
+
}
|
|
6334
|
+
if (resources.workflow) {
|
|
6335
|
+
lines.push(
|
|
6336
|
+
`[[${prefix}workflows]]`,
|
|
6337
|
+
`binding = "${resource.workflowBinding}"`,
|
|
6338
|
+
`name = "${environment === "staging" ? resource.workflowStagingName : resource.workflowProductionName}"`,
|
|
6339
|
+
`class_name = "${resource.workflowClassName}"`,
|
|
6340
|
+
""
|
|
6341
|
+
);
|
|
6342
|
+
}
|
|
6343
|
+
if (resources.containerProcessing) {
|
|
6344
|
+
lines.push(`# ${envName} container metadata is declared in topolo.app.json and topolo.cloudcontrol.json.`);
|
|
6345
|
+
lines.push("");
|
|
6346
|
+
}
|
|
6347
|
+
}
|
|
5630
6348
|
function wranglerToml(application, target, resources, profile) {
|
|
5631
6349
|
const slug = toSlug(application.id);
|
|
5632
6350
|
const workerName = target === "platform" ? `topolo-${slug}` : application.packageName;
|
|
@@ -5668,6 +6386,7 @@ function wranglerToml(application, target, resources, profile) {
|
|
|
5668
6386
|
"",
|
|
5669
6387
|
"[vars]",
|
|
5670
6388
|
'AUTH_BASE_URL = "https://auth.topolo.app"',
|
|
6389
|
+
'NEXUS_GATEWAY_URL = "https://nexus-api.topolo.app"',
|
|
5671
6390
|
runtimeIdentityVar,
|
|
5672
6391
|
""
|
|
5673
6392
|
);
|
|
@@ -5722,6 +6441,7 @@ function wranglerToml(application, target, resources, profile) {
|
|
|
5722
6441
|
"",
|
|
5723
6442
|
"[env.staging.vars]",
|
|
5724
6443
|
'AUTH_BASE_URL = "https://auth.stg.topolo.us"',
|
|
6444
|
+
'NEXUS_GATEWAY_URL = "https://nexus-api.stg.topolo.us"',
|
|
5725
6445
|
runtimeIdentityVar,
|
|
5726
6446
|
""
|
|
5727
6447
|
);
|
|
@@ -5776,8 +6496,8 @@ function platformWorkerTs(application, options) {
|
|
|
5776
6496
|
const resource = resourceConfig(application, options.profile);
|
|
5777
6497
|
const envBindings = [
|
|
5778
6498
|
" AUTH_BASE_URL?: string;",
|
|
6499
|
+
" NEXUS_GATEWAY_URL?: string;",
|
|
5779
6500
|
" SERVICE_ID?: string;",
|
|
5780
|
-
" TOPOLO_SERVICE_API_KEY?: string;",
|
|
5781
6501
|
...options.resources.d1 ? [` ${resource.d1Binding}?: unknown;`] : [],
|
|
5782
6502
|
...options.resources.r2 ? [` ${resource.r2Binding}?: unknown;`] : [],
|
|
5783
6503
|
...options.resources.queue ? [` ${resource.queueBinding}?: { send(message: unknown): Promise<void> };`] : [],
|
|
@@ -5810,8 +6530,9 @@ function platformWorkerTs(application, options) {
|
|
|
5810
6530
|
" }, { status: 200 });"
|
|
5811
6531
|
];
|
|
5812
6532
|
return [
|
|
5813
|
-
"import {
|
|
5814
|
-
"import {
|
|
6533
|
+
"import { Hono } from 'hono';",
|
|
6534
|
+
"import { createTopoloWidgetResponse, type TopoloWidgetDraft } from '@topolo/sdk';",
|
|
6535
|
+
"import { createTopoloWorkerRuntime, type TopoloRuntimeContext } from '@topolo-io/worker-runtime';",
|
|
5815
6536
|
"import { SCAFFOLD_APP_ID, SCAFFOLD_APP_NAME, SCAFFOLD_SERVICE_SLUG, resolveRuntimeServiceId } from './service-identity';",
|
|
5816
6537
|
...options.resources.workflow ? ["import { WorkflowEntrypoint, type WorkflowEvent, type WorkflowStep } from 'cloudflare:workers';"] : [],
|
|
5817
6538
|
"",
|
|
@@ -5819,18 +6540,8 @@ function platformWorkerTs(application, options) {
|
|
|
5819
6540
|
...envBindings,
|
|
5820
6541
|
"}",
|
|
5821
6542
|
"",
|
|
5822
|
-
"
|
|
5823
|
-
"
|
|
5824
|
-
"// is installed. Replace the quick-actions placeholder with org-scoped",
|
|
5825
|
-
"// stats once your data model is ready: ctx.user / ctx.orgId / ctx.orgSlug",
|
|
5826
|
-
"// / ctx.isPlatformAdmin / ctx.contextType / ctx.householdId are all",
|
|
5827
|
-
"// pre-resolved. Builder exceptions degrade to empty widgets, not 500s.",
|
|
5828
|
-
"const widgetHandler = createWidgetHandler<Env>({",
|
|
5829
|
-
" serviceId: SCAFFOLD_SERVICE_SLUG,",
|
|
5830
|
-
` serviceName: '${escapeSingleQuoted(serviceName)}',`,
|
|
5831
|
-
" authBaseUrl: (env) => env.AUTH_BASE_URL,",
|
|
5832
|
-
" serviceApiKey: (env) => env.TOPOLO_SERVICE_API_KEY,",
|
|
5833
|
-
" build: () => [",
|
|
6543
|
+
"function buildWidgets(): TopoloWidgetDraft[] {",
|
|
6544
|
+
" return [",
|
|
5834
6545
|
" {",
|
|
5835
6546
|
" type: 'quick-actions',",
|
|
5836
6547
|
" actions: [",
|
|
@@ -5838,18 +6549,25 @@ function platformWorkerTs(application, options) {
|
|
|
5838
6549
|
" { id: 'view-health', label: 'View health', link: '/api/health' },",
|
|
5839
6550
|
" ],",
|
|
5840
6551
|
" },",
|
|
5841
|
-
" ]
|
|
5842
|
-
"}
|
|
6552
|
+
" ];",
|
|
6553
|
+
"}",
|
|
5843
6554
|
"",
|
|
5844
6555
|
"const runtime = createTopoloWorkerRuntime<Env>({",
|
|
5845
6556
|
" appName: SCAFFOLD_APP_NAME,",
|
|
5846
6557
|
" serviceSlug: SCAFFOLD_SERVICE_SLUG,",
|
|
5847
6558
|
" resolveServiceId: (env) => resolveRuntimeServiceId(env),",
|
|
5848
6559
|
" authBaseUrl: (env) => env.AUTH_BASE_URL,",
|
|
5849
|
-
"
|
|
6560
|
+
" usageMonitoring: {",
|
|
6561
|
+
" appId: SCAFFOLD_APP_ID,",
|
|
6562
|
+
" nexusGatewayUrl: (env) => env.NEXUS_GATEWAY_URL,",
|
|
6563
|
+
" },",
|
|
5850
6564
|
"});",
|
|
5851
6565
|
"",
|
|
5852
|
-
"
|
|
6566
|
+
"async function handleRequest(",
|
|
6567
|
+
" _request: Request,",
|
|
6568
|
+
" env: Env,",
|
|
6569
|
+
" rt: TopoloRuntimeContext<Env>,",
|
|
6570
|
+
"): Promise<Response> {",
|
|
5853
6571
|
" const url = rt.url;",
|
|
5854
6572
|
"",
|
|
5855
6573
|
" let serviceId: string;",
|
|
@@ -5872,9 +6590,15 @@ function platformWorkerTs(application, options) {
|
|
|
5872
6590
|
" }, { status: 200 });",
|
|
5873
6591
|
" }",
|
|
5874
6592
|
"",
|
|
5875
|
-
"
|
|
5876
|
-
"
|
|
5877
|
-
"
|
|
6593
|
+
" if (url.pathname === '/api/widget') {",
|
|
6594
|
+
" const auth = await rt.verifyAuth({ serviceId });",
|
|
6595
|
+
" if (!auth.ok) return rt.authError(auth);",
|
|
6596
|
+
" return rt.json(createTopoloWidgetResponse({",
|
|
6597
|
+
" serviceId,",
|
|
6598
|
+
" serviceName: SCAFFOLD_APP_NAME,",
|
|
6599
|
+
" widgets: buildWidgets(),",
|
|
6600
|
+
" }), { status: 200, headers: { 'Cache-Control': 'public, max-age=15' } });",
|
|
6601
|
+
" }",
|
|
5878
6602
|
"",
|
|
5879
6603
|
" const auth = await rt.verifyAuth({ serviceId });",
|
|
5880
6604
|
"",
|
|
@@ -5887,10 +6611,21 @@ function platformWorkerTs(application, options) {
|
|
|
5887
6611
|
" }",
|
|
5888
6612
|
"",
|
|
5889
6613
|
" return rt.notFound();",
|
|
6614
|
+
"}",
|
|
6615
|
+
"",
|
|
6616
|
+
"const api = new Hono<{ Bindings: Env & { __rt?: TopoloRuntimeContext<Env> } }>();",
|
|
6617
|
+
"api.all('*', (c) => {",
|
|
6618
|
+
" const rt = c.env.__rt;",
|
|
6619
|
+
" if (!rt) return Response.json({ error: 'runtime_context_unavailable' }, { status: 500 });",
|
|
6620
|
+
" return handleRequest(c.req.raw, c.env, rt);",
|
|
5890
6621
|
"});",
|
|
5891
6622
|
"",
|
|
5892
6623
|
"export default {",
|
|
5893
|
-
" fetch:
|
|
6624
|
+
" fetch: runtime.worker((request, env, ctx, rt) => {",
|
|
6625
|
+
" const bindings = env as Env & { __rt?: TopoloRuntimeContext<Env> };",
|
|
6626
|
+
" bindings.__rt = rt;",
|
|
6627
|
+
" return api.fetch(request, bindings, ctx as ExecutionContext);",
|
|
6628
|
+
" }),",
|
|
5894
6629
|
"};",
|
|
5895
6630
|
"",
|
|
5896
6631
|
"function errorMessage(error: unknown): string {",
|
|
@@ -5905,7 +6640,7 @@ function developerWorkerTs(application) {
|
|
|
5905
6640
|
const serviceId = application.serviceId ?? application.id;
|
|
5906
6641
|
const serviceName = application.name || "Topolo App";
|
|
5907
6642
|
return [
|
|
5908
|
-
"import {
|
|
6643
|
+
"import { createTopoloWidgetResponse, type TopoloWidgetDraft } from '@topolo/sdk';",
|
|
5909
6644
|
"",
|
|
5910
6645
|
"export interface Env {",
|
|
5911
6646
|
" AUTH_BASE_URL?: string;",
|
|
@@ -5916,17 +6651,8 @@ function developerWorkerTs(application) {
|
|
|
5916
6651
|
`const DEFAULT_SERVICE_ID = '${serviceId}';`,
|
|
5917
6652
|
`const SERVICE_NAME = '${escapeSingleQuoted(serviceName)}';`,
|
|
5918
6653
|
"",
|
|
5919
|
-
"
|
|
5920
|
-
"
|
|
5921
|
-
"// is installed. Replace the quick-actions placeholder with org-scoped",
|
|
5922
|
-
"// stats once your data model is ready: ctx.user / ctx.orgId / ctx.orgSlug",
|
|
5923
|
-
"// / ctx.isPlatformAdmin / ctx.contextType / ctx.householdId are all",
|
|
5924
|
-
"// pre-resolved. Builder exceptions degrade to empty widgets, not 500s.",
|
|
5925
|
-
"const widgetHandler = createWidgetHandler<Env>({",
|
|
5926
|
-
" serviceId: DEFAULT_SERVICE_ID,",
|
|
5927
|
-
" serviceName: SERVICE_NAME,",
|
|
5928
|
-
" authBaseUrl: (env) => env.AUTH_BASE_URL,",
|
|
5929
|
-
" build: () => [",
|
|
6654
|
+
"function buildWidgets(): TopoloWidgetDraft[] {",
|
|
6655
|
+
" return [",
|
|
5930
6656
|
" {",
|
|
5931
6657
|
" type: 'quick-actions',",
|
|
5932
6658
|
" actions: [",
|
|
@@ -5934,8 +6660,8 @@ function developerWorkerTs(application) {
|
|
|
5934
6660
|
" { id: 'view-health', label: 'View health', link: '/api/health' },",
|
|
5935
6661
|
" ],",
|
|
5936
6662
|
" },",
|
|
5937
|
-
" ]
|
|
5938
|
-
"}
|
|
6663
|
+
" ];",
|
|
6664
|
+
"}",
|
|
5939
6665
|
"",
|
|
5940
6666
|
"export default {",
|
|
5941
6667
|
" async fetch(request: Request, env: Env): Promise<Response> {",
|
|
@@ -5945,8 +6671,15 @@ function developerWorkerTs(application) {
|
|
|
5945
6671
|
" return json({ ok: true, service: env.SERVICE_ID ?? DEFAULT_SERVICE_ID }, { status: 200 }, request);",
|
|
5946
6672
|
" }",
|
|
5947
6673
|
"",
|
|
5948
|
-
"
|
|
5949
|
-
"
|
|
6674
|
+
" if (url.pathname === '/api/widget') {",
|
|
6675
|
+
" const auth = await verifyTopoloRequest(request, env);",
|
|
6676
|
+
" if (!auth.ok) return json({ error: auth.error }, { status: auth.status }, request);",
|
|
6677
|
+
" return json(createTopoloWidgetResponse({",
|
|
6678
|
+
" serviceId: env.SERVICE_ID ?? DEFAULT_SERVICE_ID,",
|
|
6679
|
+
" serviceName: SERVICE_NAME,",
|
|
6680
|
+
" widgets: buildWidgets(),",
|
|
6681
|
+
" }), { status: 200, headers: { 'Cache-Control': 'public, max-age=15' } }, request);",
|
|
6682
|
+
" }",
|
|
5950
6683
|
"",
|
|
5951
6684
|
" const auth = await verifyTopoloRequest(request, env);",
|
|
5952
6685
|
" if (!auth.ok) {",
|
|
@@ -6002,6 +6735,126 @@ function developerWorkerTs(application) {
|
|
|
6002
6735
|
""
|
|
6003
6736
|
].join("\n");
|
|
6004
6737
|
}
|
|
6738
|
+
function topoloAppManifestJson(application, options) {
|
|
6739
|
+
const slug = toSlug(application.id);
|
|
6740
|
+
const resource = resourceConfig(application, options.profile);
|
|
6741
|
+
const targets = {};
|
|
6742
|
+
if (options.api) {
|
|
6743
|
+
const bindings = {};
|
|
6744
|
+
if (options.resources.d1) {
|
|
6745
|
+
bindings.d1 = [
|
|
6746
|
+
{
|
|
6747
|
+
binding: resource.d1Binding,
|
|
6748
|
+
staging: {
|
|
6749
|
+
databaseName: resource.d1StagingName,
|
|
6750
|
+
databaseId: "provision-after-scaffold"
|
|
6751
|
+
},
|
|
6752
|
+
production: {
|
|
6753
|
+
databaseName: resource.d1ProductionName,
|
|
6754
|
+
databaseId: "provision-after-scaffold"
|
|
6755
|
+
},
|
|
6756
|
+
migrationsDir: "migrations"
|
|
6757
|
+
}
|
|
6758
|
+
];
|
|
6759
|
+
}
|
|
6760
|
+
if (options.resources.r2) {
|
|
6761
|
+
bindings.r2 = [
|
|
6762
|
+
{
|
|
6763
|
+
binding: resource.r2Binding,
|
|
6764
|
+
staging: { bucketName: resource.r2StagingName },
|
|
6765
|
+
production: { bucketName: resource.r2ProductionName }
|
|
6766
|
+
}
|
|
6767
|
+
];
|
|
6768
|
+
}
|
|
6769
|
+
if (options.resources.queue) {
|
|
6770
|
+
bindings.queues = [
|
|
6771
|
+
{
|
|
6772
|
+
binding: resource.queueBinding,
|
|
6773
|
+
staging: { queueName: resource.queueStagingName },
|
|
6774
|
+
production: { queueName: resource.queueProductionName },
|
|
6775
|
+
consumer: true
|
|
6776
|
+
}
|
|
6777
|
+
];
|
|
6778
|
+
}
|
|
6779
|
+
if (options.resources.workflow) {
|
|
6780
|
+
bindings.workflows = [
|
|
6781
|
+
{
|
|
6782
|
+
binding: resource.workflowBinding,
|
|
6783
|
+
className: resource.workflowClassName,
|
|
6784
|
+
staging: { name: resource.workflowStagingName },
|
|
6785
|
+
production: { name: resource.workflowProductionName }
|
|
6786
|
+
}
|
|
6787
|
+
];
|
|
6788
|
+
}
|
|
6789
|
+
targets.api = {
|
|
6790
|
+
kind: "worker",
|
|
6791
|
+
dir: "apps/api",
|
|
6792
|
+
wranglerName: `topolo-${slug}-api`,
|
|
6793
|
+
main: "src/worker.ts",
|
|
6794
|
+
compatibilityFlags: ["nodejs_compat"],
|
|
6795
|
+
healthcheckPath: "/api/health",
|
|
6796
|
+
vars: {
|
|
6797
|
+
AUTH_BASE_URL: {
|
|
6798
|
+
staging: "https://auth.stg.topolo.us",
|
|
6799
|
+
production: "https://auth.topolo.app"
|
|
6800
|
+
}
|
|
6801
|
+
},
|
|
6802
|
+
...Object.keys(bindings).length ? { bindings } : {}
|
|
6803
|
+
};
|
|
6804
|
+
}
|
|
6805
|
+
targets.web = {
|
|
6806
|
+
kind: "worker",
|
|
6807
|
+
dir: "apps/web",
|
|
6808
|
+
wranglerName: `topolo-${slug}`,
|
|
6809
|
+
subdomain: slug,
|
|
6810
|
+
main: "src/worker.ts",
|
|
6811
|
+
workersDev: false,
|
|
6812
|
+
assets: {
|
|
6813
|
+
directory: "./dist",
|
|
6814
|
+
binding: "ASSETS",
|
|
6815
|
+
notFoundHandling: "single-page-application",
|
|
6816
|
+
runWorkerFirst: ["/api/*"]
|
|
6817
|
+
},
|
|
6818
|
+
compatibilityFlags: ["nodejs_compat"],
|
|
6819
|
+
buildCommand: {
|
|
6820
|
+
staging: "cd ../.. && DEPLOY_ENVIRONMENT=staging VITE_TOPOLO_AUTH_URL=https://auth.stg.topolo.us npm run build",
|
|
6821
|
+
production: "cd ../.. && DEPLOY_ENVIRONMENT=production VITE_TOPOLO_AUTH_URL=https://auth.topolo.app npm run build"
|
|
6822
|
+
},
|
|
6823
|
+
healthcheckPath: options.api ? "/api/health" : "/",
|
|
6824
|
+
...options.api ? {
|
|
6825
|
+
bindings: {
|
|
6826
|
+
services: [
|
|
6827
|
+
{
|
|
6828
|
+
binding: "API",
|
|
6829
|
+
service: {
|
|
6830
|
+
staging: `topolo-${slug}-api-staging`,
|
|
6831
|
+
production: `topolo-${slug}-api-production`
|
|
6832
|
+
}
|
|
6833
|
+
}
|
|
6834
|
+
]
|
|
6835
|
+
}
|
|
6836
|
+
} : {}
|
|
6837
|
+
};
|
|
6838
|
+
return `${json({
|
|
6839
|
+
$schema: "./../../topolo-platform/tooling/app-manifest-schema.json",
|
|
6840
|
+
name: `topolo-${slug}`,
|
|
6841
|
+
serviceId: application.serviceId,
|
|
6842
|
+
primaryTarget: "web",
|
|
6843
|
+
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE,
|
|
6844
|
+
environments: {
|
|
6845
|
+
staging: {
|
|
6846
|
+
accountId: STAGING_CLOUDFLARE_ACCOUNT_ID,
|
|
6847
|
+
domain: "stg.topolo.us"
|
|
6848
|
+
},
|
|
6849
|
+
production: {
|
|
6850
|
+
accountId: CLOUDFLARE_ACCOUNT_ID,
|
|
6851
|
+
domain: "topolo.app"
|
|
6852
|
+
}
|
|
6853
|
+
},
|
|
6854
|
+
targets
|
|
6855
|
+
})}
|
|
6856
|
+
`;
|
|
6857
|
+
}
|
|
6005
6858
|
function cloudcontrolJson(application, options) {
|
|
6006
6859
|
const slug = toSlug(application.id);
|
|
6007
6860
|
const appPath = firstPartyAppPath(application.appDir, options.audience);
|
|
@@ -6110,16 +6963,16 @@ function cloudcontrolJson(application, options) {
|
|
|
6110
6963
|
{
|
|
6111
6964
|
kind: "worker",
|
|
6112
6965
|
environment: "production",
|
|
6113
|
-
target_name: `topolo-${slug}`,
|
|
6966
|
+
target_name: `topolo-${slug}-api-production`,
|
|
6114
6967
|
cloudflare_account_id: CLOUDFLARE_ACCOUNT_ID,
|
|
6115
|
-
config_path: "wrangler.toml",
|
|
6116
|
-
|
|
6117
|
-
|
|
6968
|
+
config_path: "apps/api/wrangler.toml",
|
|
6969
|
+
workdir: "apps/api",
|
|
6970
|
+
build_command: null,
|
|
6971
|
+
output_dir: null,
|
|
6118
6972
|
production_branch: "main",
|
|
6119
6973
|
healthcheck_path: "/api/health",
|
|
6120
|
-
domains: [
|
|
6121
|
-
routes: [
|
|
6122
|
-
api_url: application.productionUrl,
|
|
6974
|
+
domains: [],
|
|
6975
|
+
routes: [],
|
|
6123
6976
|
service_slug: serviceSlug
|
|
6124
6977
|
},
|
|
6125
6978
|
{
|
|
@@ -6127,36 +6980,73 @@ function cloudcontrolJson(application, options) {
|
|
|
6127
6980
|
environment: "staging",
|
|
6128
6981
|
target_name: `topolo-${slug}-staging`,
|
|
6129
6982
|
cloudflare_account_id: STAGING_CLOUDFLARE_ACCOUNT_ID,
|
|
6130
|
-
config_path: "wrangler.toml",
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6983
|
+
config_path: "apps/web/wrangler.toml",
|
|
6984
|
+
workdir: "apps/web",
|
|
6985
|
+
build_command: "DEPLOY_ENVIRONMENT=staging VITE_TOPOLO_AUTH_URL=https://auth.stg.topolo.us npm run build",
|
|
6986
|
+
output_dir: null,
|
|
6987
|
+
production_branch: "staging",
|
|
6134
6988
|
healthcheck_path: "/api/health",
|
|
6135
6989
|
domains: [stagingHost],
|
|
6136
6990
|
routes: [stagingHost],
|
|
6137
6991
|
api_url: `https://${stagingHost}`,
|
|
6992
|
+
service_slug: serviceSlug,
|
|
6993
|
+
sdk_service_id: application.id,
|
|
6994
|
+
agent_callable: true
|
|
6995
|
+
},
|
|
6996
|
+
{
|
|
6997
|
+
kind: "worker",
|
|
6998
|
+
environment: "staging",
|
|
6999
|
+
target_name: `topolo-${slug}-api-staging`,
|
|
7000
|
+
cloudflare_account_id: STAGING_CLOUDFLARE_ACCOUNT_ID,
|
|
7001
|
+
config_path: "apps/api/wrangler.toml",
|
|
7002
|
+
workdir: "apps/api",
|
|
7003
|
+
build_command: null,
|
|
7004
|
+
output_dir: null,
|
|
7005
|
+
production_branch: "staging",
|
|
7006
|
+
healthcheck_path: "/api/health",
|
|
7007
|
+
domains: [],
|
|
7008
|
+
routes: [],
|
|
6138
7009
|
service_slug: serviceSlug
|
|
7010
|
+
},
|
|
7011
|
+
{
|
|
7012
|
+
kind: "worker",
|
|
7013
|
+
environment: "production",
|
|
7014
|
+
target_name: `topolo-${slug}-production`,
|
|
7015
|
+
cloudflare_account_id: CLOUDFLARE_ACCOUNT_ID,
|
|
7016
|
+
config_path: "apps/web/wrangler.toml",
|
|
7017
|
+
workdir: "apps/web",
|
|
7018
|
+
build_command: "DEPLOY_ENVIRONMENT=production VITE_TOPOLO_AUTH_URL=https://auth.topolo.app npm run build",
|
|
7019
|
+
output_dir: null,
|
|
7020
|
+
production_branch: "main",
|
|
7021
|
+
healthcheck_path: "/api/health",
|
|
7022
|
+
domains: [host],
|
|
7023
|
+
routes: [host],
|
|
7024
|
+
api_url: application.productionUrl,
|
|
7025
|
+
service_slug: serviceSlug,
|
|
7026
|
+
sdk_service_id: application.id,
|
|
7027
|
+
agent_callable: true
|
|
6139
7028
|
}
|
|
6140
7029
|
] : [
|
|
6141
7030
|
{
|
|
6142
|
-
kind: "
|
|
7031
|
+
kind: "worker",
|
|
6143
7032
|
environment: "production",
|
|
6144
7033
|
target_name: `topolo-${slug}`,
|
|
6145
7034
|
cloudflare_account_id: CLOUDFLARE_ACCOUNT_ID,
|
|
6146
|
-
config_path:
|
|
7035
|
+
config_path: "wrangler.toml",
|
|
6147
7036
|
build_command: "npm run build",
|
|
6148
7037
|
output_dir: "dist",
|
|
6149
7038
|
production_branch: "main",
|
|
6150
|
-
healthcheck_path:
|
|
7039
|
+
healthcheck_path: "/",
|
|
6151
7040
|
domains: [host],
|
|
6152
7041
|
routes: [host],
|
|
6153
|
-
api_url:
|
|
7042
|
+
api_url: application.productionUrl,
|
|
7043
|
+
agent_callable: false
|
|
6154
7044
|
}
|
|
6155
7045
|
];
|
|
6156
7046
|
return `${json({
|
|
6157
7047
|
name: `topolo-${slug}`,
|
|
6158
7048
|
description: `Canonical documentation for ${toTitle(application.name)} lives in Apps/system/TopoloDocs.`,
|
|
6159
|
-
deploy_method:
|
|
7049
|
+
deploy_method: "wrangler",
|
|
6160
7050
|
ci_provider: "github_actions",
|
|
6161
7051
|
repo_identity: {
|
|
6162
7052
|
provider: "github",
|
|
@@ -6236,7 +7126,7 @@ function systemJson(application, options) {
|
|
|
6236
7126
|
visibility: "internal",
|
|
6237
7127
|
api_contract: {
|
|
6238
7128
|
type: options.api ? "curated" : "none",
|
|
6239
|
-
source: options.api ? `${appPath}/src/worker.ts` : `${appPath}/src/App.tsx`,
|
|
7129
|
+
source: options.api ? `${appPath}/apps/api/src/worker.ts` : `${appPath}/apps/web/src/App.tsx`,
|
|
6240
7130
|
notes: apiNotes
|
|
6241
7131
|
},
|
|
6242
7132
|
primary_hosts: application.productionUrl ? [application.productionUrl] : [],
|
|
@@ -6325,17 +7215,19 @@ function internalDocs(application, options) {
|
|
|
6325
7215
|
"",
|
|
6326
7216
|
"## Architecture",
|
|
6327
7217
|
"",
|
|
6328
|
-
"The generated browser surface uses `@topolo-io/ui-kit` for the shared landing page, shared login page, auth callback state, and shared signed shell. `vite.config.ts` includes the standard React plugin plus React runtime dedupe so linked Topolo packages resolve a single browser React runtime.",
|
|
6329
|
-
options.api ? `The generated app
|
|
7218
|
+
"The generated browser surface in `apps/web` uses `@topolo-io/ui-kit` for the shared landing page, shared login page, auth callback state, and shared signed shell. `apps/web/vite.config.ts` includes the standard React plugin plus React runtime dedupe so linked Topolo packages resolve a single browser React runtime.",
|
|
7219
|
+
options.api ? `The generated app keeps browser service identity in \`${appPath}/apps/web/src/service-identity.ts\` and API runtime service identity in \`${appPath}/apps/api/src/service-identity.ts\`. Runtime code reads the provisioned Auth service id from the API Worker \`SERVICE_ID\` binding and exposes it to the browser through the same-origin service-identity route forwarded by the web Worker.` : `The generated app centralizes browser service identity in \`${appPath}/apps/web/src/service-identity.ts\` and reads Auth identity from the app runtime instead of calling Auth for slug lookups.`,
|
|
6330
7220
|
"",
|
|
6331
7221
|
"## Runtime Surfaces",
|
|
6332
7222
|
"",
|
|
6333
|
-
`- \`${appPath}/src/App.tsx\``,
|
|
6334
|
-
`- \`${appPath}/src/service-identity.ts\``,
|
|
7223
|
+
`- \`${appPath}/apps/web/src/App.tsx\``,
|
|
7224
|
+
`- \`${appPath}/apps/web/src/service-identity.ts\``,
|
|
7225
|
+
`- \`${appPath}/apps/web/wrangler.toml\``,
|
|
6335
7226
|
"- public landing route: `/`",
|
|
6336
7227
|
"- public sign-in route: `/login`",
|
|
6337
7228
|
"- auth callback route: `/auth/callback`",
|
|
6338
|
-
...options.api ? [`- \`${appPath}/src/worker.ts\``] : [],
|
|
7229
|
+
...options.api ? [`- \`${appPath}/apps/api/src/worker.ts\``, `- \`${appPath}/apps/api/wrangler.toml\``] : [],
|
|
7230
|
+
`- \`${appPath}/topolo.app.json\``,
|
|
6339
7231
|
`- \`${appPath}/topolo.cloudcontrol.json\``,
|
|
6340
7232
|
...options.api && application.serviceId ? [`- \`Apps/system/TopoloAuth/catalog/service-manifests/${application.serviceId}.json\``] : [],
|
|
6341
7233
|
"",
|
|
@@ -6494,6 +7386,12 @@ function serviceManifestJson(application, options) {
|
|
|
6494
7386
|
name: "workspace:write",
|
|
6495
7387
|
description: `Manage ${title} ${resourceLabel} data`,
|
|
6496
7388
|
resourcePattern: null
|
|
7389
|
+
},
|
|
7390
|
+
{
|
|
7391
|
+
id: `perm_${permissionPrefix}_usage_write`,
|
|
7392
|
+
name: "usage:write",
|
|
7393
|
+
description: `Record Nexus usage events for ${title}`,
|
|
7394
|
+
resourcePattern: null
|
|
6497
7395
|
}
|
|
6498
7396
|
],
|
|
6499
7397
|
apiKeyScopes: [
|
|
@@ -6508,6 +7406,12 @@ function serviceManifestJson(application, options) {
|
|
|
6508
7406
|
name: "workspace.write",
|
|
6509
7407
|
description: `Manage ${title} ${resourceLabel} data`,
|
|
6510
7408
|
resourcePattern: null
|
|
7409
|
+
},
|
|
7410
|
+
{
|
|
7411
|
+
id: `aks_${permissionPrefix}_usage_write`,
|
|
7412
|
+
name: "usage.write",
|
|
7413
|
+
description: `Record Nexus usage events for ${title}`,
|
|
7414
|
+
resourcePattern: null
|
|
6511
7415
|
}
|
|
6512
7416
|
],
|
|
6513
7417
|
roleBundles: {
|
|
@@ -6948,6 +7852,15 @@ async function applyProvisionedServiceId(manifestPath, serviceId) {
|
|
|
6948
7852
|
// src/commands/apps.ts
|
|
6949
7853
|
import { join as join3 } from "path";
|
|
6950
7854
|
var APPLICATION_IDS = Object.keys(APPLICATIONS).sort();
|
|
7855
|
+
var CLOUDCONTROL_LOCAL_APPLICATION = {
|
|
7856
|
+
id: "cloudcontrol",
|
|
7857
|
+
appDir: "TopoloCloudControl",
|
|
7858
|
+
name: "topolo-cloudcontrol",
|
|
7859
|
+
packageName: "topolo-cloudcontrol",
|
|
7860
|
+
productionUrl: null,
|
|
7861
|
+
services: [],
|
|
7862
|
+
deployTargets: []
|
|
7863
|
+
};
|
|
6951
7864
|
function registerAppsCommand(program2) {
|
|
6952
7865
|
const apps = program2.command("apps").description("List every Topolo platform application known to the SDK catalog").option("--json", "Output JSON", true).option("--no-json", "Output human-readable table").action((opts) => {
|
|
6953
7866
|
const mode = resolveOutputMode(opts.json);
|
|
@@ -6958,7 +7871,7 @@ function registerAppsCommand(program2) {
|
|
|
6958
7871
|
fail(err, mode);
|
|
6959
7872
|
}
|
|
6960
7873
|
});
|
|
6961
|
-
apps.command("get <application>").description(
|
|
7874
|
+
apps.command("get <application>").description("Show one Topolo application. Run `topolo apps --json` to discover application IDs.").option("--json", "Output JSON", true).option("--no-json", "Output human-readable details").action((application, opts) => {
|
|
6962
7875
|
const mode = resolveOutputMode(opts.json);
|
|
6963
7876
|
try {
|
|
6964
7877
|
const app = resolveApplication(application);
|
|
@@ -7087,7 +8000,7 @@ function applicationRows() {
|
|
|
7087
8000
|
function resolveApplication(application) {
|
|
7088
8001
|
const id = application.trim().toLowerCase();
|
|
7089
8002
|
if (!APPLICATION_IDS.includes(id)) {
|
|
7090
|
-
throw new Error(`Unknown application "${application}".
|
|
8003
|
+
throw new Error(`Unknown application "${application}". ${formatKnownValues(APPLICATION_IDS, "applications")}`);
|
|
7091
8004
|
}
|
|
7092
8005
|
return APPLICATIONS[id];
|
|
7093
8006
|
}
|
|
@@ -7109,7 +8022,12 @@ function applicationRequirementsPayload(application) {
|
|
|
7109
8022
|
};
|
|
7110
8023
|
}
|
|
7111
8024
|
function applicationAuditPayload(application, options = {}) {
|
|
7112
|
-
const
|
|
8025
|
+
const requestedId = application?.trim().toLowerCase();
|
|
8026
|
+
const report = requestedId === "cloudcontrol" && options.local ? {
|
|
8027
|
+
version: APPLICATION_REQUIREMENTS_VERSION,
|
|
8028
|
+
applications: [auditApplicationRequirements(CLOUDCONTROL_LOCAL_APPLICATION)],
|
|
8029
|
+
migrationQueue: []
|
|
8030
|
+
} : application ? auditAllApplicationRequirements([resolveApplication(application).id]) : auditAllApplicationRequirements();
|
|
7113
8031
|
if (!options.local) return report;
|
|
7114
8032
|
return enrichApplicationAuditWithLocalEvidence(report, { repoRoot: options.repoRoot });
|
|
7115
8033
|
}
|
|
@@ -7233,6 +8151,7 @@ function formatRows(rows) {
|
|
|
7233
8151
|
return lines.join("\n");
|
|
7234
8152
|
}
|
|
7235
8153
|
function formatApplication(application) {
|
|
8154
|
+
const deployTargets = application.deployTargets;
|
|
7236
8155
|
const lines = [
|
|
7237
8156
|
`ID: ${application.id}`,
|
|
7238
8157
|
`Name: ${application.name}`,
|
|
@@ -7242,10 +8161,10 @@ function formatApplication(application) {
|
|
|
7242
8161
|
`Services: ${application.services.length ? application.services.join(", ") : "-"}`,
|
|
7243
8162
|
"Targets:"
|
|
7244
8163
|
];
|
|
7245
|
-
if (
|
|
8164
|
+
if (deployTargets.length === 0) {
|
|
7246
8165
|
lines.push(" - none");
|
|
7247
8166
|
} else {
|
|
7248
|
-
for (const target of
|
|
8167
|
+
for (const target of deployTargets) {
|
|
7249
8168
|
const parts = [`${target.name} (${target.kind})`];
|
|
7250
8169
|
if (target.serviceId) parts.push(`service=${target.serviceId}`);
|
|
7251
8170
|
if (target.apiUrl) parts.push(`api=${target.apiUrl}`);
|
|
@@ -7406,6 +8325,12 @@ function normalizeFailOn(value) {
|
|
|
7406
8325
|
}
|
|
7407
8326
|
throw new Error("Invalid --fail-on value. Use missing, needs_review, or partial.");
|
|
7408
8327
|
}
|
|
8328
|
+
function formatKnownValues(values, label) {
|
|
8329
|
+
const sorted = [...values].sort();
|
|
8330
|
+
const preview = sorted.slice(0, 25).join(", ");
|
|
8331
|
+
const suffix = sorted.length > 25 ? `, ... +${sorted.length - 25} more` : "";
|
|
8332
|
+
return `Run discovery for the full ${label} list. Known snapshot sample: ${preview}${suffix}`;
|
|
8333
|
+
}
|
|
7409
8334
|
function statusesAtOrWorse(threshold) {
|
|
7410
8335
|
if (threshold === "missing") return ["missing"];
|
|
7411
8336
|
if (threshold === "needs_review") return ["missing", "needs_review"];
|