@heroku/sdk 0.2.0-beta.0 → 0.4.0-beta.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/dist/resources/data/database.d.ts +1 -1
- package/dist/resources/data/maintenance.d.ts +1 -1
- package/dist/resources/data/postgres-database.d.ts +1 -1
- package/dist/resources/data/transfer.d.ts +1 -1
- package/dist/resources/extensions/platform.d.ts +1 -1
- package/dist/resources/extensions/platform.js +1 -1
- package/dist/resources/platform/add-on/index.d.ts +1 -1
- package/dist/resources/platform/app/index.d.ts +1 -1
- package/dist/resources/platform/dyno/index.d.ts +4 -2
- package/dist/resources/platform/dyno/index.js +3 -0
- package/dist/resources/platform/dyno/wait-for-info.d.ts +95 -0
- package/dist/resources/platform/dyno/wait-for-info.js +108 -0
- package/dist/resources/platform/log-session/index.d.ts +1 -1
- package/dist/resources/platform/pipeline/coupling.d.ts +1 -1
- package/dist/resources/platform/pipeline/index.d.ts +1 -1
- package/dist/resources/platform/pipeline/promotion.d.ts +1 -1
- package/package.json +51 -7
|
@@ -43,7 +43,7 @@ export declare function dryRunUpgrade(ctx: DatabaseCtx, appIdentity: string, add
|
|
|
43
43
|
export declare function runUpgrade(ctx: DatabaseCtx, appIdentity: string, addonIdentity?: string, body?: DatabaseUpgradeBody, options?: DatabaseOptions): Promise<DatabaseUpgradeResponse>;
|
|
44
44
|
export declare function prepareUpgrade(ctx: DatabaseCtx, appIdentity: string, addonIdentity?: string, body?: DatabaseUpgradeBody, options?: DatabaseOptions): Promise<DatabaseUpgradeResponse>;
|
|
45
45
|
export declare function cancelUpgrade(ctx: DatabaseCtx, appIdentity: string, addonIdentity?: string, options?: DatabaseOptions): Promise<DatabaseUpgradeResponse>;
|
|
46
|
-
export declare const databaseExtensions: import("../../
|
|
46
|
+
export declare const databaseExtensions: import("../../core/extend-resource.js").ResourceExtension<"data", "database", {
|
|
47
47
|
cancelUpgrade: (appIdentity: string, addonIdentity?: string, options?: DatabaseOptions) => Promise<DatabaseUpgradeResponse>;
|
|
48
48
|
describe: (appIdentity: string, addonIdentity?: string, options?: DatabaseOptions) => Promise<DatabaseDescribeResult>;
|
|
49
49
|
dryRunUpgrade: (appIdentity: string, addonIdentity?: string, body?: DatabaseUpgradeBody, options?: DatabaseOptions) => Promise<DatabaseUpgradeResponse>;
|
|
@@ -4,6 +4,6 @@ export type MaintenanceInfoOptions = {
|
|
|
4
4
|
signal?: AbortSignal;
|
|
5
5
|
};
|
|
6
6
|
export declare function info(ctx: Pick<ResourceCtx, 'data' | 'platform'>, appIdentity: string, addonIdentity?: string, options?: MaintenanceInfoOptions): Promise<MaintenanceInfoResult>;
|
|
7
|
-
export declare const maintenanceExtensions: import("../../
|
|
7
|
+
export declare const maintenanceExtensions: import("../../core/extend-resource.js").ResourceExtension<"data", "maintenance", {
|
|
8
8
|
info: (appIdentity: string, addonIdentity?: string, options?: MaintenanceInfoOptions) => Promise<MaintenanceInfoResult>;
|
|
9
9
|
}>;
|
|
@@ -26,7 +26,7 @@ type CredentialsCtx = {
|
|
|
26
26
|
platform: ResourceCtx['platform'];
|
|
27
27
|
};
|
|
28
28
|
export declare function listCredentials(ctx: CredentialsCtx, appIdentity: string, addonIdentity?: string, options?: ListCredentialsOptions): Promise<CredentialInfo[]>;
|
|
29
|
-
export declare const postgresDatabaseExtensions: import("../../
|
|
29
|
+
export declare const postgresDatabaseExtensions: import("../../core/extend-resource.js").ResourceExtension<"data", "postgresDatabase", {
|
|
30
30
|
listCredentials: (appIdentity: string, addonIdentity?: string, options?: ListCredentialsOptions) => Promise<CredentialInfo[]>;
|
|
31
31
|
}>;
|
|
32
32
|
export {};
|
|
@@ -43,7 +43,7 @@ type TransferCtx = {
|
|
|
43
43
|
platform: ResourceCtx['platform'];
|
|
44
44
|
};
|
|
45
45
|
export declare function listByApp(ctx: TransferCtx, appIdentity: string, addonIdentity?: string, options?: TransferOptions): Promise<BackupTransfer[]>;
|
|
46
|
-
export declare const transferExtensions: import("../../
|
|
46
|
+
export declare const transferExtensions: import("../../core/extend-resource.js").ResourceExtension<"data", "transfer", {
|
|
47
47
|
listByApp: (appIdentity: string, addonIdentity?: string, options?: TransferOptions) => Promise<BackupTransfer[]>;
|
|
48
48
|
}>;
|
|
49
49
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { addOnExtensions } from '../platform/add-on/index.js';
|
|
2
2
|
export { appExtensions, type AppInfo, type PipelineCouplingDetail } from '../platform/app/index.js';
|
|
3
|
-
export { dynoExtensions } from '../platform/dyno/index.js';
|
|
3
|
+
export { dynoExtensions, DynoNotReadyError, type DynoState, waitForInfo, type WaitForInfoOptions, } from '../platform/dyno/index.js';
|
|
4
4
|
export { type AttachmentAttachedEvent, type AttachmentDetachedEvent, type AttachmentUpdatedEvent, type HerokuLogEvent, logSessionExtensions, parseHerokuLogLine, type ProvisioningCompletedEvent, type ScaledToEntry, type ScaledToEvent, type StartingProcessEvent, type StateChangedEvent, } from '../platform/log-session/index.js';
|
|
5
5
|
export { pipelineCouplingExtensions } from '../platform/pipeline/coupling.js';
|
|
6
6
|
export { pipelineExtensions } from '../platform/pipeline/index.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { addOnExtensions } from '../platform/add-on/index.js';
|
|
2
2
|
export { appExtensions } from '../platform/app/index.js';
|
|
3
|
-
export { dynoExtensions } from '../platform/dyno/index.js';
|
|
3
|
+
export { dynoExtensions, DynoNotReadyError, waitForInfo, } from '../platform/dyno/index.js';
|
|
4
4
|
export { logSessionExtensions, parseHerokuLogLine, } from '../platform/log-session/index.js';
|
|
5
5
|
export { pipelineCouplingExtensions } from '../platform/pipeline/coupling.js';
|
|
6
6
|
export { pipelineExtensions } from '../platform/pipeline/index.js';
|
|
@@ -10,7 +10,7 @@ export { formatPlanPriceLabel, type FormatPlanPriceLabelOptions, type PlanPriceB
|
|
|
10
10
|
export { resolveAddon, resolveAddonByAttachment } from './resolve.js';
|
|
11
11
|
export type { AddOnOptions, CreateAndWaitOptions, DescribedAddOn, ResolveAddonOptions, ResolvedAddOn, UpgradeAddOnOptions, } from './types.js';
|
|
12
12
|
export { upgrade } from './upgrade.js';
|
|
13
|
-
export declare const addOnExtensions: import("../../../
|
|
13
|
+
export declare const addOnExtensions: import("../../../core/extend-resource.js").ResourceExtension<"platform", "addOn", {
|
|
14
14
|
createAndWait: (appIdentity: string, body: AddOnCreateOpts, options?: CreateAndWaitOptions) => Promise<import("@heroku/types/3.sdk").AddOn>;
|
|
15
15
|
describe: (addonIdentity: string, options?: ResolveAddonOptions) => Promise<import("./types.js").DescribedAddOn>;
|
|
16
16
|
formatPlanPriceLabel: typeof formatPlanPriceLabel;
|
|
@@ -48,7 +48,7 @@ export declare function isShielded(ctx: {
|
|
|
48
48
|
export declare function getProcessTier(ctx: {
|
|
49
49
|
platform: AppInfoPlatform;
|
|
50
50
|
}, appIdentity: string, options?: GetProcessTierOptions): Promise<ProcessTier | undefined>;
|
|
51
|
-
export declare const appExtensions: import("../../../
|
|
51
|
+
export declare const appExtensions: import("../../../core/extend-resource.js").ResourceExtension<"platform", "app", {
|
|
52
52
|
describe: (appIdentity: string, options?: DescribeAppOptions) => Promise<import("./info.js").AppInfo>;
|
|
53
53
|
disableMaintenance: (appIdentity: string, options?: AppMaintenanceOptions) => Promise<App>;
|
|
54
54
|
enableMaintenance: (appIdentity: string, options?: AppMaintenanceOptions) => Promise<App>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Formation } from '@heroku/types/3.sdk';
|
|
2
2
|
import type { StickyRouteOptions } from '../../../core/create-client.js';
|
|
3
3
|
import type { ResourceCtx } from '../../../core/extend-resource.js';
|
|
4
|
+
import { type WaitForInfoOptions } from './wait-for-info.js';
|
|
5
|
+
export { DynoNotReadyError, type DynoState, waitForInfo, type WaitForInfoOptions, } from './wait-for-info.js';
|
|
4
6
|
export type DynoOptions = {
|
|
5
7
|
signal?: AbortSignal;
|
|
6
8
|
};
|
|
@@ -35,11 +37,11 @@ export declare function scaleDynos(ctx: {
|
|
|
35
37
|
platform: ScalePlatform;
|
|
36
38
|
}, appIdentity: string, updates: ScaleDynosUpdate[], options?: DynoOptions): Promise<Formation[]>;
|
|
37
39
|
export declare function restartDynos(ctx: Pick<ResourceCtx, 'platform'>, appIdentity: string, target?: RestartDynosTarget, options?: DynoOptions): Promise<void>;
|
|
38
|
-
export declare const dynoExtensions: import("../../../
|
|
40
|
+
export declare const dynoExtensions: import("../../../core/extend-resource.js").ResourceExtension<"platform", "dyno", {
|
|
39
41
|
restart: (appIdentity: string, target?: RestartDynosTarget, options?: DynoOptions) => Promise<void>;
|
|
40
42
|
scale: {
|
|
41
43
|
(appIdentity: string, updates: ScaleDynosUpdate, options?: DynoOptions): Promise<Formation>;
|
|
42
44
|
(appIdentity: string, updates: ScaleDynosUpdate[], options?: DynoOptions): Promise<Formation[]>;
|
|
43
45
|
};
|
|
46
|
+
waitForInfo: (appIdentity: string, dynoIdentity: string, options?: WaitForInfoOptions) => Promise<import("@heroku/types/3.sdk").Dyno>;
|
|
44
47
|
}>;
|
|
45
|
-
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { extendResource } from '../../../core/extend-resource.js';
|
|
2
|
+
import { waitForInfo } from './wait-for-info.js';
|
|
3
|
+
export { DynoNotReadyError, waitForInfo, } from './wait-for-info.js';
|
|
2
4
|
export async function scaleDynos(ctx, appIdentity, updates, options = {}) {
|
|
3
5
|
options.signal?.throwIfAborted();
|
|
4
6
|
const platform = options.signal ? ctx.platform.withOptions({ signal: options.signal }) : ctx.platform;
|
|
@@ -23,4 +25,5 @@ export async function restartDynos(ctx, appIdentity, target, options = {}) {
|
|
|
23
25
|
export const dynoExtensions = extendResource('platform', 'dyno', ctx => ({
|
|
24
26
|
restart: (appIdentity, target, options) => (restartDynos(ctx, appIdentity, target, options)),
|
|
25
27
|
scale: ((appIdentity, updates, options) => scaleDynos(ctx, appIdentity, updates, options)),
|
|
28
|
+
waitForInfo: (appIdentity, dynoIdentity, options) => (waitForInfo(ctx, appIdentity, dynoIdentity, options)),
|
|
26
29
|
}));
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Dyno } from '@heroku/types/3.sdk';
|
|
2
|
+
import type { ResourceCtx } from '../../../core/extend-resource.js';
|
|
3
|
+
/**
|
|
4
|
+
* Documented dyno states from the Platform API:
|
|
5
|
+
* https://devcenter.heroku.com/articles/platform-api-reference#dyno
|
|
6
|
+
*
|
|
7
|
+
* Recommended for autocomplete in {@link WaitForInfoOptions.states},
|
|
8
|
+
* which accepts any string at runtime — the platform does not commit
|
|
9
|
+
* to a closed set, so the comparison is plain string equality.
|
|
10
|
+
*/
|
|
11
|
+
export type DynoState = 'crashed' | 'down' | 'idle' | 'starting' | 'up';
|
|
12
|
+
/**
|
|
13
|
+
* Thrown by {@link waitForInfo} when `states` was set, the dyno was
|
|
14
|
+
* reachable, but its `state` never matched within the configured
|
|
15
|
+
* number of attempts. Carries the last observed dyno so callers can
|
|
16
|
+
* branch on its state (e.g. distinguish a `crashed` dyno from one
|
|
17
|
+
* stuck in `starting`).
|
|
18
|
+
*/
|
|
19
|
+
export declare class DynoNotReadyError extends Error {
|
|
20
|
+
readonly dyno: Dyno;
|
|
21
|
+
readonly expectedStates: ReadonlyArray<string>;
|
|
22
|
+
readonly attempts: number;
|
|
23
|
+
readonly id = "dyno_not_ready";
|
|
24
|
+
constructor(dyno: Dyno, expectedStates: ReadonlyArray<string>, attempts: number);
|
|
25
|
+
}
|
|
26
|
+
export type WaitForInfoOptions = {
|
|
27
|
+
/**
|
|
28
|
+
* Maximum total number of `dyno.info` calls before giving up.
|
|
29
|
+
* Defaults to 20. Each attempt is one info call; the delay
|
|
30
|
+
* between attempts is {@link WaitForInfoOptions.delayMs}.
|
|
31
|
+
*/
|
|
32
|
+
attempts?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Delay between attempts in milliseconds. Defaults to 1000.
|
|
35
|
+
* On a 429 response, the platform's `Retry-After` header takes
|
|
36
|
+
* precedence over this value for the next wait.
|
|
37
|
+
*/
|
|
38
|
+
delayMs?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Fires after every successful `dyno.info` call, including ones
|
|
41
|
+
* whose `state` does not yet match {@link WaitForInfoOptions.states}
|
|
42
|
+
* and trigger another retry, AND for the final matching dyno
|
|
43
|
+
* before it is returned. Use this to surface live state
|
|
44
|
+
* transitions in a UI (e.g. a CLI spinner that updates
|
|
45
|
+
* `starting → up`). Not called when an attempt errors (404, 429,
|
|
46
|
+
* 503). Exceptions thrown from this callback propagate and end
|
|
47
|
+
* the wait — there is no implicit catch.
|
|
48
|
+
*/
|
|
49
|
+
onPoll?: (dyno: Dyno) => void;
|
|
50
|
+
signal?: AbortSignal;
|
|
51
|
+
/**
|
|
52
|
+
* If set, only return when the dyno's `state` is one of these.
|
|
53
|
+
* If omitted, the call returns on the first 2xx response
|
|
54
|
+
* regardless of state — useful for racing past the post-creation
|
|
55
|
+
* 404 window without waiting for the dyno to be runnable. The
|
|
56
|
+
* recommended values are documented as {@link DynoState}; any
|
|
57
|
+
* string is accepted.
|
|
58
|
+
*/
|
|
59
|
+
states?: ReadonlyArray<DynoState | string>;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Poll `dyno.info` until the dyno exists and (optionally) reaches a
|
|
63
|
+
* caller-specified state. Absorbs two distinct races:
|
|
64
|
+
*
|
|
65
|
+
* - **Post-creation 404.** The platform briefly returns 404 for a
|
|
66
|
+
* newly-provisioning dyno even after `dyno.create` resolves
|
|
67
|
+
* (also observable from log events emitting "Starting process"
|
|
68
|
+
* before the dyno row is queryable). Callers that just need the
|
|
69
|
+
* row to exist should omit `states` and accept the first 2xx —
|
|
70
|
+
* the dyno's `state` value does not gate the return.
|
|
71
|
+
* - **Wait for runnable.** Callers that need to act on the dyno
|
|
72
|
+
* (open an SSH connection, exec a one-off command) need it in
|
|
73
|
+
* `starting` or `up` first. Pass `{states: ['starting', 'up']}`
|
|
74
|
+
* and the helper polls until the dyno reports one of those
|
|
75
|
+
* states.
|
|
76
|
+
*
|
|
77
|
+
* Retry policy: 404, 429, and 503 are treated as transient and
|
|
78
|
+
* trigger another attempt. 429 responses honor `Retry-After` for
|
|
79
|
+
* the next wait. Any other error throws immediately.
|
|
80
|
+
*
|
|
81
|
+
* After {@link WaitForInfoOptions.attempts} attempts:
|
|
82
|
+
* - If state-filtered, throws {@link DynoNotReadyError} carrying
|
|
83
|
+
* the last observed dyno.
|
|
84
|
+
* - Otherwise rethrows the last transient error.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* // Race past the post-creation 404; return on first 2xx regardless of state.
|
|
89
|
+
* await platform.dyno.waitForInfo(app, name)
|
|
90
|
+
*
|
|
91
|
+
* // Wait for the dyno to be ready to accept connections.
|
|
92
|
+
* await platform.dyno.waitForInfo(app, name, {states: ['starting', 'up']})
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export declare function waitForInfo(ctx: Pick<ResourceCtx, 'platform'>, appIdentity: string, dynoIdentity: string, options?: WaitForInfoOptions): Promise<Dyno>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { HerokuApiError, NotFoundError, RateLimitError } from '@heroku/heroku-fetch';
|
|
2
|
+
import { wait } from '../../../utils/wait.js';
|
|
3
|
+
const DEFAULT_ATTEMPTS = 20;
|
|
4
|
+
const DEFAULT_DELAY_MS = 1000;
|
|
5
|
+
/**
|
|
6
|
+
* Thrown by {@link waitForInfo} when `states` was set, the dyno was
|
|
7
|
+
* reachable, but its `state` never matched within the configured
|
|
8
|
+
* number of attempts. Carries the last observed dyno so callers can
|
|
9
|
+
* branch on its state (e.g. distinguish a `crashed` dyno from one
|
|
10
|
+
* stuck in `starting`).
|
|
11
|
+
*/
|
|
12
|
+
export class DynoNotReadyError extends Error {
|
|
13
|
+
dyno;
|
|
14
|
+
expectedStates;
|
|
15
|
+
attempts;
|
|
16
|
+
id = 'dyno_not_ready';
|
|
17
|
+
constructor(dyno, expectedStates, attempts) {
|
|
18
|
+
super(`Dyno '${dyno.name}' did not reach state ${expectedStates.join('/')} `
|
|
19
|
+
+ `within ${attempts} attempts (last state: ${dyno.state}).`);
|
|
20
|
+
this.dyno = dyno;
|
|
21
|
+
this.expectedStates = expectedStates;
|
|
22
|
+
this.attempts = attempts;
|
|
23
|
+
this.name = 'DynoNotReadyError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Poll `dyno.info` until the dyno exists and (optionally) reaches a
|
|
28
|
+
* caller-specified state. Absorbs two distinct races:
|
|
29
|
+
*
|
|
30
|
+
* - **Post-creation 404.** The platform briefly returns 404 for a
|
|
31
|
+
* newly-provisioning dyno even after `dyno.create` resolves
|
|
32
|
+
* (also observable from log events emitting "Starting process"
|
|
33
|
+
* before the dyno row is queryable). Callers that just need the
|
|
34
|
+
* row to exist should omit `states` and accept the first 2xx —
|
|
35
|
+
* the dyno's `state` value does not gate the return.
|
|
36
|
+
* - **Wait for runnable.** Callers that need to act on the dyno
|
|
37
|
+
* (open an SSH connection, exec a one-off command) need it in
|
|
38
|
+
* `starting` or `up` first. Pass `{states: ['starting', 'up']}`
|
|
39
|
+
* and the helper polls until the dyno reports one of those
|
|
40
|
+
* states.
|
|
41
|
+
*
|
|
42
|
+
* Retry policy: 404, 429, and 503 are treated as transient and
|
|
43
|
+
* trigger another attempt. 429 responses honor `Retry-After` for
|
|
44
|
+
* the next wait. Any other error throws immediately.
|
|
45
|
+
*
|
|
46
|
+
* After {@link WaitForInfoOptions.attempts} attempts:
|
|
47
|
+
* - If state-filtered, throws {@link DynoNotReadyError} carrying
|
|
48
|
+
* the last observed dyno.
|
|
49
|
+
* - Otherwise rethrows the last transient error.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* // Race past the post-creation 404; return on first 2xx regardless of state.
|
|
54
|
+
* await platform.dyno.waitForInfo(app, name)
|
|
55
|
+
*
|
|
56
|
+
* // Wait for the dyno to be ready to accept connections.
|
|
57
|
+
* await platform.dyno.waitForInfo(app, name, {states: ['starting', 'up']})
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export async function waitForInfo(ctx, appIdentity, dynoIdentity, options = {}) {
|
|
61
|
+
const { attempts = DEFAULT_ATTEMPTS, delayMs = DEFAULT_DELAY_MS, onPoll, signal, states, } = options;
|
|
62
|
+
signal?.throwIfAborted();
|
|
63
|
+
// Scope the in-flight info call to the caller's signal so an abort
|
|
64
|
+
// takes effect during the API call, not just during the backoff.
|
|
65
|
+
const platform = signal ? ctx.platform.withOptions({ signal }) : ctx.platform;
|
|
66
|
+
let lastError;
|
|
67
|
+
let lastDyno;
|
|
68
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
69
|
+
let nextDelayMs = delayMs;
|
|
70
|
+
try {
|
|
71
|
+
const dyno = await platform.dyno.info(appIdentity, dynoIdentity);
|
|
72
|
+
onPoll?.(dyno);
|
|
73
|
+
if (!states || states.includes(dyno.state)) {
|
|
74
|
+
return dyno;
|
|
75
|
+
}
|
|
76
|
+
lastDyno = dyno;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (!isTransient(error))
|
|
80
|
+
throw error;
|
|
81
|
+
lastError = error;
|
|
82
|
+
if (error instanceof RateLimitError && typeof error.retryAfter === 'number') {
|
|
83
|
+
nextDelayMs = Math.max(delayMs, error.retryAfter * 1000);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (attempt < attempts - 1) {
|
|
87
|
+
await wait(nextDelayMs, signal);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (states && lastDyno) {
|
|
91
|
+
throw new DynoNotReadyError(lastDyno, states, attempts);
|
|
92
|
+
}
|
|
93
|
+
throw lastError ?? new Error(`Dyno '${dynoIdentity}' on app '${appIdentity}' was not available within ${attempts} attempts.`);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Errors the platform commonly returns transiently during a dyno's
|
|
97
|
+
* provisioning window. Anything else propagates so callers see real
|
|
98
|
+
* failures (auth, app-not-found-permanently, 5xx that aren't 503).
|
|
99
|
+
*/
|
|
100
|
+
function isTransient(error) {
|
|
101
|
+
if (error instanceof NotFoundError)
|
|
102
|
+
return true;
|
|
103
|
+
if (error instanceof RateLimitError)
|
|
104
|
+
return true;
|
|
105
|
+
if (error instanceof HerokuApiError && error.statusCode === 503)
|
|
106
|
+
return true;
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
@@ -96,7 +96,7 @@ export type StreamLogsOptions = {
|
|
|
96
96
|
* - errors thrown by `logSession.create` (auth, app-not-found, etc.)
|
|
97
97
|
*/
|
|
98
98
|
export declare function streamLogs(ctx: Pick<ResourceCtx, 'platform'>, appIdentity: string, options?: StreamLogsOptions): AsyncGenerator<string, void, unknown>;
|
|
99
|
-
export declare const logSessionExtensions: import("../../../
|
|
99
|
+
export declare const logSessionExtensions: import("../../../core/extend-resource.js").ResourceExtension<"platform", "logSession", {
|
|
100
100
|
parseHerokuLogLine: typeof parseHerokuLogLine;
|
|
101
101
|
streamLogs: (appIdentity: string, options?: StreamLogsOptions) => AsyncGenerator<string, void, unknown>;
|
|
102
102
|
}>;
|
|
@@ -22,6 +22,6 @@ export type AppWithPipelineCoupling = TeamApp & {
|
|
|
22
22
|
* result; otherwise this throws.
|
|
23
23
|
*/
|
|
24
24
|
export declare function listPipelineApps(ctx: Pick<ResourceCtx, 'platform'>, pipelineId: string, options?: ListPipelineAppsOptions): Promise<AppWithPipelineCoupling[]>;
|
|
25
|
-
export declare const pipelineCouplingExtensions: import("../../../
|
|
25
|
+
export declare const pipelineCouplingExtensions: import("../../../core/extend-resource.js").ResourceExtension<"platform", "pipelineCoupling", {
|
|
26
26
|
listApps: (pipelineId: string, options?: ListPipelineAppsOptions) => Promise<AppWithPipelineCoupling[]>;
|
|
27
27
|
}>;
|
|
@@ -48,6 +48,6 @@ export declare class PipelineAmbiguousError extends Error {
|
|
|
48
48
|
* `error.matches`.
|
|
49
49
|
*/
|
|
50
50
|
export declare function resolvePipeline(ctx: Pick<ResourceCtx, 'platform'>, identity: string, options?: ResolvePipelineOptions): Promise<Pipeline>;
|
|
51
|
-
export declare const pipelineExtensions: import("../../../
|
|
51
|
+
export declare const pipelineExtensions: import("../../../core/extend-resource.js").ResourceExtension<"platform", "pipeline", {
|
|
52
52
|
resolve: (identity: string, options?: ResolvePipelineOptions) => Promise<Pipeline>;
|
|
53
53
|
}>;
|
|
@@ -16,6 +16,6 @@ export type PromotePipelineResult = {
|
|
|
16
16
|
targets: PipelinePromotionTarget[];
|
|
17
17
|
};
|
|
18
18
|
export declare function promotePipeline(ctx: Pick<ResourceCtx, 'platform'>, body: PipelinePromotionCreateOpts, options?: PromotePipelineOptions): Promise<PromotePipelineResult>;
|
|
19
|
-
export declare const pipelinePromotionExtensions: import("../../../
|
|
19
|
+
export declare const pipelinePromotionExtensions: import("../../../core/extend-resource.js").ResourceExtension<"platform", "pipelinePromotion", {
|
|
20
20
|
promote: (body: PipelinePromotionCreateOpts, options?: PromotePipelineOptions) => Promise<PromotePipelineResult>;
|
|
21
21
|
}>;
|
package/package.json
CHANGED
|
@@ -1,17 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroku/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-beta.0",
|
|
4
4
|
"description": "Heroku SDK",
|
|
5
5
|
"author": "Heroku",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"exports": {
|
|
9
|
-
".":
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"./
|
|
14
|
-
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./platform": {
|
|
14
|
+
"types": "./dist/services/platform.d.ts",
|
|
15
|
+
"default": "./dist/services/platform.js"
|
|
16
|
+
},
|
|
17
|
+
"./data": {
|
|
18
|
+
"types": "./dist/services/data.d.ts",
|
|
19
|
+
"default": "./dist/services/data.js"
|
|
20
|
+
},
|
|
21
|
+
"./extensions/platform": {
|
|
22
|
+
"types": "./dist/resources/extensions/platform.d.ts",
|
|
23
|
+
"default": "./dist/resources/extensions/platform.js"
|
|
24
|
+
},
|
|
25
|
+
"./extensions/data": {
|
|
26
|
+
"types": "./dist/resources/extensions/data.d.ts",
|
|
27
|
+
"default": "./dist/resources/extensions/data.js"
|
|
28
|
+
},
|
|
29
|
+
"./resources/platform/add-on": {
|
|
30
|
+
"types": "./dist/resources/platform/add-on/index.d.ts",
|
|
31
|
+
"default": "./dist/resources/platform/add-on/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./resources/platform/app": {
|
|
34
|
+
"types": "./dist/resources/platform/app/index.d.ts",
|
|
35
|
+
"default": "./dist/resources/platform/app/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./resources/platform/dyno": {
|
|
38
|
+
"types": "./dist/resources/platform/dyno/index.d.ts",
|
|
39
|
+
"default": "./dist/resources/platform/dyno/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./resources/platform/log-session": {
|
|
42
|
+
"types": "./dist/resources/platform/log-session/index.d.ts",
|
|
43
|
+
"default": "./dist/resources/platform/log-session/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./resources/platform/pipeline": {
|
|
46
|
+
"types": "./dist/resources/platform/pipeline/index.d.ts",
|
|
47
|
+
"default": "./dist/resources/platform/pipeline/index.js"
|
|
48
|
+
},
|
|
49
|
+
"./resources/platform/pipeline/*": {
|
|
50
|
+
"types": "./dist/resources/platform/pipeline/*.d.ts",
|
|
51
|
+
"default": "./dist/resources/platform/pipeline/*.js"
|
|
52
|
+
},
|
|
53
|
+
"./resources/*": {
|
|
54
|
+
"types": "./dist/resources/*.d.ts",
|
|
55
|
+
"default": "./dist/resources/*.js"
|
|
56
|
+
}
|
|
15
57
|
},
|
|
16
58
|
"sideEffects": false,
|
|
17
59
|
"repository": {
|
|
@@ -24,6 +66,7 @@
|
|
|
24
66
|
"example": "tsx",
|
|
25
67
|
"lint": "eslint",
|
|
26
68
|
"lint:fix": "eslint --fix",
|
|
69
|
+
"prebuild": "rimraf dist",
|
|
27
70
|
"prepare": "npm run build",
|
|
28
71
|
"test": "vitest --run"
|
|
29
72
|
},
|
|
@@ -42,6 +85,7 @@
|
|
|
42
85
|
"eslint": "^9.39.4",
|
|
43
86
|
"eslint-config-oclif": "^6.0.167",
|
|
44
87
|
"eslint-plugin-vitest": "0.5.4",
|
|
88
|
+
"rimraf": "^6.1.3",
|
|
45
89
|
"tsx": "^4.22.4",
|
|
46
90
|
"typescript": "^6.0.2",
|
|
47
91
|
"vitest": "^4.1.4"
|