1import type { NamespaceNode } from "../Namespace.ts";
2import type { ProviderMode } from "../ProviderMode.ts";
3import type { RemovalPolicy } from "../RemovalPolicy.ts";
4import type { ResourceBinding } from "../Resource.ts";
5
6export type ResourceState =
7 | CreatingResourceState
8 | CreatedResourceState
9 | UpdatingReourceState
10 | UpdatedResourceState
11 | DeletingResourceState
12 | ReplacingResourceState
13 | ReplacedResourceState;
14
15export type Props = Record<string, any>;
16export type Attr = Record<string, any>;
17
18export type ResourceStatus = ResourceState["status"];
19export type ReplacementResourceState =
20 | ReplacingResourceState
21 | ReplacedResourceState;
22export type ReplacementOldResourceState =
23 | CreatingResourceState
24 | CreatedResourceState
25 | UpdatingReourceState
26 | UpdatedResourceState
27 | DeletingResourceState
28 | ReplacementResourceState;
29
30interface BaseResourceState {
31 /**
32 * Discriminator vs {@link ActionState}. Optional for back-compat: legacy
33 * persisted rows have no `kind` field and are implicitly resources.
34 */
35 readonly kind?: "resource";
36 /** Type of the Resource (e.g. AWS.Lambda.Function) */
37 resourceType: string;
38 /** Namespace of the Resource */
39 namespace: NamespaceNode | undefined;
40 /** Fully Qualified Name (namespace path + logical ID) */
41 fqn: string;
42 /** Logical ID of the Resource (stable across creates, updates, deletes and replaces) */
43 logicalId: string;
44 /** A unique randomly generated token used to seed ID generation (only changes when replaced) */
45 instanceId: string;
46 /** The version of the provider that was used to create/update the resource. */
47 providerVersion: number;
48 /** Current status of the logical Resource */
49 status: ResourceStatus;
50 /** List of FQNs of resources that depend on this resource */
51 downstream: string[];
52 /** List of Bindings attached to this Resource */
53 bindings: ResourceBinding[];
54 /** Desired state (input props) of this Resource */
55 props?: Props;
56 /** The output attributes of this Resource (if it has been created) */
57 attr?: Attr;
58 /** The removal policy of the resource */
59 removalPolicy?: RemovalPolicy["Service"];
60 /** Attr-less lookup could recover the predecessor migrated away from this FQN. */
61 adoptionBlocked?: "migrated-fqn";
62 /**
63 * The {@link ProviderMode} this resource was last reconciled with.
64 *
65 * Stamped by Apply on every commit for resources whose provider
66 * distinguishes modes (`ProviderLayer.dual`). Plan treats a mismatch
67 * between the persisted mode and the resolved desired mode as a
68 * **replacement**, and deletion always uses the provider variant of the
69 * mode that created the row.
70 *
71 * `undefined` means either a mode-agnostic provider (single
72 * implementation serves both dev and deploy) or a legacy row written
73 * before modes were persisted — both acted on the real cloud, so an
74 * unstamped row is assumed **live**, unless its attrs carry a local
75 * identity marker (`dev:`-prefixed ids) proving it was reconciled
76 * locally, in which case it is assumed **local** (see `stampedMode`).
77 * Same-mode runs see no churn; a run in the other mode replaces it like
78 * any stamped row.
79 */
80 providerMode?: ProviderMode;
81}
82
83export interface CreatingResourceState extends BaseResourceState {
84 status: "creating";
85 /** The new resource properties that are being (or have been) applied. */
86 props: Props;
87}
88
89export interface CreatedResourceState extends BaseResourceState {
90 status: "created";
91 /** The new resource properties that have been applied. */
92 props: Props;
93 /** The output attributes of the created resource */
94 attr: Attr;
95}
96
97export interface UpdatingReourceState extends BaseResourceState {
98 status: "updating";
99 /** Persisted until the first post-adoption reconcile succeeds. */
100 adopting?: true;
101 /** The new resource properties that are being (or have been) applied. */
102 props: Props;
103 old: {
104 /** The old resource properties that have been successfully applied. */
105 props: Props;
106 /** List of Bindings attached to this Resource */
107 bindings: any[];
108 /** The old output properties that have been successfully applied. */
109 attr: Attr;
110 // TODO(sam): do I need to track the old downstream edges?
111 // downstream: string[];
112 };
113}
114
115export interface UpdatedResourceState extends BaseResourceState {
116 status: "updated";
117 /** The new resource properties that are being (or have been) applied. */
118 props: Props;
119 /** The output attributes of the created resource */
120 attr: Attr;
121}
122
123export interface DeletingResourceState extends BaseResourceState {
124 status: "deleting";
125 /** Attributes of the resource being deleted */
126 attr: Attr | undefined;
127}
128
129export interface ReplacingResourceState extends BaseResourceState {
130 status: "replacing";
131 /** Desired properties of the new resource (the replacement) */
132 props: Props;
133 /** Reference to the state of the old resource (the one being replaced) */
134 old: ReplacementOldResourceState;
135 /** Whether the resource should be deleted before or after replacements */
136 deleteFirst: boolean;
137}
138
139export interface ReplacedResourceState extends BaseResourceState {
140 status: "replaced";
141 /** Desired properties of the new resource (the replacement) */
142 props: Props;
143 /** Output attributes of the new resource (the replacement) */
144 attr: Attr;
145 /** Reference to the state of the old resource (the one being replaced) */
146 old: ReplacementOldResourceState;
147 /** Whether the resource should be deleted before or after replacements */
148 deleteFirst: boolean;
149 // .. will (finally) transition to `CreatedResourceState` after finalizing
150}