@bedrock-rbx/core 0.1.0-beta.13 → 0.1.0-beta.14

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/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as UniverseOverlayWithoutId, D as ConfigValidationIssue, E as ConfigError, S as UniverseOverlayWithId, T as validateConfig, _ as ResolvedPlaceEntry, a as ConfigEnvironmentUniverseId, b as StateConfig, c as DisplayNamePrefixConfig, d as GistStateConfig, f as PlaceEntry, g as ResolvedConfig, h as RedactedPlaceOverride, i as Config, l as EnvironmentEntry, m as RedactedGamePassOverride, n as ConfigInput, o as ConfigRootUniverseId, p as RedactedDeveloperProductOverride, r as defineConfig, s as DeveloperProductEntry, t as ConfigContext, u as GamePassEntry, v as ResolvedUniverseEntry, w as isGistStateConfig, x as UniverseEntry, y as ResourceEntryByKind } from "./define-config-Bd0XIiSX.mjs";
1
+ import { C as UniverseOverlayWithId, D as ConfigError, E as validateConfig, O as ConfigValidationIssue, S as UniverseEntry, T as isGistStateConfig, _ as ResolvedConfig, a as ConfigEnvironmentUniverseId, b as ResourceEntryByKind, c as DisplayNamePrefixConfig, d as GistStateConfig, f as PlaceEntry, g as RedactedPlaceOverride, h as RedactedGamePassOverride, i as Config, l as EnvironmentEntry, m as RedactedEnvironmentOverride, n as ConfigInput, o as ConfigRootUniverseId, p as RedactedDeveloperProductOverride, r as defineConfig, s as DeveloperProductEntry, t as ConfigContext, u as GamePassEntry, v as ResolvedPlaceEntry, w as UniverseOverlayWithoutId, x as StateConfig, y as ResolvedUniverseEntry } from "./define-config-C2cOtDpP.mjs";
2
2
  import { OpenCloudError, OpenCloudError as OpenCloudError$1, Result, Result as Result$1 } from "@bedrock-rbx/ocale";
3
3
  import { Type as Type$1 } from "arktype";
4
4
  import { DeveloperProductsClient } from "@bedrock-rbx/ocale/developer-products";
@@ -1329,127 +1329,6 @@ type SelectEnvironmentError = IncompletePassEntryError | IncompletePlaceEntryErr
1329
1329
  */
1330
1330
  declare function selectEnvironment(config: Config, environment: string): Result$1<ResolvedConfig, SelectEnvironmentError>;
1331
1331
  //#endregion
1332
- //#region src/ports/resource-driver.d.ts
1333
- /**
1334
- * Plugin contract for a resource adapter: the interface a third-party author
1335
- * implements to teach Bedrock how to reconcile one {@link ResourceKind} against
1336
- * its upstream API.
1337
- *
1338
- * `ResourceDriver<K>` is a *driven* (secondary) port in hexagonal terms; the
1339
- * name "driver" follows Terraform, Pulumi, and Mantle IaC convention for a
1340
- * component that talks to a specific resource API.
1341
- *
1342
- * @template K - The {@link ResourceKind} discriminator this driver handles.
1343
- *
1344
- * @example
1345
- *
1346
- * ```ts
1347
- * import {
1348
- * asResourceKey,
1349
- * asRobloxAssetId,
1350
- * asSha256Hex,
1351
- * type ResourceDriver,
1352
- * } from "@bedrock-rbx/core";
1353
- *
1354
- * const gamePassDriver: ResourceDriver<"gamePass"> = {
1355
- * async create(desired) {
1356
- * return {
1357
- * data: {
1358
- * ...desired,
1359
- * outputs: {
1360
- * assetId: asRobloxAssetId("9876543210"),
1361
- * iconAssetIds: { "en-us": asRobloxAssetId("1122334455") },
1362
- * },
1363
- * },
1364
- * success: true,
1365
- * };
1366
- * },
1367
- * };
1368
- *
1369
- * return gamePassDriver
1370
- * .create({
1371
- * description: "Grants VIP perks.",
1372
- * icon: { "en-us": "assets/vip-icon.png" },
1373
- * iconFileHashes: {
1374
- * "en-us": asSha256Hex(
1375
- * "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
1376
- * ),
1377
- * },
1378
- * key: asResourceKey("vip-pass"),
1379
- * kind: "gamePass",
1380
- * name: "VIP Pass",
1381
- * price: undefined,
1382
- * })
1383
- * .then((result) => {
1384
- * expect(result.success).toBeTrue();
1385
- * if (result.success) {
1386
- * expect(result.data.outputs.assetId).toBe("9876543210");
1387
- * }
1388
- * });
1389
- * ```
1390
- */
1391
- interface ResourceDriver<K extends ResourceKind> {
1392
- /**
1393
- * Create the resource upstream from its desired state and return the
1394
- * resulting current state (desired fields + Roblox-assigned outputs).
1395
- */
1396
- create(desired: Extract<ResourceDesiredState, {
1397
- kind: K;
1398
- }>): Promise<Result$1<ResourceCurrentState<K>, OpenCloudError$1>>;
1399
- /**
1400
- * Reconcile an upstream resource whose managed content has drifted from its
1401
- * desired state. Receives the last-known current state so the driver can
1402
- * compute a minimal patch (or no-op upstream, for file-backed kinds where
1403
- * republishing is unconditional).
1404
- *
1405
- * Optional. Drivers whose upstream API has no update operation omit this
1406
- * method; `applyOps` surfaces an `updateUnsupported` error at dispatch time
1407
- * instead.
1408
- */
1409
- update?(current: ResourceCurrentState<K>, desired: Extract<ResourceDesiredState, {
1410
- kind: K;
1411
- }>): Promise<Result$1<ResourceCurrentState<K>, OpenCloudError$1>>;
1412
- }
1413
- /**
1414
- * Polymorphic dispatch table keyed by {@link ResourceKind}, mapping each kind
1415
- * to the {@link ResourceDriver} that handles it. `applyOps` indexes the
1416
- * registry by `op.desired.kind` to reach the matching driver with full type
1417
- * safety: adding a new kind to `ResourceDesiredState` is a compile error until
1418
- * a matching registry entry is supplied.
1419
- *
1420
- * @example
1421
- *
1422
- * ```ts
1423
- * import { OpenCloudError, type DriverRegistry } from "@bedrock-rbx/core";
1424
- *
1425
- * const registry: DriverRegistry = {
1426
- * gamePass: {
1427
- * async create() {
1428
- * return { err: new OpenCloudError("not implemented"), success: false };
1429
- * },
1430
- * },
1431
- * place: {
1432
- * async create() {
1433
- * return { err: new OpenCloudError("not implemented"), success: false };
1434
- * },
1435
- * },
1436
- * universe: {
1437
- * async create() {
1438
- * return { err: new OpenCloudError("not implemented"), success: false };
1439
- * },
1440
- * },
1441
- * developerProduct: {
1442
- * async create() {
1443
- * return { err: new OpenCloudError("not implemented"), success: false };
1444
- * },
1445
- * },
1446
- * };
1447
- *
1448
- * expect(registry.gamePass).toBeObject();
1449
- * ```
1450
- */
1451
- type DriverRegistry = { [K in ResourceKind]: ResourceDriver<K> };
1452
- //#endregion
1453
1332
  //#region src/core/operations.d.ts
1454
1333
  /**
1455
1334
  * Fields shared by every operation variant.
@@ -1561,11 +1440,13 @@ interface CreateOperation extends BaseOperation {
1561
1440
  * name: "VIP Pass",
1562
1441
  * price: 750,
1563
1442
  * },
1443
+ * changedFields: ["description", "price"],
1564
1444
  * key: asResourceKey("vip-pass"),
1565
1445
  * type: "update",
1566
1446
  * };
1567
1447
  *
1568
1448
  * expect(op.type).toBe("update");
1449
+ * expect(op.changedFields).toStrictEqual(["description", "price"]);
1569
1450
  * if (op.desired.kind === "gamePass") {
1570
1451
  * expect(op.desired.price).toBe(750);
1571
1452
  * }
@@ -1575,6 +1456,13 @@ interface CreateOperation extends BaseOperation {
1575
1456
  * ```
1576
1457
  */
1577
1458
  interface UpdateOperation extends BaseOperation {
1459
+ /**
1460
+ * Top-level field names that differ between `current` and `desired`,
1461
+ * populated by `diff` from the kind module's `changedFieldsBetween`.
1462
+ * Plan and apply renderers consume this as the single source of truth
1463
+ * for "what changed" on this op; never empty for an `update` variant.
1464
+ */
1465
+ readonly changedFields: ReadonlyArray<string>;
1578
1466
  /** Last-known live state; the driver computes a patch against `desired`. */
1579
1467
  readonly current: ResourceCurrentState;
1580
1468
  /** Declared desired state to converge toward. */
@@ -1587,9 +1475,9 @@ interface UpdateOperation extends BaseOperation {
1587
1475
  * entry matches its `current` entry exactly. The driver performs no I/O for
1588
1476
  * this variant.
1589
1477
  *
1590
- * Bare by design: the operation carries only `key` and `type` because no
1591
- * payload is needed at apply time. Callers that need the matching desired or
1592
- * current state look it up in the snapshots passed to `diff`.
1478
+ * Carries `key` and `kind` so progress renderers and adapters can describe the
1479
+ * unchanged resource without re-looking it up in the desired or current
1480
+ * snapshots passed to `diff`.
1593
1481
  *
1594
1482
  * @example
1595
1483
  *
@@ -1598,14 +1486,18 @@ interface UpdateOperation extends BaseOperation {
1598
1486
  *
1599
1487
  * const op: NoopOperation = {
1600
1488
  * key: asResourceKey("vip-pass"),
1489
+ * kind: "gamePass",
1601
1490
  * type: "noop",
1602
1491
  * };
1603
1492
  *
1604
1493
  * expect(op.type).toBe("noop");
1494
+ * expect(op.kind).toBe("gamePass");
1605
1495
  * expect(op.key).toBe("vip-pass");
1606
1496
  * ```
1607
1497
  */
1608
1498
  interface NoopOperation extends BaseOperation {
1499
+ /** Resource-kind discriminator copied from the matching desired/current entry. */
1500
+ readonly kind: ResourceKind;
1609
1501
  /** Discriminator tag for the `Operation` union. */
1610
1502
  readonly type: "noop";
1611
1503
  }
@@ -1638,6 +1530,7 @@ interface NoopOperation extends BaseOperation {
1638
1530
  *
1639
1531
  * const op: Operation = {
1640
1532
  * key: asResourceKey("vip-pass"),
1533
+ * kind: "gamePass",
1641
1534
  * type: "noop",
1642
1535
  * };
1643
1536
  *
@@ -1646,15 +1539,145 @@ interface NoopOperation extends BaseOperation {
1646
1539
  */
1647
1540
  type Operation = CreateOperation | NoopOperation | UpdateOperation;
1648
1541
  //#endregion
1542
+ //#region src/ports/resource-driver.d.ts
1543
+ /**
1544
+ * Plugin contract for a resource adapter: the interface a third-party author
1545
+ * implements to teach Bedrock how to reconcile one {@link ResourceKind} against
1546
+ * its upstream API.
1547
+ *
1548
+ * `ResourceDriver<K>` is a *driven* (secondary) port in hexagonal terms; the
1549
+ * name "driver" follows Terraform, Pulumi, and Mantle IaC convention for a
1550
+ * component that talks to a specific resource API.
1551
+ *
1552
+ * @template K - The {@link ResourceKind} discriminator this driver handles.
1553
+ *
1554
+ * @example
1555
+ *
1556
+ * ```ts
1557
+ * import {
1558
+ * asResourceKey,
1559
+ * asRobloxAssetId,
1560
+ * asSha256Hex,
1561
+ * type ResourceDriver,
1562
+ * } from "@bedrock-rbx/core";
1563
+ *
1564
+ * const gamePassDriver: ResourceDriver<"gamePass"> = {
1565
+ * async create(desired) {
1566
+ * return {
1567
+ * data: {
1568
+ * ...desired,
1569
+ * outputs: {
1570
+ * assetId: asRobloxAssetId("9876543210"),
1571
+ * iconAssetIds: { "en-us": asRobloxAssetId("1122334455") },
1572
+ * },
1573
+ * },
1574
+ * success: true,
1575
+ * };
1576
+ * },
1577
+ * };
1578
+ *
1579
+ * return gamePassDriver
1580
+ * .create({
1581
+ * description: "Grants VIP perks.",
1582
+ * icon: { "en-us": "assets/vip-icon.png" },
1583
+ * iconFileHashes: {
1584
+ * "en-us": asSha256Hex(
1585
+ * "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
1586
+ * ),
1587
+ * },
1588
+ * key: asResourceKey("vip-pass"),
1589
+ * kind: "gamePass",
1590
+ * name: "VIP Pass",
1591
+ * price: undefined,
1592
+ * })
1593
+ * .then((result) => {
1594
+ * expect(result.success).toBeTrue();
1595
+ * if (result.success) {
1596
+ * expect(result.data.outputs.assetId).toBe("9876543210");
1597
+ * }
1598
+ * });
1599
+ * ```
1600
+ */
1601
+ interface ResourceDriver<K extends ResourceKind> {
1602
+ /**
1603
+ * Create the resource upstream from its desired state and return the
1604
+ * resulting current state (desired fields + Roblox-assigned outputs).
1605
+ */
1606
+ create(desired: Extract<ResourceDesiredState, {
1607
+ kind: K;
1608
+ }>): Promise<Result$1<ResourceCurrentState<K>, OpenCloudError$1>>;
1609
+ /**
1610
+ * Reconcile an upstream resource whose managed content has drifted from its
1611
+ * desired state. Receives the last-known current state so the driver can
1612
+ * compute a minimal patch (or no-op upstream, for file-backed kinds where
1613
+ * republishing is unconditional).
1614
+ *
1615
+ * Optional. Drivers whose upstream API has no update operation omit this
1616
+ * method; `applyOps` surfaces an `updateUnsupported` error at dispatch time
1617
+ * instead.
1618
+ */
1619
+ update?(current: ResourceCurrentState<K>, desired: Extract<ResourceDesiredState, {
1620
+ kind: K;
1621
+ }>): Promise<Result$1<ResourceCurrentState<K>, OpenCloudError$1>>;
1622
+ }
1623
+ /**
1624
+ * Polymorphic dispatch table keyed by {@link ResourceKind}, mapping each kind
1625
+ * to the {@link ResourceDriver} that handles it. `applyOps` indexes the
1626
+ * registry by `op.desired.kind` to reach the matching driver with full type
1627
+ * safety: adding a new kind to `ResourceDesiredState` is a compile error until
1628
+ * a matching registry entry is supplied.
1629
+ *
1630
+ * @example
1631
+ *
1632
+ * ```ts
1633
+ * import { OpenCloudError, type DriverRegistry } from "@bedrock-rbx/core";
1634
+ *
1635
+ * const registry: DriverRegistry = {
1636
+ * gamePass: {
1637
+ * async create() {
1638
+ * return { err: new OpenCloudError("not implemented"), success: false };
1639
+ * },
1640
+ * },
1641
+ * place: {
1642
+ * async create() {
1643
+ * return { err: new OpenCloudError("not implemented"), success: false };
1644
+ * },
1645
+ * },
1646
+ * universe: {
1647
+ * async create() {
1648
+ * return { err: new OpenCloudError("not implemented"), success: false };
1649
+ * },
1650
+ * },
1651
+ * developerProduct: {
1652
+ * async create() {
1653
+ * return { err: new OpenCloudError("not implemented"), success: false };
1654
+ * },
1655
+ * },
1656
+ * };
1657
+ *
1658
+ * expect(registry.gamePass).toBeObject();
1659
+ * ```
1660
+ */
1661
+ type DriverRegistry = { [K in ResourceKind]: ResourceDriver<K> };
1662
+ //#endregion
1649
1663
  //#region src/shell/apply-ops.d.ts
1650
1664
  /**
1665
+ * Optional wiring `applyOps` uses to emit per-resource and aggregate progress
1666
+ * events. When omitted, `applyOps` runs silently (backward-compatible with
1667
+ * pre-progress callers).
1668
+ */
1669
+ interface ApplyOpsReporting {
1670
+ /** Environment name stamped on every emitted event. */
1671
+ readonly environment: string;
1672
+ /** Sink the apply pipeline pushes events into. */
1673
+ readonly progress: ProgressPort;
1674
+ }
1675
+ /**
1651
1676
  * Failure surfaced by `applyOps` when an operation cannot be applied.
1652
1677
  * Plain-data discriminated union; narrow on `kind`, do not `instanceof` it.
1653
- *
1654
- * `appliedSoFar` carries the driver outputs from operations that succeeded
1655
- * before the failing one, in dispatched order. Callers persist this so a
1656
- * follow-up reconcile does not duplicate Roblox-side resources that have
1657
- * already been created or updated.
1678
+ * One `ApplyError` describes one failing op; the surrounding
1679
+ * `AggregateApplyError` carries the full batch outcome (every survivor and
1680
+ * every failure).
1658
1681
  *
1659
1682
  * @example
1660
1683
  *
@@ -1666,6 +1689,9 @@ type Operation = CreateOperation | NoopOperation | UpdateOperation;
1666
1689
  * case "driverFailure": {
1667
1690
  * return `driver failed for ${err.key}: ${err.cause.message}`;
1668
1691
  * }
1692
+ * case "unexpectedThrow": {
1693
+ * return `unexpected error for ${err.key}`;
1694
+ * }
1669
1695
  * case "updateUnsupported": {
1670
1696
  * return `update not supported for ${err.key}`;
1671
1697
  * }
@@ -1674,7 +1700,6 @@ type Operation = CreateOperation | NoopOperation | UpdateOperation;
1674
1700
  *
1675
1701
  * const err: ApplyError = {
1676
1702
  * key: asResourceKey("vip-pass"),
1677
- * appliedSoFar: [],
1678
1703
  * kind: "updateUnsupported",
1679
1704
  * };
1680
1705
  *
@@ -1682,126 +1707,290 @@ type Operation = CreateOperation | NoopOperation | UpdateOperation;
1682
1707
  * ```
1683
1708
  */
1684
1709
  type ApplyError = {
1685
- readonly appliedSoFar: ReadonlyArray<ResourceCurrentState>;
1686
1710
  readonly cause: OpenCloudError$1;
1687
1711
  readonly key: ResourceKey;
1688
1712
  readonly kind: "driverFailure";
1689
1713
  } | {
1690
- readonly appliedSoFar: ReadonlyArray<ResourceCurrentState>;
1714
+ readonly cause: unknown;
1715
+ readonly key: ResourceKey;
1716
+ readonly kind: "unexpectedThrow";
1717
+ } | {
1691
1718
  readonly key: ResourceKey;
1692
1719
  readonly kind: "updateUnsupported";
1693
1720
  };
1694
1721
  /**
1695
- * Dispatch each reconciliation operation to the matching resource driver
1696
- * with first-fail semantics: on the first `Err` (driver failure or
1697
- * `updateUnsupported`), the remaining operations are skipped and the error
1698
- * is returned verbatim.
1722
+ * Aggregate outcome returned by `applyOps` when one or more ops fail.
1723
+ * `applied` is the survivor set in Phase 1 then Phase 2 input order.
1724
+ * `failures` is the non-empty list of `ApplyError`s, one per failing op,
1725
+ * grouped the same way.
1726
+ *
1727
+ * @example
1728
+ *
1729
+ * ```ts
1730
+ * import { asResourceKey, type AggregateApplyError } from "@bedrock-rbx/core";
1731
+ *
1732
+ * function summarize(err: AggregateApplyError): string {
1733
+ * return `${err.applied.length} survived, ${err.failures.length} failed`;
1734
+ * }
1735
+ *
1736
+ * const err: AggregateApplyError = {
1737
+ * applied: [],
1738
+ * failures: [{ key: asResourceKey("vip-pass"), kind: "updateUnsupported" }],
1739
+ * };
1740
+ *
1741
+ * expect(summarize(err)).toBe("0 survived, 1 failed");
1742
+ * ```
1743
+ */
1744
+ interface AggregateApplyError {
1745
+ /** Survivors persisted to state, in Phase 1 then Phase 2 input order. */
1746
+ readonly applied: ReadonlyArray<ResourceCurrentState>;
1747
+ /** Per-op failures, at least one, in Phase 1 then Phase 2 input order. */
1748
+ readonly failures: readonly [ApplyError, ...ReadonlyArray<ApplyError>];
1749
+ }
1750
+ /**
1751
+ * Dispatch reconciliation operations to their matching drivers in two phases
1752
+ * with continue-on-failure semantics. Phase 1 runs universe ops sequentially
1753
+ * (singleton per environment; sequencing it before everything else avoids the
1754
+ * `displayName` race against the root `Place`). Phase 2 dispatches every
1755
+ * remaining non-noop op concurrently via `Promise.all`; every op is
1756
+ * attempted regardless of earlier failures.
1699
1757
  *
1700
1758
  * Behaviour:
1701
- * - `create` operations are routed to `registry[op.desired.kind].create`.
1702
- * - `update` operations are routed to `registry[op.desired.kind].update`
1703
- * when the driver exposes it; otherwise they short-circuit to an
1704
- * `updateUnsupported` Err without invoking the driver.
1759
+ * - `create` operations route to `registry[op.desired.kind].create`.
1760
+ * - `update` operations route to `registry[op.desired.kind].update` when the
1761
+ * driver exposes it; otherwise they yield an `updateUnsupported`
1762
+ * `ApplyError` without invoking the driver.
1705
1763
  * - `noop` operations are skipped entirely (no I/O, no dispatch).
1764
+ * - A driver that throws outside its `Result` contract is caught at the
1765
+ * dispatch boundary and translated to an `unexpectedThrow` `ApplyError`
1766
+ * scoped to that op alone; the rest of the batch keeps running.
1767
+ *
1768
+ * On Ok the returned array carries driver outputs for every non-noop op
1769
+ * in phase order: Phase 1 universe entries first, then Phase 2 entries in
1770
+ * their input order. Noops are not represented; callers needing a full
1771
+ * post-apply snapshot merge with the pre-apply current state keyed by
1772
+ * `ResourceKey`.
1773
+ *
1774
+ * On Err the aggregate carries every survivor in `applied` (Phase 1 first,
1775
+ * then Phase 2 input order) and every failure in `failures` with the same
1776
+ * grouping. Neither array reflects completion order.
1777
+ *
1778
+ * @param ops - Reconciliation operations produced by `diff`, applied in
1779
+ * declaration order.
1780
+ * @param registry - Per-kind driver table; dispatch uses `op.desired.kind`
1781
+ * as the index.
1782
+ * @param reporting - Optional progress wiring. When supplied, `applyOps`
1783
+ * emits one `resourceOpStarted` and one terminal event per non-noop op,
1784
+ * one `resourceOpNoop` per noop op, and a final `applySummary` carrying
1785
+ * the per-type counts and the wall-clock apply duration. When omitted,
1786
+ * no events fire.
1787
+ * @returns `Ok(state)` when every op succeeded; otherwise
1788
+ * `Err(AggregateApplyError)` with the survivors and the non-empty
1789
+ * failures tuple.
1790
+ * @example
1791
+ *
1792
+ * ```ts
1793
+ * import { applyOps, type DriverRegistry } from "@bedrock-rbx/core";
1794
+ *
1795
+ * const noopRegistry: DriverRegistry = {
1796
+ * developerProduct: { create: async () => ({ err: new Error("stub") as never, success: false }) },
1797
+ * gamePass: { create: async () => ({ err: new Error("stub") as never, success: false }) },
1798
+ * place: { create: async () => ({ err: new Error("stub") as never, success: false }) },
1799
+ * universe: { create: async () => ({ err: new Error("stub") as never, success: false }) },
1800
+ * };
1801
+ *
1802
+ * return applyOps([], noopRegistry).then((result) => {
1803
+ * expect(result).toStrictEqual({ data: [], success: true });
1804
+ * });
1805
+ * ```
1806
+ */
1807
+ declare function applyOps(ops: ReadonlyArray<Operation>, registry: DriverRegistry, reporting?: ApplyOpsReporting): Promise<Result$1<ReadonlyArray<ResourceCurrentState>, AggregateApplyError>>;
1808
+ //#endregion
1809
+ //#region src/ports/progress-port.d.ts
1810
+ /**
1811
+ * Per-environment outcome event emitted after a deploy completes
1812
+ * successfully. Carries the environment name and the count of resources
1813
+ * present in the persisted state snapshot.
1814
+ */
1815
+ interface DeploySuccessEvent {
1816
+ /** The environment that finished reconciling. */
1817
+ readonly environment: string;
1818
+ /** Discriminator tag. */
1819
+ readonly kind: "deploySuccess";
1820
+ /** Number of resources in the post-deploy state snapshot. */
1821
+ readonly resourceCount: number;
1822
+ }
1823
+ /**
1824
+ * Per-environment outcome event emitted when a deploy fails. Carries the
1825
+ * environment name and the full {@link DeployError} so a renderer can
1826
+ * delegate to the existing diagnostic helpers.
1827
+ */
1828
+ interface DeployFailureEvent {
1829
+ /** The environment whose deploy failed. */
1830
+ readonly environment: string;
1831
+ /** Stage-tagged failure reason returned by the shell `deploy` function. */
1832
+ readonly error: DeployError;
1833
+ /** Discriminator tag. */
1834
+ readonly kind: "deployFailure";
1835
+ }
1836
+ /**
1837
+ * Per-resource event emitted immediately before `applyOps` dispatches a
1838
+ * non-noop op to its driver. Adapters may render a "starting" line or
1839
+ * stay silent; the matching terminal event ({@link ResourceOpSucceededEvent}
1840
+ * or {@link ResourceOpFailedEvent}) fires when the driver settles.
1841
+ */
1842
+ interface ResourceOpStartedEvent {
1843
+ /** User-supplied resource key. */
1844
+ readonly key: ResourceKey;
1845
+ /** Environment whose reconcile is running. */
1846
+ readonly environment: string;
1847
+ /** Discriminator tag. */
1848
+ readonly kind: "resourceOpStarted";
1849
+ /** Operation type being dispatched. Noops never fire this event. */
1850
+ readonly opType: "create" | "update";
1851
+ /** Resource-kind discriminator (`gamePass`, `place`, ...). */
1852
+ readonly resourceKind: ResourceKind;
1853
+ }
1854
+ /**
1855
+ * Terminal event for a successful create op. The `resourceKind` discriminator
1856
+ * narrows `outputs` to the matching `ResourceOutputs<K>` shape so renderers
1857
+ * can read Roblox-assigned IDs without casts.
1858
+ */
1859
+ type ResourceOpSucceededCreateEvent = { [K in ResourceKind]: Readonly<{
1860
+ environment: string;
1861
+ key: ResourceKey;
1862
+ kind: "resourceOpSucceeded";
1863
+ opType: "create";
1864
+ outputs: ResourceOutputs<K>;
1865
+ resourceKind: K;
1866
+ }> }[ResourceKind];
1867
+ /**
1868
+ * Terminal event for a successful update op. Carries the list of top-level
1869
+ * fields the diff flagged as changed so renderers can attribute the update.
1870
+ */
1871
+ interface ResourceOpSucceededUpdateEvent {
1872
+ /** User-supplied resource key. */
1873
+ readonly key: ResourceKey;
1874
+ /** Top-level field names whose values differed between desired and current. */
1875
+ readonly changedFields: ReadonlyArray<string>;
1876
+ /** Environment whose reconcile is running. */
1877
+ readonly environment: string;
1878
+ /** Discriminator tag. */
1879
+ readonly kind: "resourceOpSucceeded";
1880
+ /** Operation type. */
1881
+ readonly opType: "update";
1882
+ /** Resource-kind discriminator. */
1883
+ readonly resourceKind: ResourceKind;
1884
+ }
1885
+ /**
1886
+ * Terminal event for a successful non-noop op. Sub-discriminated by `opType`
1887
+ * so a renderer can extract `outputs` (creates) or `changedFields` (updates)
1888
+ * without losing type narrowing.
1889
+ */
1890
+ type ResourceOpSucceededEvent = ResourceOpSucceededCreateEvent | ResourceOpSucceededUpdateEvent;
1891
+ /**
1892
+ * Per-resource event emitted for each op the diff produced as a noop.
1893
+ * Noops never fire a `started`/terminal pair; this single event stands in
1894
+ * for the entire op so adapters can render a "unchanged" line.
1895
+ */
1896
+ interface ResourceOpNoopEvent {
1897
+ /** User-supplied resource key. */
1898
+ readonly key: ResourceKey;
1899
+ /** Environment whose reconcile is running. */
1900
+ readonly environment: string;
1901
+ /** Discriminator tag. */
1902
+ readonly kind: "resourceOpNoop";
1903
+ /** Resource-kind discriminator. */
1904
+ readonly resourceKind: ResourceKind;
1905
+ }
1906
+ /**
1907
+ * Terminal event for a failed non-noop op. Carries the {@link ApplyError}
1908
+ * so a renderer can delegate to the existing apply-cause diagnostic helper.
1909
+ */
1910
+ interface ResourceOpFailedEvent {
1911
+ /** User-supplied resource key. */
1912
+ readonly key: ResourceKey;
1913
+ /** Environment whose reconcile is running. */
1914
+ readonly environment: string;
1915
+ /** Apply error returned by `dispatchOp`. */
1916
+ readonly error: ApplyError;
1917
+ /** Discriminator tag. */
1918
+ readonly kind: "resourceOpFailed";
1919
+ /** Operation type that was being attempted. */
1920
+ readonly opType: "create" | "update";
1921
+ /** Resource-kind discriminator. */
1922
+ readonly resourceKind: ResourceKind;
1923
+ }
1924
+ /**
1925
+ * Aggregate footer event emitted after `applyOps` finishes (Phase 2 settled).
1926
+ * Fires unconditionally, including on partial failure; `durationMs` measures
1927
+ * apply time only (state-write time excluded).
1928
+ */
1929
+ interface ApplySummaryEvent {
1930
+ /** Count of successful create ops. */
1931
+ readonly created: number;
1932
+ /** Wall-clock duration between `applyOps` entry and Phase 2 resolution, in milliseconds. */
1933
+ readonly durationMs: number;
1934
+ /** Environment whose reconcile is running. */
1935
+ readonly environment: string;
1936
+ /** Count of failed ops (any opType). */
1937
+ readonly failed: number;
1938
+ /** Discriminator tag. */
1939
+ readonly kind: "applySummary";
1940
+ /** Count of noop ops. */
1941
+ readonly noop: number;
1942
+ /** Count of successful update ops. */
1943
+ readonly updated: number;
1944
+ }
1945
+ /**
1946
+ * Per-environment event emitted after `statePort.write` returns `Ok`.
1947
+ * Not emitted on write failure: the existing `deployFailure` event with
1948
+ * `kind: "stateWriteFailed"` runs the existing failure flow. The payload
1949
+ * carries no backend identity; renderers read the backend label from the
1950
+ * project config when constructing the rendered line.
1951
+ */
1952
+ interface StateWrittenEvent {
1953
+ /** Environment whose state snapshot was just persisted. */
1954
+ readonly environment: string;
1955
+ /** Discriminator tag. */
1956
+ readonly kind: "stateWritten";
1957
+ }
1958
+ /**
1959
+ * Discriminated union of progress events the CLI emits while a deploy
1960
+ * runs. The variant set is additive: future per-stage and per-resource
1961
+ * events land as new `kind` values without breaking existing adapters.
1962
+ */
1963
+ type ProgressEvent = ApplySummaryEvent | DeployFailureEvent | DeploySuccessEvent | ResourceOpFailedEvent | ResourceOpNoopEvent | ResourceOpStartedEvent | ResourceOpSucceededEvent | StateWrittenEvent;
1964
+ /**
1965
+ * Plugin contract for receiving deploy outcomes: the interface an adapter
1966
+ * (clack renderer, JSON logger, custom UI) implements to let the CLI hand
1967
+ * off events without re-implementing rendering logic.
1706
1968
  *
1707
- * On success the returned array carries the driver outputs for every
1708
- * non-noop op, in dispatched order. Noops are not represented; callers
1709
- * needing a full post-apply snapshot merge with the pre-apply current
1710
- * state keyed by `ResourceKey`.
1969
+ * `ProgressPort` is a *driven* (secondary) port in hexagonal terms.
1711
1970
  *
1712
- * @param ops - Reconciliation operations produced by `diff`, applied in order.
1713
- * @param registry - Per-kind driver table; dispatch uses `op.desired.kind` as the index.
1714
- * @returns `Ok(state)` when every operation succeeds, where `state` holds
1715
- * driver outputs for each non-noop op in dispatched order; or the first
1716
- * failure encountered.
1717
- * @throws Whatever the dispatched driver rejects with outside its `Result`
1718
- * return. A driver whose injected I/O (file reads, network calls, etc.)
1719
- * throws will surface that rejection here rather than translating it into
1720
- * a `Result` failure; wrap the call site in a try/catch when drivers are
1721
- * not trusted to contain their own rejections.
1722
1971
  * @example
1723
1972
  *
1724
1973
  * ```ts
1725
- * import {
1726
- * applyOps,
1727
- * asResourceKey,
1728
- * asRobloxAssetId,
1729
- * asSha256Hex,
1730
- * type DriverRegistry,
1731
- * type Operation,
1732
- * } from "@bedrock-rbx/core";
1974
+ * import type { ProgressEvent, ProgressPort } from "@bedrock-rbx/core";
1733
1975
  *
1734
- * const registry: DriverRegistry = {
1735
- * gamePass: {
1736
- * async create(desired) {
1737
- * return {
1738
- * data: {
1739
- * ...desired,
1740
- * outputs: {
1741
- * assetId: asRobloxAssetId("9876543210"),
1742
- * iconAssetIds: { "en-us": asRobloxAssetId("1122334455") },
1743
- * },
1744
- * },
1745
- * success: true,
1746
- * };
1747
- * },
1748
- * },
1749
- * place: {
1750
- * async create(desired) {
1751
- * return {
1752
- * data: { ...desired, outputs: { versionNumber: 1 } },
1753
- * success: true,
1754
- * };
1755
- * },
1756
- * },
1757
- * universe: {
1758
- * async create(desired) {
1759
- * return {
1760
- * data: { ...desired, outputs: { rootPlaceId: asRobloxAssetId("4711") } },
1761
- * success: true,
1762
- * };
1763
- * },
1764
- * },
1765
- * developerProduct: {
1766
- * async create(desired) {
1767
- * return {
1768
- * data: {
1769
- * ...desired,
1770
- * outputs: { productId: asRobloxAssetId("8172635495") },
1771
- * },
1772
- * success: true,
1773
- * };
1774
- * },
1976
+ * let received: ReadonlyArray<ProgressEvent> = [];
1977
+ * const port: ProgressPort = {
1978
+ * emit(event) {
1979
+ * received = [...received, event];
1775
1980
  * },
1776
1981
  * };
1777
1982
  *
1778
- * const ops: ReadonlyArray<Operation> = [
1779
- * {
1780
- * key: asResourceKey("vip-pass"),
1781
- * type: "create",
1782
- * desired: {
1783
- * key: asResourceKey("vip-pass"),
1784
- * name: "VIP Pass",
1785
- * description: "Grants VIP perks.",
1786
- * icon: { "en-us": "assets/vip-icon.png" },
1787
- * iconFileHashes: {
1788
- * "en-us": asSha256Hex(
1789
- * "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
1790
- * ),
1791
- * },
1792
- * kind: "gamePass",
1793
- * price: 500,
1794
- * },
1795
- * },
1796
- * ];
1983
+ * port.emit({ environment: "production", kind: "deploySuccess", resourceCount: 3 });
1797
1984
  *
1798
- * return applyOps(ops, registry).then((result) => {
1799
- * expect(result.success).toBe(true);
1800
- * expect(result.success && result.data).toHaveLength(1);
1801
- * });
1985
+ * expect(received).toEqual([
1986
+ * { environment: "production", kind: "deploySuccess", resourceCount: 3 },
1987
+ * ]);
1802
1988
  * ```
1803
1989
  */
1804
- declare function applyOps(ops: ReadonlyArray<Operation>, registry: DriverRegistry): Promise<Result$1<ReadonlyArray<ResourceCurrentState>, ApplyError>>;
1990
+ interface ProgressPort {
1991
+ /** Hand a single progress event to the adapter for rendering or logging. */
1992
+ emit(event: ProgressEvent): void;
1993
+ }
1805
1994
  //#endregion
1806
1995
  //#region src/shell/build-default-registry.d.ts
1807
1996
  /**
@@ -2086,16 +2275,21 @@ declare function flattenConfig(config: ResolvedConfig): ReadonlyArray<ResourceDe
2086
2275
  //#endregion
2087
2276
  //#region src/core/kinds/module.d.ts
2088
2277
  /**
2089
- * Failure surfaced during desired-state preparation. Two variants today:
2278
+ * Failure surfaced during desired-state preparation. Three variants today:
2090
2279
  *
2091
2280
  * - `fileReadFailed`: a kind module's `normalize` could not read a file
2092
2281
  * the input declared (e.g. An icon path that is missing on disk).
2093
2282
  * - `iconRemovalRejected`: `validatePlan` saw a kind whose prior current
2094
2283
  * state recorded an icon that the desired state no longer declares,
2095
2284
  * and the kind has no documented unset path on the upstream API.
2285
+ * - `redactedNameCollision`: `validatePlan` saw two developer-products in
2286
+ * the same plan that resolve to the same wire `name`. The upstream
2287
+ * Roblox API enforces per-universe uniqueness on developer-product
2288
+ * names and would reject the second PATCH with `DuplicateProductName`.
2096
2289
  *
2097
- * Both variants carry the offending `key` so the CLI can attribute the
2098
- * failure to a single resource entry.
2290
+ * The single-resource variants carry the offending `key` so the CLI can
2291
+ * attribute the failure to one entry; `redactedNameCollision` carries
2292
+ * both colliding keys and the resolved name.
2099
2293
  *
2100
2294
  * @example
2101
2295
  *
@@ -2121,6 +2315,11 @@ type BuildDesiredError = {
2121
2315
  /** ResourceKey of the entry whose icon is being removed. */readonly key: ResourceKey; /** Literal discriminator for narrowing. */
2122
2316
  readonly kind: "iconRemovalRejected"; /** Human-readable explanation naming the resource and the invariant. */
2123
2317
  readonly message: string;
2318
+ } | {
2319
+ /** The two developer-product keys whose desired `name` resolves to the same string. */readonly keys: readonly [ResourceKey, ResourceKey]; /** Literal discriminator for narrowing. */
2320
+ readonly kind: "redactedNameCollision"; /** Human-readable explanation naming both keys and the override remedy. */
2321
+ readonly message: string; /** The wire `name` value both products resolve to. */
2322
+ readonly resolvedName: string;
2124
2323
  };
2125
2324
  /**
2126
2325
  * I/O surface the shell injects into kind-module `normalize` calls. Carries
@@ -2184,6 +2383,8 @@ interface KindIo {
2184
2383
  * },
2185
2384
  * success: true,
2186
2385
  * }),
2386
+ * changedFieldsBetween: (desired, current) =>
2387
+ * desired.name === current.name ? [] : ["name"],
2187
2388
  * fieldsEqual: (desired, current) => desired.name === current.name,
2188
2389
  * };
2189
2390
  *
@@ -2200,6 +2401,15 @@ interface ResourceKindModule<K extends ResourceKind> {
2200
2401
  * invariants omit this hook.
2201
2402
  */
2202
2403
  readonly assertReconcilable?: (current: ResourceCurrentState<K>, desired: DesiredFor<K>) => Result$1<undefined, BuildDesiredError>;
2404
+ /**
2405
+ * Top-level field names that differ between `desired` and `current`,
2406
+ * in a kind-specific deterministic order. Mirrors `fieldsEqual`
2407
+ * semantics, so `fieldsEqual(d, c)` is `true` iff this returns `[]`.
2408
+ * Granularity is top-level: `discordSocialLink`, not
2409
+ * `discordSocialLink.uri`. Plan and apply renderers consume this as
2410
+ * the single source of truth for "what changed" on an update op.
2411
+ */
2412
+ changedFieldsBetween(desired: DesiredFor<K>, current: ResourceCurrentState<K>): ReadonlyArray<string>;
2203
2413
  /** ArkType schema for the authored entry body of this kind. */
2204
2414
  readonly entrySchema: Type$1<ResourceEntryByKind[K]>;
2205
2415
  /**
@@ -2383,6 +2593,13 @@ interface DeployOptions {
2383
2593
  readonly getEnv?: (name: string) => string | undefined;
2384
2594
  /** Loader invoked when `config` is omitted; defaults to `loadConfig` from this package. */
2385
2595
  readonly loadConfig?: (options?: LoadConfigOptions) => Promise<Result$1<Config, ConfigError>>;
2596
+ /**
2597
+ * Optional sink for per-resource and aggregate progress events. When
2598
+ * supplied, `applyOps` emits one started/terminal pair per non-noop op
2599
+ * (plus per-noop and summary events), and `deploy` emits `stateWritten`
2600
+ * after a successful state-write. Omit to run silently.
2601
+ */
2602
+ readonly progress?: ProgressPort;
2386
2603
  /** Reads file bytes for resources that have file-backed inputs. Defaults to `node:fs/promises.readFile`. */
2387
2604
  readonly readFile?: (path: string) => Promise<Uint8Array>;
2388
2605
  /** Per-kind driver table consulted for create / update dispatch. Default-constructed from `BEDROCK_API_KEY` when omitted. */
@@ -2399,7 +2616,7 @@ interface DeployOptions {
2399
2616
  * `unsupportedBackend`, `registryConfigMissing`).
2400
2617
  */
2401
2618
  type DeployError = IncompletePassEntryError | IncompletePlaceEntryError | IncompleteUniverseEntryError | MissingCredentialError | RegistryConfigError | StateNotConfiguredError | UnknownEnvironmentError | UnsupportedBackendError | {
2402
- readonly cause: ApplyError;
2619
+ readonly cause: AggregateApplyError;
2403
2620
  readonly kind: "applyFailed";
2404
2621
  } | {
2405
2622
  readonly cause: BuildDesiredError;
@@ -2521,70 +2738,6 @@ interface ClackPort {
2521
2738
  outro(message: string): void;
2522
2739
  }
2523
2740
  //#endregion
2524
- //#region src/ports/progress-port.d.ts
2525
- /**
2526
- * Per-environment outcome event emitted after a deploy completes
2527
- * successfully. Carries the environment name and the count of resources
2528
- * present in the persisted state snapshot.
2529
- */
2530
- interface DeploySuccessEvent {
2531
- /** The environment that finished reconciling. */
2532
- readonly environment: string;
2533
- /** Discriminator tag. */
2534
- readonly kind: "deploySuccess";
2535
- /** Number of resources in the post-deploy state snapshot. */
2536
- readonly resourceCount: number;
2537
- }
2538
- /**
2539
- * Per-environment outcome event emitted when a deploy fails. Carries the
2540
- * environment name and the full {@link DeployError} so a renderer can
2541
- * delegate to the existing diagnostic helpers.
2542
- */
2543
- interface DeployFailureEvent {
2544
- /** The environment whose deploy failed. */
2545
- readonly environment: string;
2546
- /** Stage-tagged failure reason returned by the shell `deploy` function. */
2547
- readonly error: DeployError;
2548
- /** Discriminator tag. */
2549
- readonly kind: "deployFailure";
2550
- }
2551
- /**
2552
- * Discriminated union of progress events the CLI emits while a deploy
2553
- * runs. The variant set is additive: future per-stage and per-resource
2554
- * events land as new `kind` values without breaking existing adapters.
2555
- */
2556
- type ProgressEvent = DeployFailureEvent | DeploySuccessEvent;
2557
- /**
2558
- * Plugin contract for receiving deploy outcomes: the interface an adapter
2559
- * (clack renderer, JSON logger, custom UI) implements to let the CLI hand
2560
- * off events without re-implementing rendering logic.
2561
- *
2562
- * `ProgressPort` is a *driven* (secondary) port in hexagonal terms.
2563
- *
2564
- * @example
2565
- *
2566
- * ```ts
2567
- * import type { ProgressEvent, ProgressPort } from "@bedrock-rbx/core";
2568
- *
2569
- * let received: ReadonlyArray<ProgressEvent> = [];
2570
- * const port: ProgressPort = {
2571
- * emit(event) {
2572
- * received = [...received, event];
2573
- * },
2574
- * };
2575
- *
2576
- * port.emit({ environment: "production", kind: "deploySuccess", resourceCount: 3 });
2577
- *
2578
- * expect(received).toEqual([
2579
- * { environment: "production", kind: "deploySuccess", resourceCount: 3 },
2580
- * ]);
2581
- * ```
2582
- */
2583
- interface ProgressPort {
2584
- /** Hand a single progress event to the adapter for rendering or logging. */
2585
- emit(event: ProgressEvent): void;
2586
- }
2587
- //#endregion
2588
2741
  //#region src/adapters/clack-progress-adapter.d.ts
2589
2742
  /**
2590
2743
  * Configuration for {@link createClackProgressAdapter}.
@@ -2592,12 +2745,18 @@ interface ProgressPort {
2592
2745
  interface ClackProgressAdapterDeps {
2593
2746
  /** Output port the events are rendered through. */
2594
2747
  readonly clack: ClackPort;
2748
+ /**
2749
+ * Loaded project config; the `stateWritten` case resolves the per-environment
2750
+ * `StateConfig` against this to format the backend label. When omitted,
2751
+ * `stateWritten` renders the generic `"state"` placeholder.
2752
+ */
2753
+ readonly config?: Config;
2595
2754
  }
2596
2755
  /**
2597
2756
  * Build a {@link ProgressPort} that renders events through a `ClackPort`.
2598
- * Pattern-matches on the event `kind`: `deploySuccess` becomes a single
2599
- * success line and `deployFailure` delegates to the package's deploy-error
2600
- * rendering helper.
2757
+ * Pattern-matches on the event `kind`: per-resource events render one line each,
2758
+ * the aggregate `applySummary` becomes the deploy footer, and `stateWritten`
2759
+ * names the persistence backend resolved from the loaded `Config`.
2601
2760
  *
2602
2761
  * @example
2603
2762
  *
@@ -2616,12 +2775,12 @@ interface ClackProgressAdapterDeps {
2616
2775
  *
2617
2776
  * const port = createClackProgressAdapter({ clack });
2618
2777
  *
2619
- * port.emit({ environment: "production", kind: "deploySuccess", resourceCount: 3 });
2778
+ * port.emit({ environment: "production", kind: "stateWritten" });
2620
2779
  *
2621
- * expect(lines).toEqual(["ok: production: 3 resources reconciled"]);
2780
+ * expect(lines).toEqual(["log: State written to state"]);
2622
2781
  * ```
2623
2782
  *
2624
- * @param deps - The clack port the adapter renders through.
2783
+ * @param deps - The clack port and optional config the adapter renders through.
2625
2784
  * @returns A `ProgressPort` that renders via clack.
2626
2785
  */
2627
2786
  declare function createClackProgressAdapter(deps: ClackProgressAdapterDeps): ProgressPort;
@@ -3184,8 +3343,12 @@ declare function derivePriceFields(desired: {
3184
3343
  * `update` op if any declared field differs or a `noop` op if every field
3185
3344
  * matches.
3186
3345
  *
3187
- * Ops appear in the order their desired entries appear in the input array so
3188
- * callers can rely on declaration order when logging or applying ops.
3346
+ * Ops appear in the order their desired entries appear in the input array.
3347
+ * `applyOps` regroups them into Phase 1 (universe) and Phase 2 (everything
3348
+ * else) when dispatching; the execution order within Phase 2 is not
3349
+ * guaranteed because Phase 2 dispatches concurrently. Persisted state-file
3350
+ * order is determined by the merge in `deploy.runReconcile` (which retains
3351
+ * prior-snapshot positions for unchanged keys), not by this diff output.
3189
3352
  *
3190
3353
  * @param desired - Declared desired state from user config, already normalized
3191
3354
  * (file hashes computed, nullable wire values mapped to `undefined`).
@@ -3249,6 +3412,11 @@ declare function derivePriceFields(desired: {
3249
3412
  * const ops = diff([unchanged, drifted, fresh], current);
3250
3413
  *
3251
3414
  * expect(ops.map((op) => op.type)).toEqual(["noop", "update", "create"]);
3415
+ *
3416
+ * const updateOp = ops[1]!;
3417
+ * if (updateOp.type === "update") {
3418
+ * expect(updateOp.changedFields).toStrictEqual(["name"]);
3419
+ * }
3252
3420
  * ```
3253
3421
  */
3254
3422
  declare function diff(desired: ReadonlyArray<ResourceDesiredState>, current: ReadonlyArray<ResourceCurrentState>): ReadonlyArray<Operation>;
@@ -3632,5 +3800,5 @@ interface MigrateMantleStateDeps {
3632
3800
  */
3633
3801
  declare function migrateMantleState(deps: MigrateMantleStateDeps): Promise<Result$1<MigrationReport, MigrateError>>;
3634
3802
  //#endregion
3635
- export { type ApplyError, type BaseOperation, type BedrockState, type BuildDesiredError, type ClackPort, type ClackProgressAdapterDeps, type Config, type ConfigContext, type ConfigEnvironmentUniverseId, type ConfigError, type ConfigInput, type ConfigRootUniverseId, type ConfigValidationIssue, type CreateOperation, DEFAULT_PREFIX_FORMAT, type DeployError, type DeployFailureEvent, type DeployOptions, type DeploySuccessEvent, type DeveloperProductDesiredInput, type DeveloperProductDesiredState, type DeveloperProductDriverDeps, type DeveloperProductEntry, type DeveloperProductOutputs, type DisplayNamePrefixConfig, type DriverRegistry, type EnvironmentEntry, type GamePassDesiredInput, type GamePassDesiredState, type GamePassDriverDeps, type GamePassEntry, type GamePassOutputs, type GetEnvironmentError, type GistStateAdapterDeps, type GistStateConfig, type IncompletePlaceEntryError, type IncompleteUniverseEntryError, type KindIo, type KindRegistry, type LoadConfigOptions, type MigrateError, type MigrateMantleStateDeps, type MigrationReport, type MigrationSummary, type MigrationWarning, type MissingCredentialError, type NoopOperation, OpenCloudError, type Operation, type PlaceDesiredInput, type PlaceDesiredState, type PlaceDriverDeps, type PlaceEntry, type PlaceOutputs, type PriceFields, type ProgressEvent, type ProgressPort, type RedactedDeveloperProductOverride, type RedactedGamePassOverride, type RedactedPlaceOverride, type RegistryConfigError, type ResolvedConfig, type ResolvedPlaceEntry, type ResolvedUniverseEntry, type ResourceCurrentState, type ResourceDesiredInput, type ResourceDesiredState, type ResourceDriver, type ResourceEntryByKind, type ResourceKey, type ResourceKind, type ResourceKindModule, type ResourceOutputs, type ResourceOutputsByKind, type Result, type RobloxAssetId, SOCIAL_LINK_FIELDS, type SelectEnvironmentError, type Sha256Hex, type SocialLink, type SocialLinkField, type StateConfig, type StateError, type StateNotConfiguredError, type StatePort, type StatesByEnvironment, UNIVERSE_SINGLETON_KEY, type UniverseDesiredInput, type UniverseDesiredState, type UniverseDriverDeps, type UniverseEntry, type UniverseOutputs, type UniverseOverlayWithId, type UniverseOverlayWithoutId, type UnknownEnvironmentError, type UnsupportedBackendError, type UpdateOperation, applyOps, asResourceKey, asRobloxAssetId, asSha256Hex, buildDefaultRegistry, buildDesired, buildStatePort, createClackPort, createClackProgressAdapter, createDeveloperProductDriver, createGamePassDriver, createGistStateAdapter, createNoOpProgressAdapter, createPlaceDriver, createUniverseDriver, defaultKindRegistry, defineConfig, deploy, derivePriceFields, diff, flattenConfig, getEnvironment, isGistStateConfig, isResourceKey, isRobloxAssetId, isSha256Hex, loadConfig, migrateMantleState, parseStateFile, renderDisplayNamePrefix, resolveStateConfig, selectEnvironment, serializeStateFile, shouldReuploadIcon, validateConfig, validateEnvironmentName, validatePlan };
3803
+ export { type AggregateApplyError, type ApplyError, type ApplyOpsReporting, type ApplySummaryEvent, type BaseOperation, type BedrockState, type BuildDesiredError, type ClackPort, type ClackProgressAdapterDeps, type Config, type ConfigContext, type ConfigEnvironmentUniverseId, type ConfigError, type ConfigInput, type ConfigRootUniverseId, type ConfigValidationIssue, type CreateOperation, DEFAULT_PREFIX_FORMAT, type DeployError, type DeployFailureEvent, type DeployOptions, type DeploySuccessEvent, type DeveloperProductDesiredInput, type DeveloperProductDesiredState, type DeveloperProductDriverDeps, type DeveloperProductEntry, type DeveloperProductOutputs, type DisplayNamePrefixConfig, type DriverRegistry, type EnvironmentEntry, type GamePassDesiredInput, type GamePassDesiredState, type GamePassDriverDeps, type GamePassEntry, type GamePassOutputs, type GetEnvironmentError, type GistStateAdapterDeps, type GistStateConfig, type IncompletePlaceEntryError, type IncompleteUniverseEntryError, type KindIo, type KindRegistry, type LoadConfigOptions, type MigrateError, type MigrateMantleStateDeps, type MigrationReport, type MigrationSummary, type MigrationWarning, type MissingCredentialError, type NoopOperation, OpenCloudError, type Operation, type PlaceDesiredInput, type PlaceDesiredState, type PlaceDriverDeps, type PlaceEntry, type PlaceOutputs, type PriceFields, type ProgressEvent, type ProgressPort, type RedactedDeveloperProductOverride, type RedactedEnvironmentOverride, type RedactedGamePassOverride, type RedactedPlaceOverride, type RegistryConfigError, type ResolvedConfig, type ResolvedPlaceEntry, type ResolvedUniverseEntry, type ResourceCurrentState, type ResourceDesiredInput, type ResourceDesiredState, type ResourceDriver, type ResourceEntryByKind, type ResourceKey, type ResourceKind, type ResourceKindModule, type ResourceOpFailedEvent, type ResourceOpNoopEvent, type ResourceOpStartedEvent, type ResourceOpSucceededCreateEvent, type ResourceOpSucceededEvent, type ResourceOpSucceededUpdateEvent, type ResourceOutputs, type ResourceOutputsByKind, type Result, type RobloxAssetId, SOCIAL_LINK_FIELDS, type SelectEnvironmentError, type Sha256Hex, type SocialLink, type SocialLinkField, type StateConfig, type StateError, type StateNotConfiguredError, type StatePort, type StateWrittenEvent, type StatesByEnvironment, UNIVERSE_SINGLETON_KEY, type UniverseDesiredInput, type UniverseDesiredState, type UniverseDriverDeps, type UniverseEntry, type UniverseOutputs, type UniverseOverlayWithId, type UniverseOverlayWithoutId, type UnknownEnvironmentError, type UnsupportedBackendError, type UpdateOperation, applyOps, asResourceKey, asRobloxAssetId, asSha256Hex, buildDefaultRegistry, buildDesired, buildStatePort, createClackPort, createClackProgressAdapter, createDeveloperProductDriver, createGamePassDriver, createGistStateAdapter, createNoOpProgressAdapter, createPlaceDriver, createUniverseDriver, defaultKindRegistry, defineConfig, deploy, derivePriceFields, diff, flattenConfig, getEnvironment, isGistStateConfig, isResourceKey, isRobloxAssetId, isSha256Hex, loadConfig, migrateMantleState, parseStateFile, renderDisplayNamePrefix, resolveStateConfig, selectEnvironment, serializeStateFile, shouldReuploadIcon, validateConfig, validateEnvironmentName, validatePlan };
3636
3804
  //# sourceMappingURL=index.d.mts.map