@molecule/api-deploy-rollout 0.0.0-stage → 1.1.0
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/LICENSE +202 -0
- package/README.md +518 -2
- package/dist/browser-guard.d.ts +2 -0
- package/dist/browser-guard.d.ts.map +1 -0
- package/dist/browser-guard.js +19 -0
- package/dist/browser-guard.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/provider.d.ts +48 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +64 -0
- package/dist/provider.js.map +1 -0
- package/dist/types.d.ts +308 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +23 -0
- package/dist/types.js.map +1 -0
- package/package.json +55 -4
package/README.md
CHANGED
|
@@ -1,3 +1,519 @@
|
|
|
1
|
-
|
|
1
|
+
<!--
|
|
2
|
+
AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
3
|
+
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
|
+
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
|
+
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
+
Generated: 2026-10-19T18:03:27.132Z
|
|
7
|
+
-->
|
|
2
8
|
|
|
3
|
-
|
|
9
|
+
# @molecule/api-deploy-rollout
|
|
10
|
+
|
|
11
|
+
Deploy-rollout core interface for molecule.dev.
|
|
12
|
+
|
|
13
|
+
Replaces the running instances of a deployment with new ones without taking the
|
|
14
|
+
deployment down — grow-then-shrink (create the new set, gate it ready, join it,
|
|
15
|
+
then retire the old one at a time) and in-place (change the same instances one at
|
|
16
|
+
a time, with a restore path). The package carries the contract only:
|
|
17
|
+
`@molecule/api-deploy-rollout-default` is the algorithm, `-fly` and `-sandbox`
|
|
18
|
+
adapt concrete instance providers.
|
|
19
|
+
|
|
20
|
+
> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
|
|
21
|
+
> It is written to be read by coding agents as much as by people, and is generated from this
|
|
22
|
+
> package's source — edit `src/index.ts` JSDoc, not this file.
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { setProvider, runRollout } from '@molecule/api-deploy-rollout'
|
|
28
|
+
import { provider } from '@molecule/api-deploy-rollout-default'
|
|
29
|
+
|
|
30
|
+
setProvider(provider)
|
|
31
|
+
|
|
32
|
+
const outcome = await runRollout({
|
|
33
|
+
provider: myInstanceProvider,
|
|
34
|
+
current: oldInstances,
|
|
35
|
+
policy: { replicas: 2, soakMs: 30_000, drainMs: 25_000 },
|
|
36
|
+
})
|
|
37
|
+
// outcome.status === 'completed' when the new set is serving
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Type
|
|
41
|
+
|
|
42
|
+
`core`
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm install @molecule/api-deploy-rollout @molecule/api-bond
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API
|
|
51
|
+
|
|
52
|
+
### Interfaces
|
|
53
|
+
|
|
54
|
+
#### `RolloutInstance`
|
|
55
|
+
|
|
56
|
+
One instance a rollout can act on.
|
|
57
|
+
|
|
58
|
+
`id` is the provider's stable handle. `upstreamUrl` is the routable address the
|
|
59
|
+
deployment's edge dials, when the provider has one — a rollout that only
|
|
60
|
+
restarts instances in place does not need it.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
interface RolloutInstance {
|
|
64
|
+
/** Provider instance id. */
|
|
65
|
+
id: string
|
|
66
|
+
/** The routable upstream URL, when the provider exposes one. */
|
|
67
|
+
upstreamUrl?: string
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### `InstanceProvider`
|
|
72
|
+
|
|
73
|
+
What a grow-then-shrink rollout needs from whatever hosts the instances.
|
|
74
|
+
|
|
75
|
+
The caller implements this over its hosting provider; the `-sandbox` bond does it
|
|
76
|
+
over `@molecule/api-code-sandbox`, and tests drive it with a fake that records the
|
|
77
|
+
order and can fail any step.
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
interface InstanceProvider<I extends RolloutInstance = RolloutInstance> {
|
|
81
|
+
/** A human-readable provider name, for progress lines. */
|
|
82
|
+
readonly name?: string
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Every instance the deployment currently owns, when the provider can enumerate
|
|
86
|
+
* them. Used to resume an interrupted rollout idempotently: an instance already
|
|
87
|
+
* ready and joined is not created twice.
|
|
88
|
+
*/
|
|
89
|
+
list?(): Promise<I[]>
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Create the instance at `index` (0-based, above any primary the caller created
|
|
93
|
+
* itself). It must not be routable until {@link InstanceProvider.join}.
|
|
94
|
+
*
|
|
95
|
+
* @param index - Which instance this is.
|
|
96
|
+
* @returns The created instance.
|
|
97
|
+
*/
|
|
98
|
+
create(index: number): Promise<I>
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Resolve once the instance may take traffic.
|
|
102
|
+
*
|
|
103
|
+
* @param instance - The instance to gate.
|
|
104
|
+
* @param timeoutMs - The policy's readiness budget, for providers whose probe
|
|
105
|
+
* accepts one.
|
|
106
|
+
* @returns `false` when it never became ready (the rollout aborts).
|
|
107
|
+
*/
|
|
108
|
+
waitReady(instance: I, timeoutMs?: number): Promise<boolean>
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* A single, fast readiness probe, for the soak window. Optional: a caller that
|
|
112
|
+
* sets `soakMs` must provide it, because a blocking readiness wait cannot tell a
|
|
113
|
+
* warm instance from a recovering one.
|
|
114
|
+
*
|
|
115
|
+
* @param instance - The instance to probe.
|
|
116
|
+
* @returns Whether it is serving right now.
|
|
117
|
+
*/
|
|
118
|
+
isServing?(instance: I): Promise<boolean>
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Add the instance to the routable set, so the edge may send it new requests.
|
|
122
|
+
*
|
|
123
|
+
* @param instance - A ready instance.
|
|
124
|
+
*/
|
|
125
|
+
join(instance: I): Promise<void>
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Remove the instance from the routable set, so no NEW request is routed to it.
|
|
129
|
+
* Requests already in flight are untouched.
|
|
130
|
+
*
|
|
131
|
+
* @param instance - The instance being retired.
|
|
132
|
+
*/
|
|
133
|
+
leave(instance: I): Promise<void>
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Tell the instance to drain: finish in-flight work and stop accepting new
|
|
137
|
+
* connections. Resolve when it may be destroyed, and never later than `drainMs`.
|
|
138
|
+
*
|
|
139
|
+
* @param instance - The retired instance.
|
|
140
|
+
* @param drainMs - The bounded wait.
|
|
141
|
+
*/
|
|
142
|
+
drain(instance: I, drainMs: number): Promise<void>
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Destroy the instance, releasing whatever it costs.
|
|
146
|
+
*
|
|
147
|
+
* @param instance - The instance to remove.
|
|
148
|
+
*/
|
|
149
|
+
destroy(instance: I): Promise<void>
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### `InPlaceInstanceProvider`
|
|
154
|
+
|
|
155
|
+
What an in-place rollout needs from whatever hosts the instances.
|
|
156
|
+
|
|
157
|
+
Every instance keeps its identity; `replace` changes it to the new build and
|
|
158
|
+
`restore` puts it back on the old one. The caller supplies {@link list} so a
|
|
159
|
+
resumed rollout can see what is already there.
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
interface InPlaceInstanceProvider<I extends RolloutInstance = RolloutInstance> {
|
|
163
|
+
/** A human-readable provider name, for progress lines. */
|
|
164
|
+
readonly name?: string
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Every instance the rollout may act on, in roll order.
|
|
168
|
+
*
|
|
169
|
+
* @returns The instances.
|
|
170
|
+
*/
|
|
171
|
+
list(): Promise<I[]>
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Whether the instance is serving requests right now.
|
|
175
|
+
*
|
|
176
|
+
* @param instance - The instance to probe.
|
|
177
|
+
* @returns `true` while it answers its readiness probe.
|
|
178
|
+
*/
|
|
179
|
+
isServing(instance: I): Promise<boolean>
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Change the instance to the new build and leave it serving.
|
|
183
|
+
*
|
|
184
|
+
* @param instance - The instance to change.
|
|
185
|
+
*/
|
|
186
|
+
replace(instance: I): Promise<void>
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Put the instance back on the old build. Called only for instances this run
|
|
190
|
+
* already replaced.
|
|
191
|
+
*
|
|
192
|
+
* @param instance - The instance to restore.
|
|
193
|
+
*/
|
|
194
|
+
restore(instance: I): Promise<void>
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
#### `RolloutPolicy`
|
|
199
|
+
|
|
200
|
+
How a rollout bounds itself.
|
|
201
|
+
|
|
202
|
+
Every field is optional on the caller's side; the bond fills in the defaults
|
|
203
|
+
documented here.
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
interface RolloutPolicy {
|
|
207
|
+
/**
|
|
208
|
+
* How many instances the NEW set holds, for a grow-then-shrink rollout. The
|
|
209
|
+
* caller's own primary instance is not created here, so the bond creates
|
|
210
|
+
* `replicas - 1`. Defaults to `current.length` (a like-for-like replacement).
|
|
211
|
+
*/
|
|
212
|
+
replicas?: number
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* The most instances that may be unavailable at once. When set, the bond derives
|
|
216
|
+
* `minHealthy = max(1, instances - maxUnavailable)` and refuses a step that would
|
|
217
|
+
* go below it. Default: `minHealthy` is 1 — never blank the deployment.
|
|
218
|
+
*/
|
|
219
|
+
maxUnavailable?: number
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* An absolute floor on healthy instances. Overrides the value derived from
|
|
223
|
+
* {@link RolloutPolicy.maxUnavailable}. Defaults to 1.
|
|
224
|
+
*/
|
|
225
|
+
minHealthy?: number
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* How long a changed instance must keep answering without a gap before the next
|
|
229
|
+
* step starts. Passing one probe is not proof of a warm instance; a gap restarts
|
|
230
|
+
* the window. Defaults to 0 (no soak).
|
|
231
|
+
*/
|
|
232
|
+
soakMs?: number
|
|
233
|
+
|
|
234
|
+
/** Probe cadence during the soak. Defaults to 2000 ms. */
|
|
235
|
+
soakProbeMs?: number
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* How long the soak may keep retrying before the rollout aborts. Defaults to
|
|
239
|
+
* `soakMs + 60 s`.
|
|
240
|
+
*/
|
|
241
|
+
soakGraceMs?: number
|
|
242
|
+
|
|
243
|
+
/** How long a retired instance may take to drain. Defaults to 25 s. */
|
|
244
|
+
drainMs?: number
|
|
245
|
+
|
|
246
|
+
/** The readiness budget handed to `waitReady`. Defaults to 120 s. */
|
|
247
|
+
readinessTimeoutMs?: number
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* What an abort does to instances this run already changed: `reverse` restores
|
|
251
|
+
* them newest first (the default), `none` leaves them as they are.
|
|
252
|
+
*/
|
|
253
|
+
rollback?: 'reverse' | 'none'
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Whether a rollout reconciles against the provider's current instances instead
|
|
257
|
+
* of starting from the caller's list. Defaults to true; a provider without
|
|
258
|
+
* `list()` falls back to the caller's list.
|
|
259
|
+
*/
|
|
260
|
+
resume?: boolean
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
#### `RolloutFailure`
|
|
265
|
+
|
|
266
|
+
A step that failed but did not stop the rollout (a retirement or rollback step).
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
interface RolloutFailure<I extends RolloutInstance = RolloutInstance> {
|
|
270
|
+
/** The instance the step addressed. */
|
|
271
|
+
instance: I
|
|
272
|
+
/** The step that failed. */
|
|
273
|
+
step: RolloutStep
|
|
274
|
+
/** Whatever was thrown, for the caller's log. */
|
|
275
|
+
error: unknown
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### `RolloutOutcome`
|
|
280
|
+
|
|
281
|
+
What a completed or aborted rollout did.
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
interface RolloutOutcome<I extends RolloutInstance = RolloutInstance> {
|
|
285
|
+
/** `completed` when the target set is serving; `aborted` otherwise. */
|
|
286
|
+
status: 'completed' | 'aborted'
|
|
287
|
+
/** Every instance this run created and joined, in creation order. */
|
|
288
|
+
created: I[]
|
|
289
|
+
/** Every new instance that is healthy and joined. */
|
|
290
|
+
upstreams: I[]
|
|
291
|
+
/** Old instances this run removed from the set and destroyed. */
|
|
292
|
+
retired: I[]
|
|
293
|
+
/** Steps that failed but did not stop the rollout. */
|
|
294
|
+
failures: RolloutFailure<I>[]
|
|
295
|
+
/** Instances this run restored, newest first (an in-place abort). */
|
|
296
|
+
rolledBack: string[]
|
|
297
|
+
/** Restores that themselves failed. */
|
|
298
|
+
rollbackFailures: RolloutFailure<I>[]
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
#### `InPlaceRolloutOutcome`
|
|
303
|
+
|
|
304
|
+
What an in-place rollout did.
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
interface InPlaceRolloutOutcome<I extends RolloutInstance = RolloutInstance> {
|
|
308
|
+
/** The instances changed successfully, in roll order. */
|
|
309
|
+
applied: string[]
|
|
310
|
+
/** Every instance that passed its gate. */
|
|
311
|
+
instances: I[]
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
#### `RolloutOptions`
|
|
316
|
+
|
|
317
|
+
What {@link InstanceProvider} needs for one grow-then-shrink rollout.
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
interface RolloutOptions<I extends RolloutInstance = RolloutInstance> {
|
|
321
|
+
/** The instance provider. */
|
|
322
|
+
provider: InstanceProvider<I>
|
|
323
|
+
/** The instances serving right now (empty on a first deploy). */
|
|
324
|
+
current?: readonly I[]
|
|
325
|
+
/** Rollout bounds; the bond fills the defaults. */
|
|
326
|
+
policy?: RolloutPolicy
|
|
327
|
+
/** Optional progress sink — plain sentences. */
|
|
328
|
+
log?: (line: string) => Promise<void> | void
|
|
329
|
+
/** Consulted between steps; `true` aborts and keeps the old set serving. */
|
|
330
|
+
isCancelled?: () => Promise<boolean> | boolean
|
|
331
|
+
/**
|
|
332
|
+
* Set when the caller has already created and joined ONE instance of the new
|
|
333
|
+
* set (the primary), outside this rollout. It counts toward healthy capacity.
|
|
334
|
+
*/
|
|
335
|
+
primaryServing?: boolean
|
|
336
|
+
/** Injectable clock, for tests. Defaults to `Date.now`. */
|
|
337
|
+
now?: () => number
|
|
338
|
+
/** Injectable sleep, for tests. Defaults to a real timer. */
|
|
339
|
+
sleep?: (ms: number) => Promise<void>
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
#### `DeployRolloutProvider`
|
|
344
|
+
|
|
345
|
+
The contract every deploy-rollout bond implements.
|
|
346
|
+
|
|
347
|
+
The two methods are the two real deployment topologies; a bond that supports
|
|
348
|
+
only one rejects the other with a clear error rather than silently doing
|
|
349
|
+
nothing.
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
interface DeployRolloutProvider {
|
|
353
|
+
/** A human-readable provider name, for diagnostics. */
|
|
354
|
+
readonly name: string
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Run a grow-then-shrink replacement of a deployment's instances.
|
|
358
|
+
*
|
|
359
|
+
* @param options - The set to build, the old set, and the instance provider.
|
|
360
|
+
* @returns What the rollout did.
|
|
361
|
+
*/
|
|
362
|
+
run<I extends RolloutInstance>(options: RolloutOptions<I>): Promise<RolloutOutcome<I>>
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Run an in-place replacement (the same instances changed one at a time).
|
|
366
|
+
*
|
|
367
|
+
* @param options - The instances to roll and the provider or callbacks.
|
|
368
|
+
* @returns What the rollout did.
|
|
369
|
+
*/
|
|
370
|
+
runInPlace<I extends RolloutInstance>(
|
|
371
|
+
options: InPlaceRolloutOptions<I>,
|
|
372
|
+
): Promise<InPlaceRolloutOutcome<I>>
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
#### `InPlaceRolloutOptions`
|
|
377
|
+
|
|
378
|
+
What an in-place rollout needs.
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
interface InPlaceRolloutOptions<I extends RolloutInstance = RolloutInstance> {
|
|
382
|
+
/**
|
|
383
|
+
* The instances to roll. When absent, the provider's own list is used.
|
|
384
|
+
*/
|
|
385
|
+
machines?: readonly I[]
|
|
386
|
+
/**
|
|
387
|
+
* A provider that owns the operations. Alternatively pass `apply`/`rollback`/
|
|
388
|
+
* `probeServing` directly; the provider is a convenience for callers that
|
|
389
|
+
* already model their hosting this way.
|
|
390
|
+
*/
|
|
391
|
+
provider?: InPlaceInstanceProvider<I>
|
|
392
|
+
/** Change one instance and leave it serving on the NEW build. */
|
|
393
|
+
apply?: (instance: I) => Promise<void>
|
|
394
|
+
/** Put one instance back on the OLD build. */
|
|
395
|
+
rollback?: (instance: I) => Promise<void>
|
|
396
|
+
/** Whether an instance is serving right now. */
|
|
397
|
+
probeServing?: (instanceId: string) => Promise<boolean>
|
|
398
|
+
/** Rollout bounds; the bond fills the defaults. */
|
|
399
|
+
policy?: RolloutPolicy
|
|
400
|
+
/** Pause between instances. Defaults to 0. */
|
|
401
|
+
betweenMs?: number
|
|
402
|
+
/** Optional progress sink — plain sentences. */
|
|
403
|
+
log?: (line: string) => Promise<void> | void
|
|
404
|
+
/** Consulted before each instance; `true` aborts and rolls back. */
|
|
405
|
+
isCancelled?: () => Promise<boolean> | boolean
|
|
406
|
+
/** Injectable clock, for tests. Defaults to `Date.now`. */
|
|
407
|
+
now?: () => number
|
|
408
|
+
/** Injectable sleep, for tests. Defaults to a real timer. */
|
|
409
|
+
sleep?: (ms: number) => Promise<void>
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Types
|
|
414
|
+
|
|
415
|
+
#### `RolloutStep`
|
|
416
|
+
|
|
417
|
+
The step of a rollout that produced a result or a failure.
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
type RolloutStep =
|
|
421
|
+
| 'create'
|
|
422
|
+
| 'ready'
|
|
423
|
+
| 'join'
|
|
424
|
+
| 'leave'
|
|
425
|
+
| 'drain'
|
|
426
|
+
| 'destroy'
|
|
427
|
+
| 'replace'
|
|
428
|
+
| 'restore'
|
|
429
|
+
| 'capacity'
|
|
430
|
+
| 'cancelled'
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Functions
|
|
434
|
+
|
|
435
|
+
#### `setProvider(provider)`
|
|
436
|
+
|
|
437
|
+
Registers a deploy-rollout provider as the active singleton. Called by a bond
|
|
438
|
+
package during application startup.
|
|
439
|
+
|
|
440
|
+
```typescript
|
|
441
|
+
function setProvider(provider: DeployRolloutProvider): void
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
- `provider` — The provider implementation to bond.
|
|
445
|
+
|
|
446
|
+
#### `getProvider()`
|
|
447
|
+
|
|
448
|
+
Retrieves the bonded deploy-rollout provider, throwing if none is wired.
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
function getProvider(): DeployRolloutProvider
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**Returns:** The bonded provider.
|
|
455
|
+
|
|
456
|
+
#### `hasProvider()`
|
|
457
|
+
|
|
458
|
+
Checks whether a deploy-rollout provider is currently bonded.
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
function hasProvider(): boolean
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
**Returns:** `true` if a provider is bonded.
|
|
465
|
+
|
|
466
|
+
#### `runRollout(options)`
|
|
467
|
+
|
|
468
|
+
Runs a grow-then-shrink rollout through the bonded provider.
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
function runRollout(options: RolloutOptions<I>): Promise<RolloutOutcome<I>>
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
- `options` — The set to build, the old set, and the instance provider.
|
|
475
|
+
|
|
476
|
+
**Returns:** What the rollout did.
|
|
477
|
+
|
|
478
|
+
#### `runInPlaceRollout(options)`
|
|
479
|
+
|
|
480
|
+
Runs an in-place rollout (the same instances changed one at a time) through the
|
|
481
|
+
bonded provider.
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
function runInPlaceRollout(options: InPlaceRolloutOptions<I>): Promise<InPlaceRolloutOutcome<I>>
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
- `options` — The instances to roll and the provider or callbacks.
|
|
488
|
+
|
|
489
|
+
**Returns:** What the rollout did.
|
|
490
|
+
|
|
491
|
+
## Available Providers
|
|
492
|
+
|
|
493
|
+
| Provider | Package |
|
|
494
|
+
| ------------ | -------------------------------------- |
|
|
495
|
+
| Default | `@molecule/api-deploy-rollout-default` |
|
|
496
|
+
| Fly Machines | `@molecule/api-deploy-rollout-fly` |
|
|
497
|
+
| Sandbox | `@molecule/api-deploy-rollout-sandbox` |
|
|
498
|
+
|
|
499
|
+
## Injection Notes
|
|
500
|
+
|
|
501
|
+
### Requirements
|
|
502
|
+
|
|
503
|
+
Peer dependencies:
|
|
504
|
+
|
|
505
|
+
- `@molecule/api-bond` ^1.0.1
|
|
506
|
+
|
|
507
|
+
### Runtime Dependencies
|
|
508
|
+
|
|
509
|
+
- `@molecule/api-bond`
|
|
510
|
+
|
|
511
|
+
- **The core has no implementation.** The state machine, the soak, the capacity
|
|
512
|
+
floor and the reverse rollback live in a bond, so a caller can swap in a
|
|
513
|
+
provider whose rules differ without touching its own code.
|
|
514
|
+
- **Never reduces healthy capacity below the floor.** A step that would leave
|
|
515
|
+
fewer healthy instances than the policy allows is refused, not attempted.
|
|
516
|
+
- **An abort keeps the old set serving.** Every instance created or changed by
|
|
517
|
+
the run is undone, newest first, before the error is thrown.
|
|
518
|
+
- **Idempotent resume.** Re-running a rollout after an interruption reconciles
|
|
519
|
+
against the provider's current instances instead of creating duplicates.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-guard.d.ts","sourceRoot":"","sources":["../src/browser-guard.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser guard — `@molecule/api-deploy-rollout` is SERVER-ONLY.
|
|
3
|
+
*
|
|
4
|
+
* Generated by scripts/gen-browser-guards.mjs (workspace root) — edit THAT, not this.
|
|
5
|
+
* Evaluating a server package in a browser bundle is always an import-graph mistake
|
|
6
|
+
* (node APIs, secrets); without this guard it surfaces as a cryptic downstream crash
|
|
7
|
+
* ("Buffer is not defined") far from the culprit. Throwing here names the package and
|
|
8
|
+
* the fix at the exact moment the client bundle evaluates it. jsdom tests and SSR are
|
|
9
|
+
* unaffected: the throw requires browser globals AND the absence of a node runtime.
|
|
10
|
+
*/
|
|
11
|
+
const g = globalThis;
|
|
12
|
+
if (g.window !== undefined && g.document !== undefined && !g.process?.versions?.node) {
|
|
13
|
+
throw new Error('@molecule/api-deploy-rollout is SERVER-ONLY: it was bundled into browser/client code. Import it only ' +
|
|
14
|
+
'from server code (a server route/function or your API), or dynamic-import it inside ' +
|
|
15
|
+
'the server handler — never from components or shared client modules, and never ' +
|
|
16
|
+
'polyfill Buffer/process to silence this.');
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=browser-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-guard.js","sourceRoot":"","sources":["../src/browser-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,GAAG,UAIT,CAAA;AACD,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACrF,MAAM,IAAI,KAAK,CACb,uGAAuG;QACrG,sFAAsF;QACtF,iFAAiF;QACjF,0CAA0C,CAC7C,CAAA;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deploy-rollout core interface for molecule.dev.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the running instances of a deployment with new ones without taking the
|
|
5
|
+
* deployment down — grow-then-shrink (create the new set, gate it ready, join it,
|
|
6
|
+
* then retire the old one at a time) and in-place (change the same instances one at
|
|
7
|
+
* a time, with a restore path). The package carries the contract only:
|
|
8
|
+
* `@molecule/api-deploy-rollout-default` is the algorithm, `-fly` and `-sandbox`
|
|
9
|
+
* adapt concrete instance providers.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { setProvider, runRollout } from '@molecule/api-deploy-rollout'
|
|
14
|
+
* import { provider } from '@molecule/api-deploy-rollout-default'
|
|
15
|
+
*
|
|
16
|
+
* setProvider(provider)
|
|
17
|
+
*
|
|
18
|
+
* const outcome = await runRollout({
|
|
19
|
+
* provider: myInstanceProvider,
|
|
20
|
+
* current: oldInstances,
|
|
21
|
+
* policy: { replicas: 2, soakMs: 30_000, drainMs: 25_000 },
|
|
22
|
+
* })
|
|
23
|
+
* // outcome.status === 'completed' when the new set is serving
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* - **The core has no implementation.** The state machine, the soak, the capacity
|
|
28
|
+
* floor and the reverse rollback live in a bond, so a caller can swap in a
|
|
29
|
+
* provider whose rules differ without touching its own code.
|
|
30
|
+
* - **Never reduces healthy capacity below the floor.** A step that would leave
|
|
31
|
+
* fewer healthy instances than the policy allows is refused, not attempted.
|
|
32
|
+
* - **An abort keeps the old set serving.** Every instance created or changed by
|
|
33
|
+
* the run is undone, newest first, before the error is thrown.
|
|
34
|
+
* - **Idempotent resume.** Re-running a rollout after an interruption reconciles
|
|
35
|
+
* against the provider's current instances instead of creating duplicates.
|
|
36
|
+
*
|
|
37
|
+
* @module
|
|
38
|
+
*/
|
|
39
|
+
export * from './browser-guard.js';
|
|
40
|
+
export * from './provider.js';
|
|
41
|
+
export * from './types.js';
|
|
42
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deploy-rollout core interface for molecule.dev.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the running instances of a deployment with new ones without taking the
|
|
5
|
+
* deployment down — grow-then-shrink (create the new set, gate it ready, join it,
|
|
6
|
+
* then retire the old one at a time) and in-place (change the same instances one at
|
|
7
|
+
* a time, with a restore path). The package carries the contract only:
|
|
8
|
+
* `@molecule/api-deploy-rollout-default` is the algorithm, `-fly` and `-sandbox`
|
|
9
|
+
* adapt concrete instance providers.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { setProvider, runRollout } from '@molecule/api-deploy-rollout'
|
|
14
|
+
* import { provider } from '@molecule/api-deploy-rollout-default'
|
|
15
|
+
*
|
|
16
|
+
* setProvider(provider)
|
|
17
|
+
*
|
|
18
|
+
* const outcome = await runRollout({
|
|
19
|
+
* provider: myInstanceProvider,
|
|
20
|
+
* current: oldInstances,
|
|
21
|
+
* policy: { replicas: 2, soakMs: 30_000, drainMs: 25_000 },
|
|
22
|
+
* })
|
|
23
|
+
* // outcome.status === 'completed' when the new set is serving
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* - **The core has no implementation.** The state machine, the soak, the capacity
|
|
28
|
+
* floor and the reverse rollback live in a bond, so a caller can swap in a
|
|
29
|
+
* provider whose rules differ without touching its own code.
|
|
30
|
+
* - **Never reduces healthy capacity below the floor.** A step that would leave
|
|
31
|
+
* fewer healthy instances than the policy allows is refused, not attempted.
|
|
32
|
+
* - **An abort keeps the old set serving.** Every instance created or changed by
|
|
33
|
+
* the run is undone, newest first, before the error is thrown.
|
|
34
|
+
* - **Idempotent resume.** Re-running a rollout after an interruption reconciles
|
|
35
|
+
* against the provider's current instances instead of creating duplicates.
|
|
36
|
+
*
|
|
37
|
+
* @module
|
|
38
|
+
*/
|
|
39
|
+
export * from './browser-guard.js';
|
|
40
|
+
export * from './provider.js';
|
|
41
|
+
export * from './types.js';
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accessors for the bonded deploy-rollout provider.
|
|
3
|
+
*
|
|
4
|
+
* A provider bond (e.g. `@molecule/api-deploy-rollout-default`) calls
|
|
5
|
+
* `setProvider()` during application startup. Application code uses the
|
|
6
|
+
* convenience accessors (`runRollout`, `runInPlaceRollout`), which delegate to the
|
|
7
|
+
* bonded provider, so the hosting-specific algorithm is a wiring decision rather
|
|
8
|
+
* than an import.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import type { DeployRolloutProvider, InPlaceRolloutOptions, InPlaceRolloutOutcome, RolloutInstance, RolloutOptions, RolloutOutcome } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Registers a deploy-rollout provider as the active singleton. Called by a bond
|
|
15
|
+
* package during application startup.
|
|
16
|
+
*
|
|
17
|
+
* @param provider - The provider implementation to bond.
|
|
18
|
+
*/
|
|
19
|
+
export declare const setProvider: (provider: DeployRolloutProvider) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Retrieves the bonded deploy-rollout provider, throwing if none is wired.
|
|
22
|
+
*
|
|
23
|
+
* @returns The bonded provider.
|
|
24
|
+
* @throws {Error} If no deploy-rollout provider has been bonded.
|
|
25
|
+
*/
|
|
26
|
+
export declare const getProvider: () => DeployRolloutProvider;
|
|
27
|
+
/**
|
|
28
|
+
* Checks whether a deploy-rollout provider is currently bonded.
|
|
29
|
+
*
|
|
30
|
+
* @returns `true` if a provider is bonded.
|
|
31
|
+
*/
|
|
32
|
+
export declare const hasProvider: () => boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Runs a grow-then-shrink rollout through the bonded provider.
|
|
35
|
+
*
|
|
36
|
+
* @param options - The set to build, the old set, and the instance provider.
|
|
37
|
+
* @returns What the rollout did.
|
|
38
|
+
*/
|
|
39
|
+
export declare const runRollout: <I extends RolloutInstance>(options: RolloutOptions<I>) => Promise<RolloutOutcome<I>>;
|
|
40
|
+
/**
|
|
41
|
+
* Runs an in-place rollout (the same instances changed one at a time) through the
|
|
42
|
+
* bonded provider.
|
|
43
|
+
*
|
|
44
|
+
* @param options - The instances to roll and the provider or callbacks.
|
|
45
|
+
* @returns What the rollout did.
|
|
46
|
+
*/
|
|
47
|
+
export declare const runInPlaceRollout: <I extends RolloutInstance>(options: InPlaceRolloutOptions<I>) => Promise<InPlaceRolloutOutcome<I>>;
|
|
48
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EACV,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,cAAc,EACf,MAAM,YAAY,CAAA;AAInB;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,UAAU,qBAAqB,KAAG,IAE7D,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,QAAO,qBAS9B,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,QAAO,OAE9B,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,eAAe,EAClD,SAAS,cAAc,CAAC,CAAC,CAAC,KACzB,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAE3B,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,eAAe,EACzD,SAAS,qBAAqB,CAAC,CAAC,CAAC,KAChC,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAElC,CAAA"}
|