alchemy 2.0.0-beta.68 → 2.0.0-beta.69
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/bin/exec.js +124 -16
- package/bin/exec.js.map +1 -1
- package/lib/Apply.d.ts.map +1 -1
- package/lib/Apply.js +33 -0
- package/lib/Apply.js.map +1 -1
- package/lib/Cli/LoggingCli.d.ts.map +1 -1
- package/lib/Cli/LoggingCli.js +9 -1
- package/lib/Cli/LoggingCli.js.map +1 -1
- package/lib/Cloudflare/Access/Group.d.ts +11 -2
- package/lib/Cloudflare/Access/Group.d.ts.map +1 -1
- package/lib/Cloudflare/Access/Group.js.map +1 -1
- package/lib/Cloudflare/Access/Policy.d.ts +11 -2
- package/lib/Cloudflare/Access/Policy.d.ts.map +1 -1
- package/lib/Cloudflare/Access/Policy.js.map +1 -1
- package/lib/Cloudflare/Account/Member.d.ts +1 -1
- package/lib/Cloudflare/Account/Member.d.ts.map +1 -1
- package/lib/Cloudflare/Website/StaticSite.d.ts.map +1 -1
- package/lib/Cloudflare/Website/StaticSite.js +8 -1
- package/lib/Cloudflare/Website/StaticSite.js.map +1 -1
- package/lib/Plan.d.ts +23 -4
- package/lib/Plan.d.ts.map +1 -1
- package/lib/Plan.js +226 -22
- package/lib/Plan.js.map +1 -1
- package/lib/Rename.d.ts +132 -0
- package/lib/Rename.d.ts.map +1 -0
- package/lib/Rename.js +117 -0
- package/lib/Rename.js.map +1 -0
- package/lib/Resource.d.ts +9 -0
- package/lib/Resource.d.ts.map +1 -1
- package/lib/Resource.js +11 -0
- package/lib/Resource.js.map +1 -1
- package/lib/State/HttpStateApi.d.ts +14 -14
- package/lib/Sync.d.ts.map +1 -1
- package/lib/Sync.js +1 -0
- package/lib/Sync.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/package.json +4 -4
- package/src/Apply.ts +47 -0
- package/src/Cli/LoggingCli.ts +10 -1
- package/src/Cloudflare/Access/Group.ts +16 -2
- package/src/Cloudflare/Access/Policy.ts +16 -2
- package/src/Cloudflare/Website/StaticSite.ts +8 -1
- package/src/Plan.ts +284 -28
- package/src/Rename.ts +135 -0
- package/src/Resource.ts +27 -0
- package/src/Sync.ts +1 -0
- package/src/index.ts +1 -0
package/bin/exec.js
CHANGED
|
@@ -1610,6 +1610,101 @@ const make = (stack, options$7 = {}) => Effect.gen(function* () {
|
|
|
1610
1610
|
stage: stage$1,
|
|
1611
1611
|
fqn
|
|
1612
1612
|
})), { concurrency: "unbounded" });
|
|
1613
|
+
const persistedRows = new Map(resourceFqns.map((fqn, i) => [fqn, oldResources[i]]));
|
|
1614
|
+
const formerFqnClaims = /* @__PURE__ */ new Map();
|
|
1615
|
+
for (const resource of resources) for (const formerFqn of resource.FormerFqns ?? []) {
|
|
1616
|
+
if (formerFqn === resource.FQN) continue;
|
|
1617
|
+
const claimant = formerFqnClaims.get(formerFqn);
|
|
1618
|
+
if (claimant !== void 0 && claimant !== resource.FQN) return yield* Effect.die(/* @__PURE__ */ new Error(`Resources '${claimant}' and '${resource.FQN}' both claim former FQN '${formerFqn}' via renamedFrom(...). A former FQN can migrate to exactly one resource — remove the decoration from one of them.`));
|
|
1619
|
+
formerFqnClaims.set(formerFqn, resource.FQN);
|
|
1620
|
+
}
|
|
1621
|
+
const renameMigrations = /* @__PURE__ */ new Map();
|
|
1622
|
+
const migratedRowFqns = /* @__PURE__ */ new Set();
|
|
1623
|
+
const resolveRenamer = Effect.fn(function* (resource) {
|
|
1624
|
+
const provider = Option.getOrUndefined(yield* tryFindProviderByType(resource.Type));
|
|
1625
|
+
const allowedTypes = new Set([resource.Type, ...provider?.aliases ?? []]);
|
|
1626
|
+
const persisted = persistedRows.get(resource.FQN);
|
|
1627
|
+
const persistedRow = isActionState(persisted) ? void 0 : persisted;
|
|
1628
|
+
const rowTaken = migratedRowFqns.has(resource.FQN);
|
|
1629
|
+
const ownRow = !rowTaken && persistedRow !== void 0 && allowedTypes.has(persistedRow.resourceType) ? persistedRow : void 0;
|
|
1630
|
+
let source = ownRow;
|
|
1631
|
+
let adopted = ownRow;
|
|
1632
|
+
const renamedFrom = [];
|
|
1633
|
+
for (const formerFqn of resource.FormerFqns) {
|
|
1634
|
+
if (formerFqnClaims.get(formerFqn) !== resource.FQN) continue;
|
|
1635
|
+
if (renamedFrom.includes(formerFqn)) continue;
|
|
1636
|
+
const formerPersisted = persistedRows.get(formerFqn);
|
|
1637
|
+
if (formerPersisted === void 0 || isActionState(formerPersisted)) continue;
|
|
1638
|
+
const formerRow = formerPersisted;
|
|
1639
|
+
if (!allowedTypes.has(formerRow.resourceType)) continue;
|
|
1640
|
+
if (source === void 0) {
|
|
1641
|
+
source = formerRow;
|
|
1642
|
+
adopted = {
|
|
1643
|
+
...formerRow,
|
|
1644
|
+
fqn: resource.FQN,
|
|
1645
|
+
logicalId: resource.LogicalId,
|
|
1646
|
+
namespace: resource.Namespace
|
|
1647
|
+
};
|
|
1648
|
+
renamedFrom.push(formerFqn);
|
|
1649
|
+
} else if (source.instanceId === formerRow.instanceId) renamedFrom.push(formerFqn);
|
|
1650
|
+
}
|
|
1651
|
+
if (renamedFrom.length === 0) return;
|
|
1652
|
+
if (persistedRow !== void 0 && ownRow === void 0 && !rowTaken) return yield* Effect.die(/* @__PURE__ */ new Error(`Cannot migrate '${renamedFrom[0]}' to '${resource.FQN}': a state row of a different type ('${persistedRow.resourceType}') already occupies '${resource.FQN}'. Migrating over it would silently abandon that row's cloud resource. Delete or rename the conflicting resource first, then re-deploy.`));
|
|
1653
|
+
renameMigrations.set(resource.FQN, {
|
|
1654
|
+
row: adopted,
|
|
1655
|
+
renamedFrom,
|
|
1656
|
+
moved: adopted !== ownRow
|
|
1657
|
+
});
|
|
1658
|
+
for (const formerFqn of renamedFrom) migratedRowFqns.add(formerFqn);
|
|
1659
|
+
});
|
|
1660
|
+
let pendingRenamers = resources.filter((r) => r.FormerFqns?.length);
|
|
1661
|
+
const resolvedRenamers = /* @__PURE__ */ new Set();
|
|
1662
|
+
while (pendingRenamers.length > 0) {
|
|
1663
|
+
const ready = pendingRenamers.filter((resource) => {
|
|
1664
|
+
const claimant = formerFqnClaims.get(resource.FQN);
|
|
1665
|
+
return claimant === void 0 || resolvedRenamers.has(claimant);
|
|
1666
|
+
});
|
|
1667
|
+
if (ready.length === 0) return yield* Effect.die(/* @__PURE__ */ new Error(`Rename cycle detected among [${pendingRenamers.map((r) => `'${r.FQN}'`).join(", ")}]: their renamedFrom(...) declarations claim each other's FQNs. Swapping ids in one deploy is not supported — rename through a temporary id across two deploys instead.`));
|
|
1668
|
+
for (const resource of ready) {
|
|
1669
|
+
yield* resolveRenamer(resource);
|
|
1670
|
+
resolvedRenamers.add(resource.FQN);
|
|
1671
|
+
}
|
|
1672
|
+
pendingRenamers = pendingRenamers.filter((r) => !resolvedRenamers.has(r.FQN));
|
|
1673
|
+
}
|
|
1674
|
+
/**
|
|
1675
|
+
* Fetch the persisted row for a declared resource, resolving renames
|
|
1676
|
+
* (see the pre-computed `renameMigrations` above):
|
|
1677
|
+
*
|
|
1678
|
+
* - a renamer plans from its migrated row (`renamedFrom` rides onto
|
|
1679
|
+
* the plan node; apply persists the move before any lifecycle op)
|
|
1680
|
+
* - a resource declared at a former FQN whose row is migrating away
|
|
1681
|
+
* starts from scratch — the row is NOT its state, whatever the FQN
|
|
1682
|
+
* says
|
|
1683
|
+
*/
|
|
1684
|
+
const getPersistedRow = Effect.fn(function* (resource) {
|
|
1685
|
+
const migration = renameMigrations.get(resource.FQN);
|
|
1686
|
+
if (migration !== void 0) return {
|
|
1687
|
+
row: migration.row,
|
|
1688
|
+
renamedFrom: migration.renamedFrom,
|
|
1689
|
+
renameMoved: migration.moved
|
|
1690
|
+
};
|
|
1691
|
+
const persisted = yield* state.get({
|
|
1692
|
+
stack: stackName,
|
|
1693
|
+
stage: stage$1,
|
|
1694
|
+
fqn: resource.FQN
|
|
1695
|
+
});
|
|
1696
|
+
const row = isActionState(persisted) ? void 0 : persisted;
|
|
1697
|
+
if (row !== void 0 && migratedRowFqns.has(resource.FQN)) return {
|
|
1698
|
+
row: void 0,
|
|
1699
|
+
renamedFrom: void 0,
|
|
1700
|
+
renameMoved: false
|
|
1701
|
+
};
|
|
1702
|
+
return {
|
|
1703
|
+
row,
|
|
1704
|
+
renamedFrom: void 0,
|
|
1705
|
+
renameMoved: false
|
|
1706
|
+
};
|
|
1707
|
+
});
|
|
1613
1708
|
const resolvedResources = {};
|
|
1614
1709
|
const resolveResource = (resourceExpr) => Effect.gen(function* () {
|
|
1615
1710
|
if (isAction(resourceExpr.src)) return resourceExpr;
|
|
@@ -1617,12 +1712,7 @@ const make = (stack, options$7 = {}) => Effect.gen(function* () {
|
|
|
1617
1712
|
const resource = resourceExpr.src;
|
|
1618
1713
|
const { provider, mode } = yield* resolveProviderAndMode(resource);
|
|
1619
1714
|
const props = materializeStableRefs(yield* resolveInput(resource.Props));
|
|
1620
|
-
const
|
|
1621
|
-
stack: stackName,
|
|
1622
|
-
stage: stage$1,
|
|
1623
|
-
fqn: resource.FQN
|
|
1624
|
-
});
|
|
1625
|
-
const oldState = isActionState(persisted) ? void 0 : persisted;
|
|
1715
|
+
const { row: oldState } = yield* getPersistedRow(resource);
|
|
1626
1716
|
if (!oldState || oldState.status === "creating") return resourceExpr;
|
|
1627
1717
|
if (hasModeSwitched(mode, oldState)) return resourceExpr;
|
|
1628
1718
|
const oldProps = oldState.status === "updating" ? oldState.old.props : oldState.props;
|
|
@@ -1789,14 +1879,11 @@ const make = (stack, options$7 = {}) => Effect.gen(function* () {
|
|
|
1789
1879
|
const downstream = newDownstreamDependencies[fqn] ?? [];
|
|
1790
1880
|
const applyBindings = dedupeBindings(yield* resolveInput(stack.bindings[fqn] ?? []));
|
|
1791
1881
|
const newBindings = materializeStableRefs(applyBindings);
|
|
1792
|
-
const
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
fqn
|
|
1796
|
-
});
|
|
1797
|
-
let oldState = isActionState(persisted) ? void 0 : persisted;
|
|
1882
|
+
const { row: persistedRow, renamedFrom, renameMoved } = yield* getPersistedRow(resource);
|
|
1883
|
+
let oldState = persistedRow;
|
|
1884
|
+
const reusesMigratedFqn = migratedRowFqns.has(fqn);
|
|
1798
1885
|
let forceUpdateAfterAdoption = false;
|
|
1799
|
-
if (oldState === void 0 && provider.read && isResolved(news)) {
|
|
1886
|
+
if (oldState === void 0 && provider.read && isResolved(news) && !reusesMigratedFqn) {
|
|
1800
1887
|
const adoptInstanceId = yield* generateInstanceId();
|
|
1801
1888
|
const readResult = yield* provider.read({
|
|
1802
1889
|
id,
|
|
@@ -1844,7 +1931,8 @@ const make = (stack, options$7 = {}) => Effect.gen(function* () {
|
|
|
1844
1931
|
resource,
|
|
1845
1932
|
bindings: bindingDiffs,
|
|
1846
1933
|
downstream,
|
|
1847
|
-
mode
|
|
1934
|
+
mode,
|
|
1935
|
+
renamedFrom
|
|
1848
1936
|
});
|
|
1849
1937
|
if (oldState === void 0) return Node({
|
|
1850
1938
|
action: "create",
|
|
@@ -1888,7 +1976,7 @@ const make = (stack, options$7 = {}) => Effect.gen(function* () {
|
|
|
1888
1976
|
news,
|
|
1889
1977
|
oldBindings,
|
|
1890
1978
|
newBindings
|
|
1891
|
-
}).pipe(providePlanScope(fqn, oldState.instanceId))).pipe(Effect.map((diff$1) => diff$1 ?? { action: havePropsChanged(oldProps, news) || bindingDiffs.some((b) => b.action !== "noop") ? "update" : "noop" }), Effect.map((diff$1) => options$7.force && diff$1.action === "noop" ? { action: "update" } : diff$1), Effect.map((diff$1) => forceUpdateAfterAdoption && diff$1.action === "noop" ? { action: "update" } : diff$1));
|
|
1979
|
+
}).pipe(providePlanScope(fqn, oldState.instanceId))).pipe(Effect.map((diff$1) => diff$1 ?? { action: havePropsChanged(oldProps, news) || bindingDiffs.some((b) => b.action !== "noop") ? "update" : "noop" }), Effect.map((diff$1) => options$7.force && diff$1.action === "noop" ? { action: "update" } : diff$1), Effect.map((diff$1) => (forceUpdateAfterAdoption || renameMoved) && diff$1.action === "noop" ? { action: "update" } : diff$1));
|
|
1892
1980
|
if (oldState.status === "creating") if (diff.action === "noop") return Node({
|
|
1893
1981
|
action: "create",
|
|
1894
1982
|
props: applyProps,
|
|
@@ -2086,6 +2174,7 @@ const make = (stack, options$7 = {}) => Effect.gen(function* () {
|
|
|
2086
2174
|
if (isActionState(persisted)) return;
|
|
2087
2175
|
const oldState = persisted;
|
|
2088
2176
|
if (oldState) {
|
|
2177
|
+
if (migratedRowFqns.has(fqn)) return;
|
|
2089
2178
|
const { logicalId } = parseFqn(fqn);
|
|
2090
2179
|
const resourceType = oldState.resourceType;
|
|
2091
2180
|
const providerOption = yield* tryFindProviderByType(resourceType, oldState.providerMode);
|
|
@@ -2107,6 +2196,7 @@ const make = (stack, options$7 = {}) => Effect.gen(function* () {
|
|
|
2107
2196
|
RemovalPolicy: oldState.removalPolicy,
|
|
2108
2197
|
Adopt: void 0,
|
|
2109
2198
|
Mode: oldState.providerMode,
|
|
2199
|
+
FormerFqns: void 0,
|
|
2110
2200
|
RuntimeContext: void 0,
|
|
2111
2201
|
Providers: void 0
|
|
2112
2202
|
},
|
|
@@ -2208,6 +2298,23 @@ const apply = (plan) => Effect.gen(function* () {
|
|
|
2208
2298
|
const stackName = stack.name;
|
|
2209
2299
|
const tracker = {};
|
|
2210
2300
|
const terminalStatuses = /* @__PURE__ */ new Map();
|
|
2301
|
+
const migrationTargets = new Set(Object.values(plan.resources).filter((node) => node.renamedFrom?.length && node.state !== void 0).map((node) => node.resource.FQN));
|
|
2302
|
+
yield* Effect.forEach(Object.values(plan.resources), (node) => {
|
|
2303
|
+
const { renamedFrom, state: row } = node;
|
|
2304
|
+
return renamedFrom === void 0 || renamedFrom.length === 0 || row === void 0 ? Effect.void : Effect.gen(function* () {
|
|
2305
|
+
yield* state.set({
|
|
2306
|
+
stack: stackName,
|
|
2307
|
+
stage: stage$1,
|
|
2308
|
+
fqn: node.resource.FQN,
|
|
2309
|
+
value: row
|
|
2310
|
+
});
|
|
2311
|
+
yield* Effect.forEach(renamedFrom.filter((formerFqn) => !migrationTargets.has(formerFqn)), (formerFqn) => state.delete({
|
|
2312
|
+
stack: stackName,
|
|
2313
|
+
stage: stage$1,
|
|
2314
|
+
fqn: formerFqn
|
|
2315
|
+
}), { concurrency: "unbounded" });
|
|
2316
|
+
});
|
|
2317
|
+
}, { concurrency: "unbounded" });
|
|
2211
2318
|
yield* executePlan(plan, tracker, terminalStatuses, session, state, stackName, stage$1);
|
|
2212
2319
|
yield* collectGarbage(plan, session);
|
|
2213
2320
|
yield* converge(plan, tracker, terminalStatuses, session, state, stackName, stage$1);
|
|
@@ -5523,7 +5630,8 @@ const formatPlanLines = (plan) => {
|
|
|
5523
5630
|
priorMode: item.action === "replace" ? item.state.providerMode : void 0,
|
|
5524
5631
|
defaultMode: plan.defaultMode
|
|
5525
5632
|
});
|
|
5526
|
-
|
|
5633
|
+
const renamed = item.action !== "delete" && item.renamedFrom?.length ? ` ${dim(`(renamed from ${item.renamedFrom.join(", ")})`)}` : "";
|
|
5634
|
+
lines.push(`${tag(item.resource.LogicalId)} ${action}${mode}${renamed}`);
|
|
5527
5635
|
for (const binding of item.bindings) {
|
|
5528
5636
|
if (binding.action === "noop") continue;
|
|
5529
5637
|
const bindingAction = actionColor$1[binding.action](binding.action);
|