@sealant/sdk 0.5.1 → 0.5.2

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.
@@ -756,12 +756,13 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
756
756
  readonly github?: string | undefined;
757
757
  } | undefined;
758
758
  readonly spec: unknown;
759
+ readonly ttlSeconds?: number | undefined;
759
760
  };
760
761
  readonly responseMode?: Mode;
761
762
  }) => Effect.Effect<HttpApiClient.Client.Response<{
762
763
  readonly workspaceId: string;
763
764
  readonly name: string;
764
- readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
765
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
765
766
  readonly registryId: string;
766
767
  readonly repository: string;
767
768
  readonly tag: string;
@@ -795,6 +796,19 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
795
796
  readonly createdAt: string;
796
797
  readonly updatedAt: string;
797
798
  }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
799
+ readonly expireWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
800
+ readonly params: {
801
+ readonly workspaceId: string;
802
+ };
803
+ readonly payload: {
804
+ readonly ownerUserId: string;
805
+ readonly ttlSeconds?: number | null | undefined;
806
+ };
807
+ readonly responseMode?: Mode;
808
+ }) => Effect.Effect<HttpApiClient.Client.Response<{
809
+ readonly workspaceId: string;
810
+ readonly expiresAt: string | null;
811
+ }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
798
812
  readonly getWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
799
813
  readonly params: {
800
814
  readonly workspaceId: string;
@@ -804,7 +818,7 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
804
818
  readonly workspaceId: string;
805
819
  readonly name: string;
806
820
  readonly ownerUserId: string;
807
- readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
821
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
808
822
  readonly registryId?: string | undefined;
809
823
  readonly repository?: string | undefined;
810
824
  readonly tag?: string | undefined;
@@ -828,6 +842,7 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
828
842
  readonly updatedAt: string;
829
843
  readonly startedAt?: string | undefined;
830
844
  readonly finishedAt?: string | undefined;
845
+ readonly expiresAt?: string | undefined;
831
846
  readonly spec?: unknown;
832
847
  }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
833
848
  readonly getWorkspaceSshTarget: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
@@ -862,7 +877,7 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
862
877
  readonly items: readonly {
863
878
  readonly attemptId: string;
864
879
  readonly relation: "launch" | "rebuild" | "resume" | "retry";
865
- readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
880
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
866
881
  readonly triggerType: "api" | "manual" | "retry" | "schedule";
867
882
  readonly triggerRef?: string | undefined;
868
883
  readonly runtime?: {
@@ -913,7 +928,7 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
913
928
  readonly listWorkspaces: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
914
929
  readonly query: {
915
930
  readonly ownerUserId: string;
916
- readonly status?: "cancelled" | "failed" | "queued" | "ready" | "running" | undefined;
931
+ readonly status?: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped" | undefined;
917
932
  readonly limit?: string | undefined;
918
933
  };
919
934
  readonly responseMode?: Mode;
@@ -922,7 +937,7 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
922
937
  readonly workspaceId: string;
923
938
  readonly name: string;
924
939
  readonly ownerUserId: string;
925
- readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
940
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
926
941
  readonly registryId?: string | undefined;
927
942
  readonly repository?: string | undefined;
928
943
  readonly tag?: string | undefined;
@@ -946,6 +961,7 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
946
961
  readonly updatedAt: string;
947
962
  readonly startedAt?: string | undefined;
948
963
  readonly finishedAt?: string | undefined;
964
+ readonly expiresAt?: string | undefined;
949
965
  }[];
950
966
  }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceInternalServerError), [Mode] extends ["response-only"] ? never : never>;
951
967
  readonly renameWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
@@ -961,6 +977,31 @@ declare const buildControlPlaneClient: (config: SealantInternalConfig) => Effect
961
977
  readonly name: string;
962
978
  readonly updatedAt: string;
963
979
  }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
980
+ readonly restartWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
981
+ readonly params: {
982
+ readonly workspaceId: string;
983
+ };
984
+ readonly payload: {
985
+ readonly ownerUserId: string;
986
+ };
987
+ readonly responseMode?: Mode;
988
+ }) => Effect.Effect<HttpApiClient.Client.Response<{
989
+ readonly workspaceId: string;
990
+ readonly runId: string;
991
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
992
+ }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
993
+ readonly stopWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
994
+ readonly params: {
995
+ readonly workspaceId: string;
996
+ };
997
+ readonly payload: {
998
+ readonly ownerUserId: string;
999
+ };
1000
+ readonly responseMode?: Mode;
1001
+ }) => Effect.Effect<HttpApiClient.Client.Response<{
1002
+ readonly workspaceId: string;
1003
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
1004
+ }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
964
1005
  };
965
1006
  }, never, HttpClient.HttpClient>;
966
1007
  /** The fully-typed control-plane client, derived from the `@sealant/api-contracts` HttpApi. */
@@ -1718,12 +1759,13 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
1718
1759
  readonly github?: string | undefined;
1719
1760
  } | undefined;
1720
1761
  readonly spec: unknown;
1762
+ readonly ttlSeconds?: number | undefined;
1721
1763
  };
1722
1764
  readonly responseMode?: Mode;
1723
1765
  }) => Effect.Effect<HttpApiClient.Client.Response<{
1724
1766
  readonly workspaceId: string;
1725
1767
  readonly name: string;
1726
- readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
1768
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
1727
1769
  readonly registryId: string;
1728
1770
  readonly repository: string;
1729
1771
  readonly tag: string;
@@ -1757,6 +1799,19 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
1757
1799
  readonly createdAt: string;
1758
1800
  readonly updatedAt: string;
1759
1801
  }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
1802
+ readonly expireWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
1803
+ readonly params: {
1804
+ readonly workspaceId: string;
1805
+ };
1806
+ readonly payload: {
1807
+ readonly ownerUserId: string;
1808
+ readonly ttlSeconds?: number | null | undefined;
1809
+ };
1810
+ readonly responseMode?: Mode;
1811
+ }) => Effect.Effect<HttpApiClient.Client.Response<{
1812
+ readonly workspaceId: string;
1813
+ readonly expiresAt: string | null;
1814
+ }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
1760
1815
  readonly getWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
1761
1816
  readonly params: {
1762
1817
  readonly workspaceId: string;
@@ -1766,7 +1821,7 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
1766
1821
  readonly workspaceId: string;
1767
1822
  readonly name: string;
1768
1823
  readonly ownerUserId: string;
1769
- readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
1824
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
1770
1825
  readonly registryId?: string | undefined;
1771
1826
  readonly repository?: string | undefined;
1772
1827
  readonly tag?: string | undefined;
@@ -1790,6 +1845,7 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
1790
1845
  readonly updatedAt: string;
1791
1846
  readonly startedAt?: string | undefined;
1792
1847
  readonly finishedAt?: string | undefined;
1848
+ readonly expiresAt?: string | undefined;
1793
1849
  readonly spec?: unknown;
1794
1850
  }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
1795
1851
  readonly getWorkspaceSshTarget: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
@@ -1824,7 +1880,7 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
1824
1880
  readonly items: readonly {
1825
1881
  readonly attemptId: string;
1826
1882
  readonly relation: "launch" | "rebuild" | "resume" | "retry";
1827
- readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
1883
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
1828
1884
  readonly triggerType: "api" | "manual" | "retry" | "schedule";
1829
1885
  readonly triggerRef?: string | undefined;
1830
1886
  readonly runtime?: {
@@ -1875,7 +1931,7 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
1875
1931
  readonly listWorkspaces: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
1876
1932
  readonly query: {
1877
1933
  readonly ownerUserId: string;
1878
- readonly status?: "cancelled" | "failed" | "queued" | "ready" | "running" | undefined;
1934
+ readonly status?: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped" | undefined;
1879
1935
  readonly limit?: string | undefined;
1880
1936
  };
1881
1937
  readonly responseMode?: Mode;
@@ -1884,7 +1940,7 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
1884
1940
  readonly workspaceId: string;
1885
1941
  readonly name: string;
1886
1942
  readonly ownerUserId: string;
1887
- readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
1943
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
1888
1944
  readonly registryId?: string | undefined;
1889
1945
  readonly repository?: string | undefined;
1890
1946
  readonly tag?: string | undefined;
@@ -1908,6 +1964,7 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
1908
1964
  readonly updatedAt: string;
1909
1965
  readonly startedAt?: string | undefined;
1910
1966
  readonly finishedAt?: string | undefined;
1967
+ readonly expiresAt?: string | undefined;
1911
1968
  }[];
1912
1969
  }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceInternalServerError), [Mode] extends ["response-only"] ? never : never>;
1913
1970
  readonly renameWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
@@ -1923,6 +1980,31 @@ declare const SealantApiClient_base: Context.ServiceClass<SealantApiClient, "@se
1923
1980
  readonly name: string;
1924
1981
  readonly updatedAt: string;
1925
1982
  }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
1983
+ readonly restartWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
1984
+ readonly params: {
1985
+ readonly workspaceId: string;
1986
+ };
1987
+ readonly payload: {
1988
+ readonly ownerUserId: string;
1989
+ };
1990
+ readonly responseMode?: Mode;
1991
+ }) => Effect.Effect<HttpApiClient.Client.Response<{
1992
+ readonly workspaceId: string;
1993
+ readonly runId: string;
1994
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
1995
+ }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
1996
+ readonly stopWorkspace: <Mode extends import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode = import("effect/unstable/httpapi/HttpApiEndpoint").ClientResponseMode>(request: {
1997
+ readonly params: {
1998
+ readonly workspaceId: string;
1999
+ };
2000
+ readonly payload: {
2001
+ readonly ownerUserId: string;
2002
+ };
2003
+ readonly responseMode?: Mode;
2004
+ }) => Effect.Effect<HttpApiClient.Client.Response<{
2005
+ readonly workspaceId: string;
2006
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
2007
+ }, Mode>, import("effect/unstable/http/HttpClientError").HttpClientError | ([Mode] extends ["response-only"] ? never : import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError), [Mode] extends ["response-only"] ? never : never>;
1926
2008
  };
1927
2009
  }>;
1928
2010
  export declare class SealantApiClient extends SealantApiClient_base {
@@ -25,10 +25,11 @@ export declare const createWorkspaceOp: (payload: {
25
25
  readonly github?: string | undefined;
26
26
  } | undefined;
27
27
  readonly spec: unknown;
28
+ readonly ttlSeconds?: number | undefined;
28
29
  }, idempotencyKey?: string | undefined) => Effect.Effect<{
29
30
  readonly workspaceId: string;
30
31
  readonly name: string;
31
- readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
32
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
32
33
  readonly registryId: string;
33
34
  readonly repository: string;
34
35
  readonly tag: string;
@@ -37,7 +38,7 @@ export declare const getWorkspaceOp: (workspaceId: string) => Effect.Effect<{
37
38
  readonly workspaceId: string;
38
39
  readonly name: string;
39
40
  readonly ownerUserId: string;
40
- readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
41
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
41
42
  readonly registryId?: string | undefined;
42
43
  readonly repository?: string | undefined;
43
44
  readonly tag?: string | undefined;
@@ -61,18 +62,19 @@ export declare const getWorkspaceOp: (workspaceId: string) => Effect.Effect<{
61
62
  readonly updatedAt: string;
62
63
  readonly startedAt?: string | undefined;
63
64
  readonly finishedAt?: string | undefined;
65
+ readonly expiresAt?: string | undefined;
64
66
  readonly spec?: unknown;
65
67
  }, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError, SealantApiClient>;
66
68
  export declare const listWorkspacesOp: (query: {
67
69
  readonly ownerUserId: string;
68
- readonly status?: "cancelled" | "failed" | "queued" | "ready" | "running" | undefined;
70
+ readonly status?: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped" | undefined;
69
71
  readonly limit?: string | undefined;
70
72
  }) => Effect.Effect<{
71
73
  readonly items: readonly {
72
74
  readonly workspaceId: string;
73
75
  readonly name: string;
74
76
  readonly ownerUserId: string;
75
- readonly status: "cancelled" | "failed" | "queued" | "ready" | "running";
77
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
76
78
  readonly registryId?: string | undefined;
77
79
  readonly repository?: string | undefined;
78
80
  readonly tag?: string | undefined;
@@ -96,6 +98,7 @@ export declare const listWorkspacesOp: (query: {
96
98
  readonly updatedAt: string;
97
99
  readonly startedAt?: string | undefined;
98
100
  readonly finishedAt?: string | undefined;
101
+ readonly expiresAt?: string | undefined;
99
102
  }[];
100
103
  }, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceInternalServerError, SealantApiClient>;
101
104
  export declare const execWorkspaceOp: (workspaceId: string, payload: {
@@ -121,6 +124,26 @@ export declare const execWorkspaceOp: (workspaceId: string, payload: {
121
124
  readonly createdAt: string;
122
125
  readonly updatedAt: string;
123
126
  }, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError, SealantApiClient>;
127
+ export declare const stopWorkspaceOp: (workspaceId: string, payload: {
128
+ readonly ownerUserId: string;
129
+ }) => Effect.Effect<{
130
+ readonly workspaceId: string;
131
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
132
+ }, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError, SealantApiClient>;
133
+ export declare const restartWorkspaceOp: (workspaceId: string, payload: {
134
+ readonly ownerUserId: string;
135
+ }) => Effect.Effect<{
136
+ readonly workspaceId: string;
137
+ readonly runId: string;
138
+ readonly status: "cancelled" | "failed" | "queued" | "ready" | "running" | "stopped";
139
+ }, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadGatewayError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceConflictError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError, SealantApiClient>;
140
+ export declare const expireWorkspaceOp: (workspaceId: string, payload: {
141
+ readonly ownerUserId: string;
142
+ readonly ttlSeconds?: number | null | undefined;
143
+ }) => Effect.Effect<{
144
+ readonly workspaceId: string;
145
+ readonly expiresAt: string | null;
146
+ }, import("effect/unstable/http/HttpClientError").HttpClientError | import("effect/Schema").SchemaError | import("@sealant/api-contracts").WorkspaceBadRequestError | import("@sealant/api-contracts").WorkspaceInternalServerError | import("@sealant/api-contracts").WorkspaceNotFoundError, SealantApiClient>;
124
147
  export declare const createRunOp: (payload: {
125
148
  readonly workspaceId: string;
126
149
  readonly harnessId: string;
@@ -8,6 +8,9 @@ export const createWorkspaceOp = (payload, idempotencyKey) => Effect.flatMap(Sea
8
8
  export const getWorkspaceOp = (workspaceId) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.getWorkspace({ params: { workspaceId } }));
9
9
  export const listWorkspacesOp = (query) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.listWorkspaces({ query }));
10
10
  export const execWorkspaceOp = (workspaceId, payload) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.execWorkspace({ params: { workspaceId }, payload }));
11
+ export const stopWorkspaceOp = (workspaceId, payload) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.stopWorkspace({ params: { workspaceId }, payload }));
12
+ export const restartWorkspaceOp = (workspaceId, payload) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.restartWorkspace({ params: { workspaceId }, payload }));
13
+ export const expireWorkspaceOp = (workspaceId, payload) => Effect.flatMap(SealantApiClient, (client) => client.workspaces.expireWorkspace({ params: { workspaceId }, payload }));
11
14
  // ---- runs ----
12
15
  export const createRunOp = (payload) => Effect.flatMap(SealantApiClient, (client) => client.runs.createRun({ payload }));
13
16
  export const getRunOp = (runId) => Effect.flatMap(SealantApiClient, (client) => client.runs.getRun({ params: { runId } }));
@@ -1,9 +1,15 @@
1
1
  import { execWorkspace } from "../effect/exec-workspace.js";
2
- import { getWorkspaceOp } from "../effect/operations.js";
2
+ import { expireWorkspaceOp, getWorkspaceOp, restartWorkspaceOp, stopWorkspaceOp, } from "../effect/operations.js";
3
3
  import { SealantError, SealantNotImplementedError } from "../errors.js";
4
- const FAILED_STATUSES = new Set(["failed", "cancelled"]);
4
+ import { parseTtlSeconds } from "../internal/duration.js";
5
+ // Terminal statuses a workspace can never leave: ready()/events() fail fast (or end the stream)
6
+ // on these instead of polling out their deadline. "stopped" is terminal too — a TTL expiry or a
7
+ // concurrent stop while ready() polls must surface immediately, not as a 10-minute timeout.
8
+ const FAILED_STATUSES = new Set(["failed", "cancelled", "stopped"]);
5
9
  const READY_POLL_INTERVAL_MS = 2_000;
6
10
  const READY_TIMEOUT_MS = 10 * 60 * 1_000;
11
+ const STOP_POLL_INTERVAL_MS = 1_000;
12
+ const STOP_TIMEOUT_MS = 60 * 1_000;
7
13
  const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
8
14
  let harnessExecutors;
9
15
  export const registerHarnessExecutors = (executors) => {
@@ -83,9 +89,48 @@ export const makeWorkspace = (ctx, init) => {
83
89
  }
84
90
  return iterate();
85
91
  },
86
- stop: () => Promise.reject(new SealantNotImplementedError("workspace.stop (lifecycle, Phase 3)")),
87
- restart: () => Promise.reject(new SealantNotImplementedError("workspace.restart (lifecycle, Phase 3)")),
88
- expire: () => Promise.reject(new SealantNotImplementedError("workspace.expire (lifecycle, Phase 3)")),
92
+ // BLOCKING stop: the control plane accepts the stop (202) and the worker tears the container
93
+ // down; resolve only once the workspace reports the terminal "stopped" status, so callers can
94
+ // trust the container is gone when this settles.
95
+ stop: async () => {
96
+ const ownerUserId = ctx.config.hostLocal.ownerUserId;
97
+ await ctx.runtime.run(stopWorkspaceOp(init.id, { ownerUserId }));
98
+ const deadline = Date.now() + STOP_TIMEOUT_MS;
99
+ for (;;) {
100
+ const details = await ctx.runtime.run(getWorkspaceOp(init.id));
101
+ if (details.status === "stopped") {
102
+ return;
103
+ }
104
+ if (Date.now() > deadline) {
105
+ throw new SealantError(`Timed out waiting for workspace ${init.id} to stop.`, {
106
+ code: "workspace_stop_timeout",
107
+ });
108
+ }
109
+ await delay(STOP_POLL_INTERVAL_MS);
110
+ }
111
+ },
112
+ // Restart drives a fresh launch (new attempt, new container, same resolved spec) and returns a
113
+ // handle that resolves readiness against the NEW runtime via the usual ready() gate.
114
+ restart: async () => {
115
+ const ownerUserId = ctx.config.hostLocal.ownerUserId;
116
+ await ctx.runtime.run(restartWorkspaceOp(init.id, { ownerUserId }));
117
+ return makeWorkspace(ctx, {
118
+ id: init.id,
119
+ name: init.name,
120
+ status: "queued",
121
+ ...(init.harness === undefined ? {} : { harness: init.harness }),
122
+ });
123
+ },
124
+ // expire({in: "2h"}) sets the TTL, expire() expires now (the platform reaper stops it on its
125
+ // next tick), expire({in: null}) clears the TTL. Resolves once the expiry is recorded.
126
+ expire: async (options) => {
127
+ const ownerUserId = ctx.config.hostLocal.ownerUserId;
128
+ const ttl = options?.in;
129
+ await ctx.runtime.run(expireWorkspaceOp(init.id, {
130
+ ownerUserId,
131
+ ...(ttl === undefined ? {} : { ttlSeconds: ttl === null ? null : parseTtlSeconds(ttl) }),
132
+ }));
133
+ },
89
134
  };
90
135
  return workspace;
91
136
  };
@@ -26,5 +26,6 @@ export declare const buildCreateWorkspaceRequest: (options: CreateOptions, confi
26
26
  readonly github?: string | undefined;
27
27
  } | undefined;
28
28
  readonly spec: unknown;
29
+ readonly ttlSeconds?: number | undefined;
29
30
  };
30
31
  };
@@ -12,6 +12,7 @@
12
12
  */
13
13
  import { randomUUID } from "node:crypto";
14
14
  import { mapWorkspaceCredentials } from "./credentials.js";
15
+ import { parseTtlSeconds } from "./duration.js";
15
16
  const sanitizeRepoSlug = (value) => {
16
17
  const slug = value
17
18
  .toLowerCase()
@@ -39,7 +40,8 @@ export const buildCreateWorkspaceRequest = (options, config) => {
39
40
  kind: "git",
40
41
  provider: "generic",
41
42
  url: toGitUrl(options.repository),
42
- ref: options.ref ?? "main",
43
+ // Omitted ref = the repository's default branch, resolved by the clone itself.
44
+ ...(options.ref === undefined ? {} : { ref: options.ref }),
43
45
  },
44
46
  },
45
47
  harness: { id: options.harness.id },
@@ -63,6 +65,7 @@ export const buildCreateWorkspaceRequest = (options, config) => {
63
65
  repository: sanitizeRepoSlug(tail),
64
66
  tag: `sdk-${randomUUID().slice(0, 8)}`,
65
67
  ...(options.name === undefined ? {} : { name: options.name }),
68
+ ...(options.ttl === undefined ? {} : { ttlSeconds: parseTtlSeconds(options.ttl) }),
66
69
  spec,
67
70
  },
68
71
  };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Parse a human TTL like `"90m"`, `"2h"`, `"45s"`, `"1d"` into whole seconds (milliseconds round
3
+ * up to at least 1s — the wire TTL is second-granular). Throws a typed `SealantError` on anything
4
+ * else so a typo'd TTL fails at the call site instead of silently never expiring.
5
+ */
6
+ export declare const parseTtlSeconds: (ttl: string) => number;
@@ -0,0 +1,34 @@
1
+ import { SealantError } from "../errors.js";
2
+ const DURATION_PATTERN = /^(\d+)(ms|s|m|h|d)$/;
3
+ const UNIT_SECONDS = {
4
+ s: 1,
5
+ m: 60,
6
+ h: 3600,
7
+ d: 86400,
8
+ };
9
+ /**
10
+ * Parse a human TTL like `"90m"`, `"2h"`, `"45s"`, `"1d"` into whole seconds (milliseconds round
11
+ * up to at least 1s — the wire TTL is second-granular). Throws a typed `SealantError` on anything
12
+ * else so a typo'd TTL fails at the call site instead of silently never expiring.
13
+ */
14
+ export const parseTtlSeconds = (ttl) => {
15
+ const match = DURATION_PATTERN.exec(ttl.trim());
16
+ if (match === null) {
17
+ throw new SealantError(`Invalid TTL duration "${ttl}". Use a positive integer with a unit: e.g. "45s", "90m", "2h", "1d".`, { code: "invalid_ttl" });
18
+ }
19
+ const value = Number.parseInt(match[1] ?? "", 10);
20
+ const unit = match[2] ?? "";
21
+ if (!Number.isInteger(value) || value <= 0) {
22
+ throw new SealantError(`Invalid TTL duration "${ttl}". The value must be a positive integer.`, {
23
+ code: "invalid_ttl",
24
+ });
25
+ }
26
+ if (unit === "ms") {
27
+ return Math.max(1, Math.ceil(value / 1000));
28
+ }
29
+ const multiplier = UNIT_SECONDS[unit];
30
+ if (multiplier === undefined) {
31
+ throw new SealantError(`Invalid TTL duration "${ttl}".`, { code: "invalid_ttl" });
32
+ }
33
+ return value * multiplier;
34
+ };
package/dist/types.d.ts CHANGED
@@ -56,8 +56,8 @@ export interface Harness {
56
56
  /** Optional launch command for an interactive session (defaults to the executable). */
57
57
  readonly launchCommand?: string;
58
58
  }
59
- /** Lifecycle status of a workspace. `stopped`/`expired` arrive with lifecycle close-out (Phase 3). */
60
- export type WorkspaceStatus = "queued" | "running" | "ready" | "failed" | "cancelled";
59
+ /** Lifecycle status of a workspace. */
60
+ export type WorkspaceStatus = "queued" | "running" | "ready" | "failed" | "cancelled" | "stopped";
61
61
  /** A coarse lifecycle event observed while a workspace is being provisioned. */
62
62
  export interface WorkspaceEvent {
63
63
  readonly type: string;
@@ -109,6 +109,12 @@ export interface CreateOptions {
109
109
  readonly onEvent?: (event: WorkspaceEvent) => void;
110
110
  /** Connected-account credentials to attach to the workspace (see `WorkspaceCredentialsOptions`). */
111
111
  readonly credentials?: WorkspaceCredentialsOptions;
112
+ /**
113
+ * Time-to-live for the workspace, e.g. `"90m"`, `"2h"` (also `"45s"`, `"1d"`). Once it elapses
114
+ * the platform stops the workspace and removes its container. Omitted = the server default TTL
115
+ * (if the install configures one).
116
+ */
117
+ readonly ttl?: string;
112
118
  }
113
119
  export interface ListOptions {
114
120
  readonly status?: WorkspaceStatus;
@@ -152,13 +158,16 @@ export interface Workspace {
152
158
  exec(argv: readonly string[], options?: WorkspaceExecOptions): Promise<WorkspaceExecResult>;
153
159
  /** Lifecycle events as an async stream. */
154
160
  events(): AsyncIterable<WorkspaceEvent>;
155
- /** Stop the workspace now (Phase 3). */
161
+ /** Stop the workspace: remove its container and settle it in the terminal "stopped" status. */
156
162
  stop(): Promise<void>;
157
- /** Restart the workspace into a fresh runtime (Phase 3). */
163
+ /** Restart the workspace into a fresh runtime a new container, no filesystem carry-over. */
158
164
  restart(): Promise<Workspace>;
159
- /** Schedule the workspace to expire (Phase 3). */
165
+ /**
166
+ * Schedule the workspace to expire: `expire({ in: "2h" })` sets the TTL, `expire()` expires it
167
+ * now (the platform reaper stops it shortly), `expire({ in: null })` clears the TTL.
168
+ */
160
169
  expire(options?: {
161
- readonly in?: string;
170
+ readonly in?: string | null;
162
171
  }): Promise<void>;
163
172
  }
164
173
  export interface RunOptions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sealant/sdk",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "The fluent public SDK for Sealant — create a workspace, run a harness, replay the record.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "effect": "^4.0.0-beta.85",
30
- "@sealant/api-contracts": "^0.5.1"
30
+ "@sealant/api-contracts": "^0.5.2"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@effect/vitest": "^4.0.0-beta.85",