@reventlessdev/reventless-aws 3.0.0-alpha.239 → 3.0.0-alpha.240
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/CHANGELOG.md +7 -0
- package/package.json +7 -7
- package/src/Platform.res +173 -15
- package/src/Platform.res.mjs +220 -32
- package/src/adapter/Upload/Upload_Presign_S3.res +19 -3
- package/src/adapter/Upload/Upload_Presign_S3.res.mjs +9 -9
- package/src/capability/Capability_ObjectStore_S3.res +69 -7
- package/src/capability/Capability_ObjectStore_S3.res.mjs +32 -6
- package/src/plugin/stack/Plugin_Stack.res +19 -6
- package/src/plugin/stack/Plugin_Stack.res.mjs +6 -6
- package/src/util/Util_HostUiDomain.res +17 -0
- package/src/util/Util_HostUiDomain.res.mjs +8 -1
- package/src/util/Util_StoreLayout.res +104 -0
- package/src/util/Util_StoreLayout.res.mjs +42 -0
- package/tests/Util_StoreLayoutTest.res +115 -0
- package/tests/Util_StoreLayoutTest.res.mjs +69 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.240 (2026-07-28)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **platform:** provision object stores from the fields that declare them ([b5e2a1e](https://github.com/ReventlessDev/reventless-core/commit/b5e2a1ec88099941c113e4963f9c4b346b96b0d6))
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
# 3.0.0-alpha.239 (2026-07-28)
|
|
7
14
|
|
|
8
15
|
**Note:** Version bump only for package @reventlessdev/reventless-aws
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-aws",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.240",
|
|
4
4
|
"description": "AWS adapters for Reventless",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"dependencies": {
|
|
@@ -12,16 +12,16 @@
|
|
|
12
12
|
"sury": "11.0.0-alpha.4",
|
|
13
13
|
"uuid": "^13.0.0",
|
|
14
14
|
"@reventlessdev/rescript-aws-sdk": "2.2.0-alpha.25",
|
|
15
|
-
"@reventlessdev/rescript-effect": "0.1.0-alpha.31",
|
|
16
15
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.9",
|
|
16
|
+
"@reventlessdev/rescript-effect": "0.1.0-alpha.31",
|
|
17
17
|
"@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.61",
|
|
18
18
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.17",
|
|
19
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.189",
|
|
20
|
-
"@reventlessdev/reventless-infra": "3.0.0-alpha.107",
|
|
21
|
-
"@reventlessdev/reventless-interop": "3.0.0-alpha.29",
|
|
22
19
|
"@reventlessdev/rescript-uuid": "1.1.0-alpha.17",
|
|
23
|
-
"@reventlessdev/reventless-
|
|
24
|
-
"@reventlessdev/reventless-
|
|
20
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.190",
|
|
21
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.108",
|
|
22
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.54",
|
|
23
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.83",
|
|
24
|
+
"@reventlessdev/reventless-interop": "3.0.0-alpha.29"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"rescript": "12.3.0",
|
package/src/Platform.res
CHANGED
|
@@ -1046,7 +1046,11 @@ module MakeWithConfig = (
|
|
|
1046
1046
|
platformMergeGate: Pulumi.Output.t<unit>,
|
|
1047
1047
|
}
|
|
1048
1048
|
|
|
1049
|
-
let deployPlatform = (
|
|
1049
|
+
let deployPlatform = (
|
|
1050
|
+
~version,
|
|
1051
|
+
~hostUiBundle: option<hostUiBundleConfig>=?,
|
|
1052
|
+
~capabilities: array<ReventlessInfra.Platform.capability>=[],
|
|
1053
|
+
) => {
|
|
1050
1054
|
log.info(~comp="Platform:deployPlatform", `v${version}`)
|
|
1051
1055
|
let scheduler = makeScheduler()
|
|
1052
1056
|
hooks.scheduler := Some(scheduler)
|
|
@@ -1452,6 +1456,120 @@ module MakeWithConfig = (
|
|
|
1452
1456
|
})
|
|
1453
1457
|
})
|
|
1454
1458
|
|
|
1459
|
+
// ── Declared object stores ────────────────────────────────────────────
|
|
1460
|
+
//
|
|
1461
|
+
// The store a field declares is the store that gets provisioned. Before
|
|
1462
|
+
// this, a `@storageRef("productImages")` annotation and a hand-written
|
|
1463
|
+
// bucket name were two unrelated strings: deleting the annotation left the
|
|
1464
|
+
// bucket, and adding one provisioned nothing.
|
|
1465
|
+
//
|
|
1466
|
+
// Provisioned here, in the platform deploy, rather than in each plugin's
|
|
1467
|
+
// stack. Three things force it: the serving CDN lives here, the presign
|
|
1468
|
+
// services live here, and a shared-layout bucket has several plugins'
|
|
1469
|
+
// stores in it, so no single plugin stack can own it. Ownership is carried
|
|
1470
|
+
// in the tags instead — a per-store bucket is tagged to the plugin whose
|
|
1471
|
+
// field declared it; a shared bucket is platform substrate, because that is
|
|
1472
|
+
// what it is.
|
|
1473
|
+
let stackName = Pulumi.Pulumi.getStackName()
|
|
1474
|
+
let storeLayout = Util_StoreLayout.layoutFor(
|
|
1475
|
+
~stack=stackName,
|
|
1476
|
+
~prodStacks=Util_HostUiDomain.resolveProdStacks(),
|
|
1477
|
+
)
|
|
1478
|
+
let storeProtection = Util_StoreLayout.protectionFor(~stack=stackName)
|
|
1479
|
+
|
|
1480
|
+
// Dedup by `(plugin, store)` — that pair is a store's identity, and many
|
|
1481
|
+
// fields legitimately name one store.
|
|
1482
|
+
let declaredStores =
|
|
1483
|
+
capabilities
|
|
1484
|
+
->Array.filterMap(c =>
|
|
1485
|
+
switch c {
|
|
1486
|
+
| ObjectStore({plugin, store}) => Some((plugin, store))
|
|
1487
|
+
| Geocoding => None
|
|
1488
|
+
}
|
|
1489
|
+
)
|
|
1490
|
+
->Array.reduce([], (acc, (plugin, store)) =>
|
|
1491
|
+
acc->Array.some(((p, s)) => p == plugin && s == store)
|
|
1492
|
+
? acc
|
|
1493
|
+
: Array.concat(acc, [(plugin, store)])
|
|
1494
|
+
)
|
|
1495
|
+
|
|
1496
|
+
if declaredStores->Array.length > 0 {
|
|
1497
|
+
// The fail-open in `layoutFor` is only dangerous while it is silent: a
|
|
1498
|
+
// production stack that is not on the prod list gets the shared layout and
|
|
1499
|
+
// nothing errors. Log the choice on every deploy so it surfaces the first
|
|
1500
|
+
// time it happens rather than at an audit.
|
|
1501
|
+
log.info(
|
|
1502
|
+
~comp="Platform:deployPlatform",
|
|
1503
|
+
`object stores: ${switch storeLayout {
|
|
1504
|
+
| PerStore => "bucket per store"
|
|
1505
|
+
| SharedBucket => "shared bucket, {store}/… prefixes"
|
|
1506
|
+
}}, ${switch storeProtection {
|
|
1507
|
+
| Protected => "protected"
|
|
1508
|
+
| Unprotected => "unprotected (disposable stack)"
|
|
1509
|
+
}} — stack ${stackName}`,
|
|
1510
|
+
)
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
// One bucket per *physical name*, which is one per store under `PerStore`
|
|
1514
|
+
// and one for the whole stack under `SharedBucket`. Grouped rather than
|
|
1515
|
+
// mapped because those cardinalities differ, and a bucket carries only one
|
|
1516
|
+
// policy and one CDN origin however many stores live in it.
|
|
1517
|
+
let storeBuckets: Dict.t<ReventlessInfra.Platform.objectStore> = Dict.make()
|
|
1518
|
+
let storeBucketOrder: array<string> = []
|
|
1519
|
+
let declaredStoreServices = declaredStores->Array.map(((plugin, store)) => {
|
|
1520
|
+
let bucketName = Util_StoreLayout.bucketNameFor(
|
|
1521
|
+
~layout=storeLayout,
|
|
1522
|
+
~stack=stackName,
|
|
1523
|
+
~plugin,
|
|
1524
|
+
~store,
|
|
1525
|
+
)
|
|
1526
|
+
let keyPrefix = Util_StoreLayout.keyPrefixFor(~store)
|
|
1527
|
+
let bucket = switch storeBuckets->Dict.get(bucketName) {
|
|
1528
|
+
| Some(b) => b
|
|
1529
|
+
| None =>
|
|
1530
|
+
let b = Capability_ObjectStore_S3.make(
|
|
1531
|
+
~name=bucketName,
|
|
1532
|
+
~keyPrefix,
|
|
1533
|
+
// A shared bucket belongs to no single plugin; a dedicated one does.
|
|
1534
|
+
~plugin=?switch storeLayout {
|
|
1535
|
+
| PerStore => Some(plugin)
|
|
1536
|
+
| SharedBucket => None
|
|
1537
|
+
},
|
|
1538
|
+
~protect=storeProtection == Protected,
|
|
1539
|
+
// A protected bucket blocks `pulumi destroy`, so protecting a
|
|
1540
|
+
// disposable stack would leak exactly the buckets sharing exists to
|
|
1541
|
+
// save. The two settings are opposite faces of one decision.
|
|
1542
|
+
~forceDestroy=storeProtection == Unprotected,
|
|
1543
|
+
)
|
|
1544
|
+
storeBuckets->Dict.set(bucketName, b)
|
|
1545
|
+
storeBucketOrder->Array.push(bucketName)
|
|
1546
|
+
b
|
|
1547
|
+
}
|
|
1548
|
+
let storeHandle = bucket->Capability_ObjectStore_S3.underPrefix(~keyPrefix)
|
|
1549
|
+
// One presign service per store, scoped to that store's own prefix.
|
|
1550
|
+
let presign = Upload_Presign_S3.make(
|
|
1551
|
+
~name=`UploadPresign-${plugin}-${store}`,
|
|
1552
|
+
~bucketName=storeHandle.bucketName,
|
|
1553
|
+
~servedPrefix=storeHandle.keyPrefix,
|
|
1554
|
+
)
|
|
1555
|
+
(`${plugin}.${store}`, keyPrefix, bucketName, presign.url)
|
|
1556
|
+
})
|
|
1557
|
+
|
|
1558
|
+
// Group the served view by bucket: one origin and one bucket policy per
|
|
1559
|
+
// bucket, carrying every prefix served from it.
|
|
1560
|
+
let declaredServedBuckets = storeBucketOrder->Array.filterMap(bucketName =>
|
|
1561
|
+
storeBuckets
|
|
1562
|
+
->Dict.get(bucketName)
|
|
1563
|
+
->Option.map(b => {
|
|
1564
|
+
ReventlessInfra.Platform.id: bucketName,
|
|
1565
|
+
prefixes: declaredStoreServices
|
|
1566
|
+
->Array.filterMap(((_, prefix, bn, _)) => bn == bucketName ? Some(prefix) : None),
|
|
1567
|
+
bucketId: b.bucketId,
|
|
1568
|
+
bucketArn: b.bucketArn,
|
|
1569
|
+
bucketRegionalDomainName: b.bucketRegionalDomainName,
|
|
1570
|
+
})
|
|
1571
|
+
)
|
|
1572
|
+
|
|
1455
1573
|
// Host UI shell deployment — opt-in via ~hostUiBundle. The shell SPA is
|
|
1456
1574
|
// hosted on its own CloudFront distribution; `config.json` is generated
|
|
1457
1575
|
// at deploy time with the resolved API endpoints, region, and Cognito
|
|
@@ -1494,17 +1612,27 @@ module MakeWithConfig = (
|
|
|
1494
1612
|
// roots its keys at, read from the service's own constant. This is the
|
|
1495
1613
|
// whole reason the store arrives as one value: the app no longer restates
|
|
1496
1614
|
// the prefix, so it cannot restate it wrongly.
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1615
|
+
//
|
|
1616
|
+
// The legacy hand-configured store is served alongside the declared ones,
|
|
1617
|
+
// not replaced by them. Refs live in an append-only event log, so the
|
|
1618
|
+
// `/uploads/…` values already written there can never be rewritten;
|
|
1619
|
+
// `uploads` is therefore treated as a store that happens to predate the
|
|
1620
|
+
// declaration, and keeps its prefix permanently.
|
|
1621
|
+
let servedBuckets = Array.concat(
|
|
1622
|
+
switch cfg.uploadBucket {
|
|
1623
|
+
| Some(store) => [
|
|
1624
|
+
{
|
|
1625
|
+
ReventlessInfra.Platform.id: store.keyPrefix,
|
|
1626
|
+
prefixes: [store.keyPrefix],
|
|
1627
|
+
bucketId: store.bucketId,
|
|
1628
|
+
bucketArn: store.bucketArn,
|
|
1629
|
+
bucketRegionalDomainName: store.bucketRegionalDomainName,
|
|
1630
|
+
},
|
|
1631
|
+
]
|
|
1632
|
+
| None => []
|
|
1633
|
+
},
|
|
1634
|
+
declaredServedBuckets,
|
|
1635
|
+
)
|
|
1508
1636
|
|
|
1509
1637
|
let {distributionUrl, bucketName} = Plugin_Stack.makeUiBundleDistribution(
|
|
1510
1638
|
~pluginId="host-ui",
|
|
@@ -1569,6 +1697,18 @@ module MakeWithConfig = (
|
|
|
1569
1697
|
| None => Pulumi.Output.make(None)
|
|
1570
1698
|
}
|
|
1571
1699
|
|
|
1700
|
+
// Per-store presign endpoints, keyed by the store's qualified name. This
|
|
1701
|
+
// is what lets an upload input bind to the store its field *declares*
|
|
1702
|
+
// rather than inferring one from the field's name — the endpoint exists
|
|
1703
|
+
// per store, so there is something concrete to bind to.
|
|
1704
|
+
//
|
|
1705
|
+
// `uploadEndpoint` (singular) stays as the legacy service's URL: a shell
|
|
1706
|
+
// built before per-store binding reads it and is unaffected.
|
|
1707
|
+
let storeUploadEndpointsOutput: Pulumi.Output.t<array<(string, string)>> =
|
|
1708
|
+
declaredStoreServices
|
|
1709
|
+
->Array.map(((qualified, _, _, url)) => url->Pulumi.Output.apply(u => (qualified, u)))
|
|
1710
|
+
->Pulumi.Output.all
|
|
1711
|
+
|
|
1572
1712
|
let configJsonContent =
|
|
1573
1713
|
(
|
|
1574
1714
|
(
|
|
@@ -1579,14 +1719,14 @@ module MakeWithConfig = (
|
|
|
1579
1719
|
)->Pulumi.Output.all4,
|
|
1580
1720
|
domainEventsEndpointOutput,
|
|
1581
1721
|
geocoderEndpointOutput,
|
|
1582
|
-
uploadEndpointOutput,
|
|
1722
|
+
(uploadEndpointOutput, storeUploadEndpointsOutput)->Pulumi.Output.all2,
|
|
1583
1723
|
)
|
|
1584
1724
|
->Pulumi.Output.all4
|
|
1585
1725
|
->Pulumi.Output.apply(((
|
|
1586
1726
|
(domainEp, platformEp, poolId, clientId),
|
|
1587
1727
|
eventsEpOpt,
|
|
1588
1728
|
geocoderEpOpt,
|
|
1589
|
-
uploadEpOpt,
|
|
1729
|
+
(uploadEpOpt, storeUploadEps),
|
|
1590
1730
|
)) => {
|
|
1591
1731
|
let fields = [
|
|
1592
1732
|
("apiEndpoint", JSON.Encode.string(domainEp)),
|
|
@@ -1623,7 +1763,25 @@ module MakeWithConfig = (
|
|
|
1623
1763
|
| Some(ep) => Array.concat(withGeocoder, [("uploadEndpoint", JSON.Encode.string(ep))])
|
|
1624
1764
|
| None => withGeocoder
|
|
1625
1765
|
}
|
|
1626
|
-
|
|
1766
|
+
// Omitted entirely when nothing is declared, so a deployment without
|
|
1767
|
+
// declared stores writes a byte-identical config.json.
|
|
1768
|
+
let withStoreUploads = switch storeUploadEps {
|
|
1769
|
+
| [] => withUpload
|
|
1770
|
+
| eps =>
|
|
1771
|
+
Array.concat(
|
|
1772
|
+
withUpload,
|
|
1773
|
+
[
|
|
1774
|
+
(
|
|
1775
|
+
"uploadEndpoints",
|
|
1776
|
+
eps
|
|
1777
|
+
->Array.map(((qualified, url)) => (qualified, JSON.Encode.string(url)))
|
|
1778
|
+
->Dict.fromArray
|
|
1779
|
+
->JSON.Encode.object,
|
|
1780
|
+
),
|
|
1781
|
+
],
|
|
1782
|
+
)
|
|
1783
|
+
}
|
|
1784
|
+
withStoreUploads->Dict.fromArray->JSON.Encode.object->JSON.stringify
|
|
1627
1785
|
})
|
|
1628
1786
|
|
|
1629
1787
|
let _ = PulumiAws.S3.BucketObject.make(
|
package/src/Platform.res.mjs
CHANGED
|
@@ -36,6 +36,7 @@ import * as PluginBehavior$ReventlessCore from "@reventlessdev/reventless-core/s
|
|
|
36
36
|
import * as Plugin_Helpers$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/component/Plugin_Helpers.res.mjs";
|
|
37
37
|
import * as PgProjectionFeed$ReventlessAws from "./adapter/Postgres/PgProjectionFeed.res.mjs";
|
|
38
38
|
import * as Util_LocalConfig$ReventlessAws from "./util/Util_LocalConfig.res.mjs";
|
|
39
|
+
import * as Util_StoreLayout$ReventlessAws from "./util/Util_StoreLayout.res.mjs";
|
|
39
40
|
import * as IndexJs from "@pulumi/pulumi/runtime/index.js";
|
|
40
41
|
import * as AppSync_EventsApi$ReventlessAws from "./adapter/Api/AppSync_EventsApi.res.mjs";
|
|
41
42
|
import * as AppSync_MergedApi$ReventlessAws from "./components/Api/AppSync_MergedApi.res.mjs";
|
|
@@ -68,6 +69,7 @@ import * as UiFragments_Projection$ReventlessCore from "@reventlessdev/reventles
|
|
|
68
69
|
import * as Aggregate_Builder_Single$ReventlessAws from "./components/Aggregate_Builder_Single.res.mjs";
|
|
69
70
|
import * as ReadModel_Builder_Single$ReventlessAws from "./components/ReadModel_Builder_Single.res.mjs";
|
|
70
71
|
import * as StateChangeSlice_Builder$ReventlessAws from "./components/StateChangeSlice_Builder.res.mjs";
|
|
72
|
+
import * as Capability_ObjectStore_S3$ReventlessAws from "./capability/Capability_ObjectStore_S3.res.mjs";
|
|
71
73
|
import * as EventCollectorChannel_SQS$ReventlessAws from "./adapter/EventCollector/EventCollectorChannel_SQS.res.mjs";
|
|
72
74
|
import * as PgChangeFeedRelay_Builder$ReventlessAws from "./adapter/Postgres/PgChangeFeedRelay_Builder.res.mjs";
|
|
73
75
|
import * as RuntimeEnvironment_Lambda$ReventlessAws from "./adapter/Runtime/RuntimeEnvironment_Lambda.res.mjs";
|
|
@@ -708,7 +710,8 @@ function MakeWithConfig(Config) {
|
|
|
708
710
|
log.info("Platform", undefined, `v` + version);
|
|
709
711
|
return Pervasives.failwith("makePlatform is not supported on AWS — deploy the platform with deployPlatform and each plugin with deployPlugin (merged-API composition).");
|
|
710
712
|
};
|
|
711
|
-
let deployPlatform = (version, hostUiBundle) => {
|
|
713
|
+
let deployPlatform = (version, hostUiBundle, capabilitiesOpt) => {
|
|
714
|
+
let capabilities = capabilitiesOpt !== undefined ? capabilitiesOpt : [];
|
|
712
715
|
log.info("Platform:deployPlatform", undefined, `v` + version);
|
|
713
716
|
let scheduler = makeScheduler();
|
|
714
717
|
hooks_scheduler.contents = scheduler;
|
|
@@ -868,6 +871,76 @@ function MakeWithConfig(Config) {
|
|
|
868
871
|
adminResources: param[4]
|
|
869
872
|
});
|
|
870
873
|
});
|
|
874
|
+
let stackName = Pulumi.getStack();
|
|
875
|
+
let storeLayout = Util_StoreLayout$ReventlessAws.layoutFor(stackName, Util_HostUiDomain$ReventlessAws.resolveProdStacks());
|
|
876
|
+
let storeProtection = Util_StoreLayout$ReventlessAws.protectionFor(stackName, undefined);
|
|
877
|
+
let declaredStores = Stdlib_Array.reduce(Stdlib_Array.filterMap(capabilities, c => {
|
|
878
|
+
if (typeof c !== "object") {
|
|
879
|
+
return;
|
|
880
|
+
} else {
|
|
881
|
+
return [
|
|
882
|
+
c.plugin,
|
|
883
|
+
c.store
|
|
884
|
+
];
|
|
885
|
+
}
|
|
886
|
+
}), [], (acc, param) => {
|
|
887
|
+
let store = param[1];
|
|
888
|
+
let plugin = param[0];
|
|
889
|
+
if (acc.some(param => param[0] === plugin ? param[1] === store : false)) {
|
|
890
|
+
return acc;
|
|
891
|
+
} else {
|
|
892
|
+
return acc.concat([[
|
|
893
|
+
plugin,
|
|
894
|
+
store
|
|
895
|
+
]]);
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
if (declaredStores.length !== 0) {
|
|
899
|
+
let tmp;
|
|
900
|
+
tmp = storeLayout === "PerStore" ? "bucket per store" : "shared bucket, {store}/… prefixes";
|
|
901
|
+
let tmp$1;
|
|
902
|
+
tmp$1 = storeProtection === "Protected" ? "protected" : "unprotected (disposable stack)";
|
|
903
|
+
log.info("Platform:deployPlatform", undefined, `object stores: ` + tmp + `, ` + tmp$1 + ` — stack ` + stackName);
|
|
904
|
+
}
|
|
905
|
+
let storeBuckets = {};
|
|
906
|
+
let storeBucketOrder = [];
|
|
907
|
+
let declaredStoreServices = declaredStores.map(param => {
|
|
908
|
+
let store = param[1];
|
|
909
|
+
let plugin = param[0];
|
|
910
|
+
let bucketName = Util_StoreLayout$ReventlessAws.bucketNameFor(storeLayout, stackName, plugin, store);
|
|
911
|
+
let keyPrefix = Util_StoreLayout$ReventlessAws.keyPrefixFor(store);
|
|
912
|
+
let b = storeBuckets[bucketName];
|
|
913
|
+
let bucket;
|
|
914
|
+
if (b !== undefined) {
|
|
915
|
+
bucket = b;
|
|
916
|
+
} else {
|
|
917
|
+
let tmp;
|
|
918
|
+
tmp = storeLayout === "PerStore" ? plugin : undefined;
|
|
919
|
+
let b$1 = Capability_ObjectStore_S3$ReventlessAws.make(bucketName, keyPrefix, tmp, storeProtection === "Protected", storeProtection === "Unprotected", undefined, undefined);
|
|
920
|
+
storeBuckets[bucketName] = b$1;
|
|
921
|
+
storeBucketOrder.push(bucketName);
|
|
922
|
+
bucket = b$1;
|
|
923
|
+
}
|
|
924
|
+
let storeHandle = Capability_ObjectStore_S3$ReventlessAws.underPrefix(bucket, keyPrefix);
|
|
925
|
+
let presign = Upload_Presign_S3$ReventlessAws.make(storeHandle.bucketName, undefined, storeHandle.keyPrefix, `UploadPresign-` + plugin + `-` + store, undefined);
|
|
926
|
+
return [
|
|
927
|
+
plugin + `.` + store,
|
|
928
|
+
keyPrefix,
|
|
929
|
+
bucketName,
|
|
930
|
+
presign.url
|
|
931
|
+
];
|
|
932
|
+
});
|
|
933
|
+
let declaredServedBuckets = Stdlib_Array.filterMap(storeBucketOrder, bucketName => Stdlib_Option.map(storeBuckets[bucketName], b => ({
|
|
934
|
+
id: bucketName,
|
|
935
|
+
prefixes: Stdlib_Array.filterMap(declaredStoreServices, param => {
|
|
936
|
+
if (param[2] === bucketName) {
|
|
937
|
+
return param[1];
|
|
938
|
+
}
|
|
939
|
+
}),
|
|
940
|
+
bucketId: b.bucketId,
|
|
941
|
+
bucketArn: b.bucketArn,
|
|
942
|
+
bucketRegionalDomainName: b.bucketRegionalDomainName
|
|
943
|
+
})));
|
|
871
944
|
if (hostUiBundle !== undefined) {
|
|
872
945
|
let match$1 = Util_LocalConfig$ReventlessAws.get("hostUiBaseDomain");
|
|
873
946
|
let match$2 = Util_LocalConfig$ReventlessAws.get("hostUiHostedZoneId");
|
|
@@ -885,12 +958,15 @@ function MakeWithConfig(Config) {
|
|
|
885
958
|
customDomain = undefined;
|
|
886
959
|
}
|
|
887
960
|
let store = hostUiBundle.uploadBucket;
|
|
888
|
-
let servedBuckets =
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
961
|
+
let servedBuckets = (
|
|
962
|
+
store !== undefined ? [{
|
|
963
|
+
id: store.keyPrefix,
|
|
964
|
+
prefixes: [store.keyPrefix],
|
|
965
|
+
bucketId: store.bucketId,
|
|
966
|
+
bucketArn: store.bucketArn,
|
|
967
|
+
bucketRegionalDomainName: store.bucketRegionalDomainName
|
|
968
|
+
}] : []
|
|
969
|
+
).concat(declaredServedBuckets);
|
|
894
970
|
let match$3 = Plugin_Stack$ReventlessAws.makeUiBundleDistribution("host-ui", Stdlib_Option.getOr(hostUiBundle.bundleVersion, version), Stdlib_Option.getOr(hostUiBundle.assetsDir, Util_Bundle$ReventlessAws.resolvePackageRoot("@reventlessdev/reventless-host-shell") + "/dist"), true, undefined, true, [
|
|
895
971
|
"config.json",
|
|
896
972
|
"ui-hints.json"
|
|
@@ -902,7 +978,14 @@ function MakeWithConfig(Config) {
|
|
|
902
978
|
let index = hostUiBundle.geocoderPlaceIndex;
|
|
903
979
|
let geocoderEndpointOutput = index !== undefined ? Geocoder_AwsLocation$ReventlessAws.make(index.indexName, undefined, undefined).url.apply(u => u) : Pulumi.output(undefined);
|
|
904
980
|
let store$1 = hostUiBundle.uploadBucket;
|
|
905
|
-
let uploadEndpointOutput = store$1 !== undefined ? Upload_Presign_S3$ReventlessAws.make(store$1.bucketName, undefined, undefined, undefined).url.apply(u => u) : Pulumi.output(undefined);
|
|
981
|
+
let uploadEndpointOutput = store$1 !== undefined ? Upload_Presign_S3$ReventlessAws.make(store$1.bucketName, undefined, undefined, undefined, undefined).url.apply(u => u) : Pulumi.output(undefined);
|
|
982
|
+
let storeUploadEndpointsOutput = Pulumi.all(declaredStoreServices.map(param => {
|
|
983
|
+
let qualified = param[0];
|
|
984
|
+
return param[3].apply(u => [
|
|
985
|
+
qualified,
|
|
986
|
+
u
|
|
987
|
+
]);
|
|
988
|
+
}));
|
|
906
989
|
let configJsonContent = Pulumi.all([
|
|
907
990
|
Pulumi.all([
|
|
908
991
|
resolvedDomainApiEndpoint,
|
|
@@ -912,20 +995,25 @@ function MakeWithConfig(Config) {
|
|
|
912
995
|
]),
|
|
913
996
|
domainEventsEndpointOutput,
|
|
914
997
|
geocoderEndpointOutput,
|
|
915
|
-
|
|
998
|
+
Pulumi.all([
|
|
999
|
+
uploadEndpointOutput,
|
|
1000
|
+
storeUploadEndpointsOutput
|
|
1001
|
+
])
|
|
916
1002
|
]).apply(param => {
|
|
917
|
-
let
|
|
1003
|
+
let match = param[3];
|
|
1004
|
+
let storeUploadEps = match[1];
|
|
1005
|
+
let uploadEpOpt = match[0];
|
|
918
1006
|
let geocoderEpOpt = param[2];
|
|
919
1007
|
let eventsEpOpt = param[1];
|
|
920
|
-
let match = param[0];
|
|
1008
|
+
let match$1 = param[0];
|
|
921
1009
|
let fields = [
|
|
922
1010
|
[
|
|
923
1011
|
"apiEndpoint",
|
|
924
|
-
match[0]
|
|
1012
|
+
match$1[0]
|
|
925
1013
|
],
|
|
926
1014
|
[
|
|
927
1015
|
"platformApiEndpoint",
|
|
928
|
-
match[1]
|
|
1016
|
+
match$1[1]
|
|
929
1017
|
],
|
|
930
1018
|
[
|
|
931
1019
|
"region",
|
|
@@ -937,11 +1025,11 @@ function MakeWithConfig(Config) {
|
|
|
937
1025
|
],
|
|
938
1026
|
[
|
|
939
1027
|
"cognitoUserPoolId",
|
|
940
|
-
match[2]
|
|
1028
|
+
match$1[2]
|
|
941
1029
|
],
|
|
942
1030
|
[
|
|
943
1031
|
"cognitoClientId",
|
|
944
|
-
match[3]
|
|
1032
|
+
match$1[3]
|
|
945
1033
|
],
|
|
946
1034
|
[
|
|
947
1035
|
"liveUpdates",
|
|
@@ -970,7 +1058,14 @@ function MakeWithConfig(Config) {
|
|
|
970
1058
|
"uploadEndpoint",
|
|
971
1059
|
uploadEpOpt
|
|
972
1060
|
]]) : withGeocoder;
|
|
973
|
-
|
|
1061
|
+
let withStoreUploads = storeUploadEps.length !== 0 ? withUpload.concat([[
|
|
1062
|
+
"uploadEndpoints",
|
|
1063
|
+
Object.fromEntries(storeUploadEps.map(param => [
|
|
1064
|
+
param[0],
|
|
1065
|
+
param[1]
|
|
1066
|
+
]))
|
|
1067
|
+
]]) : withUpload;
|
|
1068
|
+
return JSON.stringify(Object.fromEntries(withStoreUploads));
|
|
974
1069
|
});
|
|
975
1070
|
new (Aws.s3.BucketObject)("host-ui-config-json", {
|
|
976
1071
|
bucket: bucketName,
|
|
@@ -1724,7 +1819,8 @@ function Make($star) {
|
|
|
1724
1819
|
log.info("Platform", undefined, `v` + version);
|
|
1725
1820
|
return Pervasives.failwith("makePlatform is not supported on AWS — deploy the platform with deployPlatform and each plugin with deployPlugin (merged-API composition).");
|
|
1726
1821
|
};
|
|
1727
|
-
let deployPlatform = (version, hostUiBundle) => {
|
|
1822
|
+
let deployPlatform = (version, hostUiBundle, capabilitiesOpt) => {
|
|
1823
|
+
let capabilities = capabilitiesOpt !== undefined ? capabilitiesOpt : [];
|
|
1728
1824
|
log.info("Platform:deployPlatform", undefined, `v` + version);
|
|
1729
1825
|
let scheduler = makeScheduler();
|
|
1730
1826
|
hooks_scheduler.contents = scheduler;
|
|
@@ -1861,6 +1957,76 @@ function Make($star) {
|
|
|
1861
1957
|
adminResources: param[4]
|
|
1862
1958
|
});
|
|
1863
1959
|
});
|
|
1960
|
+
let stackName = Pulumi.getStack();
|
|
1961
|
+
let storeLayout = Util_StoreLayout$ReventlessAws.layoutFor(stackName, Util_HostUiDomain$ReventlessAws.resolveProdStacks());
|
|
1962
|
+
let storeProtection = Util_StoreLayout$ReventlessAws.protectionFor(stackName, undefined);
|
|
1963
|
+
let declaredStores = Stdlib_Array.reduce(Stdlib_Array.filterMap(capabilities, c => {
|
|
1964
|
+
if (typeof c !== "object") {
|
|
1965
|
+
return;
|
|
1966
|
+
} else {
|
|
1967
|
+
return [
|
|
1968
|
+
c.plugin,
|
|
1969
|
+
c.store
|
|
1970
|
+
];
|
|
1971
|
+
}
|
|
1972
|
+
}), [], (acc, param) => {
|
|
1973
|
+
let store = param[1];
|
|
1974
|
+
let plugin = param[0];
|
|
1975
|
+
if (acc.some(param => param[0] === plugin ? param[1] === store : false)) {
|
|
1976
|
+
return acc;
|
|
1977
|
+
} else {
|
|
1978
|
+
return acc.concat([[
|
|
1979
|
+
plugin,
|
|
1980
|
+
store
|
|
1981
|
+
]]);
|
|
1982
|
+
}
|
|
1983
|
+
});
|
|
1984
|
+
if (declaredStores.length !== 0) {
|
|
1985
|
+
let tmp;
|
|
1986
|
+
tmp = storeLayout === "PerStore" ? "bucket per store" : "shared bucket, {store}/… prefixes";
|
|
1987
|
+
let tmp$1;
|
|
1988
|
+
tmp$1 = storeProtection === "Protected" ? "protected" : "unprotected (disposable stack)";
|
|
1989
|
+
log.info("Platform:deployPlatform", undefined, `object stores: ` + tmp + `, ` + tmp$1 + ` — stack ` + stackName);
|
|
1990
|
+
}
|
|
1991
|
+
let storeBuckets = {};
|
|
1992
|
+
let storeBucketOrder = [];
|
|
1993
|
+
let declaredStoreServices = declaredStores.map(param => {
|
|
1994
|
+
let store = param[1];
|
|
1995
|
+
let plugin = param[0];
|
|
1996
|
+
let bucketName = Util_StoreLayout$ReventlessAws.bucketNameFor(storeLayout, stackName, plugin, store);
|
|
1997
|
+
let keyPrefix = Util_StoreLayout$ReventlessAws.keyPrefixFor(store);
|
|
1998
|
+
let b = storeBuckets[bucketName];
|
|
1999
|
+
let bucket;
|
|
2000
|
+
if (b !== undefined) {
|
|
2001
|
+
bucket = b;
|
|
2002
|
+
} else {
|
|
2003
|
+
let tmp;
|
|
2004
|
+
tmp = storeLayout === "PerStore" ? plugin : undefined;
|
|
2005
|
+
let b$1 = Capability_ObjectStore_S3$ReventlessAws.make(bucketName, keyPrefix, tmp, storeProtection === "Protected", storeProtection === "Unprotected", undefined, undefined);
|
|
2006
|
+
storeBuckets[bucketName] = b$1;
|
|
2007
|
+
storeBucketOrder.push(bucketName);
|
|
2008
|
+
bucket = b$1;
|
|
2009
|
+
}
|
|
2010
|
+
let storeHandle = Capability_ObjectStore_S3$ReventlessAws.underPrefix(bucket, keyPrefix);
|
|
2011
|
+
let presign = Upload_Presign_S3$ReventlessAws.make(storeHandle.bucketName, undefined, storeHandle.keyPrefix, `UploadPresign-` + plugin + `-` + store, undefined);
|
|
2012
|
+
return [
|
|
2013
|
+
plugin + `.` + store,
|
|
2014
|
+
keyPrefix,
|
|
2015
|
+
bucketName,
|
|
2016
|
+
presign.url
|
|
2017
|
+
];
|
|
2018
|
+
});
|
|
2019
|
+
let declaredServedBuckets = Stdlib_Array.filterMap(storeBucketOrder, bucketName => Stdlib_Option.map(storeBuckets[bucketName], b => ({
|
|
2020
|
+
id: bucketName,
|
|
2021
|
+
prefixes: Stdlib_Array.filterMap(declaredStoreServices, param => {
|
|
2022
|
+
if (param[2] === bucketName) {
|
|
2023
|
+
return param[1];
|
|
2024
|
+
}
|
|
2025
|
+
}),
|
|
2026
|
+
bucketId: b.bucketId,
|
|
2027
|
+
bucketArn: b.bucketArn,
|
|
2028
|
+
bucketRegionalDomainName: b.bucketRegionalDomainName
|
|
2029
|
+
})));
|
|
1864
2030
|
if (hostUiBundle !== undefined) {
|
|
1865
2031
|
let match$1 = Util_LocalConfig$ReventlessAws.get("hostUiBaseDomain");
|
|
1866
2032
|
let match$2 = Util_LocalConfig$ReventlessAws.get("hostUiHostedZoneId");
|
|
@@ -1878,12 +2044,15 @@ function Make($star) {
|
|
|
1878
2044
|
customDomain = undefined;
|
|
1879
2045
|
}
|
|
1880
2046
|
let store = hostUiBundle.uploadBucket;
|
|
1881
|
-
let servedBuckets =
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
2047
|
+
let servedBuckets = (
|
|
2048
|
+
store !== undefined ? [{
|
|
2049
|
+
id: store.keyPrefix,
|
|
2050
|
+
prefixes: [store.keyPrefix],
|
|
2051
|
+
bucketId: store.bucketId,
|
|
2052
|
+
bucketArn: store.bucketArn,
|
|
2053
|
+
bucketRegionalDomainName: store.bucketRegionalDomainName
|
|
2054
|
+
}] : []
|
|
2055
|
+
).concat(declaredServedBuckets);
|
|
1887
2056
|
let match$3 = Plugin_Stack$ReventlessAws.makeUiBundleDistribution("host-ui", Stdlib_Option.getOr(hostUiBundle.bundleVersion, version), Stdlib_Option.getOr(hostUiBundle.assetsDir, Util_Bundle$ReventlessAws.resolvePackageRoot("@reventlessdev/reventless-host-shell") + "/dist"), true, undefined, true, [
|
|
1888
2057
|
"config.json",
|
|
1889
2058
|
"ui-hints.json"
|
|
@@ -1895,7 +2064,14 @@ function Make($star) {
|
|
|
1895
2064
|
let index = hostUiBundle.geocoderPlaceIndex;
|
|
1896
2065
|
let geocoderEndpointOutput = index !== undefined ? Geocoder_AwsLocation$ReventlessAws.make(index.indexName, undefined, undefined).url.apply(u => u) : Pulumi.output(undefined);
|
|
1897
2066
|
let store$1 = hostUiBundle.uploadBucket;
|
|
1898
|
-
let uploadEndpointOutput = store$1 !== undefined ? Upload_Presign_S3$ReventlessAws.make(store$1.bucketName, undefined, undefined, undefined).url.apply(u => u) : Pulumi.output(undefined);
|
|
2067
|
+
let uploadEndpointOutput = store$1 !== undefined ? Upload_Presign_S3$ReventlessAws.make(store$1.bucketName, undefined, undefined, undefined, undefined).url.apply(u => u) : Pulumi.output(undefined);
|
|
2068
|
+
let storeUploadEndpointsOutput = Pulumi.all(declaredStoreServices.map(param => {
|
|
2069
|
+
let qualified = param[0];
|
|
2070
|
+
return param[3].apply(u => [
|
|
2071
|
+
qualified,
|
|
2072
|
+
u
|
|
2073
|
+
]);
|
|
2074
|
+
}));
|
|
1899
2075
|
let configJsonContent = Pulumi.all([
|
|
1900
2076
|
Pulumi.all([
|
|
1901
2077
|
resolvedDomainApiEndpoint,
|
|
@@ -1905,20 +2081,25 @@ function Make($star) {
|
|
|
1905
2081
|
]),
|
|
1906
2082
|
domainEventsEndpointOutput,
|
|
1907
2083
|
geocoderEndpointOutput,
|
|
1908
|
-
|
|
2084
|
+
Pulumi.all([
|
|
2085
|
+
uploadEndpointOutput,
|
|
2086
|
+
storeUploadEndpointsOutput
|
|
2087
|
+
])
|
|
1909
2088
|
]).apply(param => {
|
|
1910
|
-
let
|
|
2089
|
+
let match = param[3];
|
|
2090
|
+
let storeUploadEps = match[1];
|
|
2091
|
+
let uploadEpOpt = match[0];
|
|
1911
2092
|
let geocoderEpOpt = param[2];
|
|
1912
2093
|
let eventsEpOpt = param[1];
|
|
1913
|
-
let match = param[0];
|
|
2094
|
+
let match$1 = param[0];
|
|
1914
2095
|
let fields = [
|
|
1915
2096
|
[
|
|
1916
2097
|
"apiEndpoint",
|
|
1917
|
-
match[0]
|
|
2098
|
+
match$1[0]
|
|
1918
2099
|
],
|
|
1919
2100
|
[
|
|
1920
2101
|
"platformApiEndpoint",
|
|
1921
|
-
match[1]
|
|
2102
|
+
match$1[1]
|
|
1922
2103
|
],
|
|
1923
2104
|
[
|
|
1924
2105
|
"region",
|
|
@@ -1930,11 +2111,11 @@ function Make($star) {
|
|
|
1930
2111
|
],
|
|
1931
2112
|
[
|
|
1932
2113
|
"cognitoUserPoolId",
|
|
1933
|
-
match[2]
|
|
2114
|
+
match$1[2]
|
|
1934
2115
|
],
|
|
1935
2116
|
[
|
|
1936
2117
|
"cognitoClientId",
|
|
1937
|
-
match[3]
|
|
2118
|
+
match$1[3]
|
|
1938
2119
|
],
|
|
1939
2120
|
[
|
|
1940
2121
|
"liveUpdates",
|
|
@@ -1963,7 +2144,14 @@ function Make($star) {
|
|
|
1963
2144
|
"uploadEndpoint",
|
|
1964
2145
|
uploadEpOpt
|
|
1965
2146
|
]]) : withGeocoder;
|
|
1966
|
-
|
|
2147
|
+
let withStoreUploads = storeUploadEps.length !== 0 ? withUpload.concat([[
|
|
2148
|
+
"uploadEndpoints",
|
|
2149
|
+
Object.fromEntries(storeUploadEps.map(param => [
|
|
2150
|
+
param[0],
|
|
2151
|
+
param[1]
|
|
2152
|
+
]))
|
|
2153
|
+
]]) : withUpload;
|
|
2154
|
+
return JSON.stringify(Object.fromEntries(withStoreUploads));
|
|
1967
2155
|
});
|
|
1968
2156
|
new (Aws.s3.BucketObject)("host-ui-config-json", {
|
|
1969
2157
|
bucket: bucketName,
|