@heroku/sdk 0.5.2 → 0.5.3

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.
Files changed (53) hide show
  1. package/dist/core/create-client.d.ts +9 -1
  2. package/dist/core/create-client.js +4 -2
  3. package/dist/resources/data/redis/errors.d.ts +8 -0
  4. package/dist/resources/data/redis/errors.js +15 -0
  5. package/dist/resources/data/redis/index.d.ts +9 -0
  6. package/dist/resources/data/redis/index.js +10 -0
  7. package/dist/resources/data/redis/resolve-by-app.d.ts +35 -0
  8. package/dist/resources/data/redis/resolve-by-app.js +56 -0
  9. package/dist/resources/data/redis/wait-for-ready.d.ts +32 -0
  10. package/dist/resources/data/redis/wait-for-ready.js +46 -0
  11. package/dist/resources/extensions/data.d.ts +1 -0
  12. package/dist/resources/extensions/data.js +1 -0
  13. package/dist/resources/extensions/platform.d.ts +5 -1
  14. package/dist/resources/extensions/platform.js +5 -1
  15. package/dist/resources/platform/add-on/destroy-and-wait.d.ts +22 -0
  16. package/dist/resources/platform/add-on/destroy-and-wait.js +62 -0
  17. package/dist/resources/platform/add-on/index.d.ts +9 -5
  18. package/dist/resources/platform/add-on/index.js +6 -0
  19. package/dist/resources/platform/add-on/types.d.ts +35 -0
  20. package/dist/resources/platform/add-on/wait-for-provisioning.d.ts +19 -0
  21. package/dist/resources/platform/add-on/wait-for-provisioning.js +37 -0
  22. package/dist/resources/platform/app/index.d.ts +3 -0
  23. package/dist/resources/platform/app/index.js +3 -0
  24. package/dist/resources/platform/app/wait-for-acm-certificates.d.ts +34 -0
  25. package/dist/resources/platform/app/wait-for-acm-certificates.js +51 -0
  26. package/dist/resources/platform/container/ensure-container-stack.d.ts +18 -0
  27. package/dist/resources/platform/container/ensure-container-stack.js +32 -0
  28. package/dist/resources/platform/container/index.d.ts +13 -0
  29. package/dist/resources/platform/container/index.js +12 -0
  30. package/dist/resources/platform/container/release-images.d.ts +21 -0
  31. package/dist/resources/platform/container/release-images.js +23 -0
  32. package/dist/resources/platform/container/remove-process-types.d.ts +22 -0
  33. package/dist/resources/platform/container/remove-process-types.js +20 -0
  34. package/dist/resources/platform/dyno/index.d.ts +3 -0
  35. package/dist/resources/platform/dyno/index.js +3 -0
  36. package/dist/resources/platform/dyno/run.d.ts +76 -0
  37. package/dist/resources/platform/dyno/run.js +74 -0
  38. package/dist/resources/platform/log-session/index.js +71 -12
  39. package/dist/resources/platform/sni-endpoint/create-and-associate.d.ts +38 -0
  40. package/dist/resources/platform/sni-endpoint/create-and-associate.js +86 -0
  41. package/dist/resources/platform/sni-endpoint/index.d.ts +5 -0
  42. package/dist/resources/platform/sni-endpoint/index.js +6 -0
  43. package/dist/resources/platform/telemetry-drain/index.d.ts +6 -0
  44. package/dist/resources/platform/telemetry-drain/index.js +6 -0
  45. package/dist/resources/platform/telemetry-drain/remove-drains-for-target.d.ts +13 -0
  46. package/dist/resources/platform/telemetry-drain/remove-drains-for-target.js +25 -0
  47. package/dist/resources/platform/telemetry-drain/types.d.ts +13 -0
  48. package/dist/resources/platform/telemetry-drain/types.js +1 -0
  49. package/dist/resources/platform/test-run/index.d.ts +5 -0
  50. package/dist/resources/platform/test-run/index.js +9 -0
  51. package/dist/resources/platform/test-run/wait-for-state.d.ts +68 -0
  52. package/dist/resources/platform/test-run/wait-for-state.js +65 -0
  53. package/package.json +10 -2
@@ -0,0 +1,6 @@
1
+ import { extendResource } from '../../../core/extend-resource.js';
2
+ import { createAndAssociate } from './create-and-associate.js';
3
+ export { createAndAssociate } from './create-and-associate.js';
4
+ export const sniEndpointExtensions = extendResource('platform', 'sniEndpoint', ctx => ({
5
+ createAndAssociate: (appIdentity, certificateChain, privateKey, options) => createAndAssociate(ctx, appIdentity, certificateChain, privateKey, options),
6
+ }));
@@ -0,0 +1,6 @@
1
+ import type { TelemetryDrainOptions, TelemetryDrainTarget } from './types.js';
2
+ export { removeDrainsForTarget } from './remove-drains-for-target.js';
3
+ export type { TelemetryDrainOptions, TelemetryDrainTarget } from './types.js';
4
+ export declare const telemetryDrainExtensions: import("../../../core/extend-resource.js").ResourceExtension<"platform", "telemetryDrain", {
5
+ removeDrains: (target: TelemetryDrainTarget, options?: TelemetryDrainOptions) => Promise<import("@heroku/types/3.sdk").TelemetryDrain[]>;
6
+ }>;
@@ -0,0 +1,6 @@
1
+ import { extendResource } from '../../../core/extend-resource.js';
2
+ import { removeDrainsForTarget } from './remove-drains-for-target.js';
3
+ export { removeDrainsForTarget } from './remove-drains-for-target.js';
4
+ export const telemetryDrainExtensions = extendResource('platform', 'telemetryDrain', ctx => ({
5
+ removeDrains: (target, options) => removeDrainsForTarget(ctx, target, options),
6
+ }));
@@ -0,0 +1,13 @@
1
+ import type { TelemetryDrain } from '@heroku/types/3.sdk';
2
+ import type { ResourceCtx } from '../../../core/extend-resource.js';
3
+ import type { TelemetryDrainOptions, TelemetryDrainTarget } from './types.js';
4
+ /**
5
+ * Remove all telemetry drains for a given app or space.
6
+ *
7
+ * Behavior:
8
+ * - Dispatches to listByApp or listBySpace based on target discriminant
9
+ * - Deletes all drains in parallel via Promise.all
10
+ * - Returns empty array if no drains exist
11
+ * - Rejects if any individual delete fails
12
+ */
13
+ export declare function removeDrainsForTarget(ctx: Pick<ResourceCtx, 'platform'>, target: TelemetryDrainTarget, options?: TelemetryDrainOptions): Promise<TelemetryDrain[]>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Remove all telemetry drains for a given app or space.
3
+ *
4
+ * Behavior:
5
+ * - Dispatches to listByApp or listBySpace based on target discriminant
6
+ * - Deletes all drains in parallel via Promise.all
7
+ * - Returns empty array if no drains exist
8
+ * - Rejects if any individual delete fails
9
+ */
10
+ export async function removeDrainsForTarget(ctx, target, options = {}) {
11
+ const { signal } = options;
12
+ const { app, space } = target;
13
+ signal?.throwIfAborted();
14
+ const platform = signal ? ctx.platform.withOptions({ signal }) : ctx.platform;
15
+ let drains = [];
16
+ if (app) {
17
+ drains = await platform.telemetryDrain.listByApp(app);
18
+ }
19
+ else if (space) {
20
+ drains = await platform.telemetryDrain.listBySpace(space);
21
+ }
22
+ signal?.throwIfAborted();
23
+ const deletedDrains = await Promise.all(drains.map(drain => platform.telemetryDrain.delete(drain.id)));
24
+ return deletedDrains;
25
+ }
@@ -0,0 +1,13 @@
1
+ export type TelemetryDrainOptions = {
2
+ /**
3
+ * Abort signal to cancel the operation.
4
+ */
5
+ signal?: AbortSignal;
6
+ };
7
+ export type TelemetryDrainTarget = {
8
+ app: string;
9
+ space?: never;
10
+ } | {
11
+ app?: never;
12
+ space: string;
13
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import { type TestRunStatus, type WaitForStateOptions } from './wait-for-state.js';
2
+ export { TestRunNotReadyError, type TestRunStatus, waitForState, type WaitForStateOptions, } from './wait-for-state.js';
3
+ export declare const testRunExtensions: import("../../../core/extend-resource.js").ResourceExtension<"platform", "testRun", {
4
+ waitForState: (pipelineId: string, testRunNumber: number, targetStates: ReadonlyArray<string | TestRunStatus>, options?: WaitForStateOptions) => Promise<import("@heroku/types/3.sdk").TestRun>;
5
+ }>;
@@ -0,0 +1,9 @@
1
+ import { extendResource } from '../../../core/extend-resource.js';
2
+ import { waitForState } from './wait-for-state.js';
3
+ export { TestRunNotReadyError, waitForState, } from './wait-for-state.js';
4
+ // Resource key MUST be the camelCase `'testRun'` — it matches the generated
5
+ // route-group export name that `mergeExtensions` looks up on the platform
6
+ // client. The directory stays kebab (`test-run/`).
7
+ export const testRunExtensions = extendResource('platform', 'testRun', ctx => ({
8
+ waitForState: (pipelineId, testRunNumber, targetStates, options) => waitForState(ctx, pipelineId, testRunNumber, targetStates, options),
9
+ }));
@@ -0,0 +1,68 @@
1
+ import type { TestRun } from '@heroku/types/3.sdk';
2
+ import type { ResourceCtx } from '../../../core/extend-resource.js';
3
+ /**
4
+ * The documented `TestRun.status` values from the Platform API. Provided
5
+ * for autocomplete in {@link waitForState}'s `targetStates`; the runtime
6
+ * comparison is plain string membership (`targetStates.includes(run.status)`),
7
+ * so any string is accepted.
8
+ */
9
+ export type TestRunStatus = TestRun['status'];
10
+ /**
11
+ * Thrown by {@link waitForState} when the test run did not reach one of
12
+ * `targetStates` within `timeoutMs`. Carries the last observed run so
13
+ * callers can branch on its terminal `status` (e.g. distinguish a
14
+ * `failed` run from one still `building`). Mirrors `DynoNotReadyError`.
15
+ */
16
+ export declare class TestRunNotReadyError extends Error {
17
+ readonly testRun: TestRun;
18
+ readonly expectedStates: ReadonlyArray<string>;
19
+ readonly timeoutMs: number;
20
+ readonly id = "test_run_not_ready";
21
+ constructor(testRun: TestRun, expectedStates: ReadonlyArray<string>, timeoutMs: number);
22
+ }
23
+ export type WaitForStateOptions = {
24
+ /**
25
+ * Delay between polls in milliseconds. Defaults to 1000.
26
+ */
27
+ intervalMs?: number;
28
+ /**
29
+ * Fires after every successful `testRun.infoByPipeline` call, including
30
+ * runs whose `status` does not yet match `targetStates` (and trigger
31
+ * another poll) AND the final matching run before it is returned. Use
32
+ * this to surface live state transitions in a UI. Exceptions thrown from
33
+ * this callback propagate and end the wait — there is no implicit catch.
34
+ */
35
+ onPoll?: (run: TestRun) => void;
36
+ /**
37
+ * Cancels the wait early. If already aborted, {@link waitForState}
38
+ * rejects before the first poll; if aborted mid-wait, the pending delay
39
+ * rejects with `signal.reason`.
40
+ */
41
+ signal?: AbortSignal;
42
+ /**
43
+ * Wall-clock budget in milliseconds before {@link TestRunNotReadyError}
44
+ * is thrown. Defaults to 600000 (10 minutes) — a finite default so a
45
+ * stuck run can't hang forever. Pass a larger value for long CI runs.
46
+ */
47
+ timeoutMs?: number;
48
+ };
49
+ /**
50
+ * Poll `testRun.infoByPipeline` until the run's `status` is one of
51
+ * `targetStates`, then return that run. Reuses the SDK's cancellable
52
+ * `wait()` helper to space polls — no bare `setTimeout` loop.
53
+ *
54
+ * Transient-error handling: errors from `infoByPipeline` **propagate**;
55
+ * there is no 404/429/503 retry. This matches the closest precedent,
56
+ * `promotePipeline`, and the original CLI `waitForStates`, which had no
57
+ * retry either — adopting `waitForInfo`'s transient retry would be behavior
58
+ * the eventual CLI caller never had.
59
+ *
60
+ * On exceeding `timeoutMs` without a match, throws {@link TestRunNotReadyError}
61
+ * carrying the last observed run.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const run = await platform.testRun.waitForState(pipelineId, 42, ['debugging', 'errored'])
66
+ * ```
67
+ */
68
+ export declare function waitForState(ctx: Pick<ResourceCtx, 'platform'>, pipelineId: string, testRunNumber: number, targetStates: ReadonlyArray<string | TestRunStatus>, options?: WaitForStateOptions): Promise<TestRun>;
@@ -0,0 +1,65 @@
1
+ import { wait } from '../../../utils/wait.js';
2
+ const DEFAULT_INTERVAL_MS = 1000;
3
+ // Finite default so a stuck CI test run can't hang a caller forever.
4
+ // Diverges deliberately from `promotePipeline`, which leaves `timeoutMs`
5
+ // unbounded; callers that need longer can pass an explicit `timeoutMs`.
6
+ const DEFAULT_TIMEOUT_MS = 600_000;
7
+ /**
8
+ * Thrown by {@link waitForState} when the test run did not reach one of
9
+ * `targetStates` within `timeoutMs`. Carries the last observed run so
10
+ * callers can branch on its terminal `status` (e.g. distinguish a
11
+ * `failed` run from one still `building`). Mirrors `DynoNotReadyError`.
12
+ */
13
+ export class TestRunNotReadyError extends Error {
14
+ testRun;
15
+ expectedStates;
16
+ timeoutMs;
17
+ id = 'test_run_not_ready';
18
+ constructor(testRun, expectedStates, timeoutMs) {
19
+ super(`Test run #${testRun.number} did not reach status ${expectedStates.join('/')} `
20
+ + `within ${timeoutMs}ms (last status: ${testRun.status}).`);
21
+ this.testRun = testRun;
22
+ this.expectedStates = expectedStates;
23
+ this.timeoutMs = timeoutMs;
24
+ this.name = 'TestRunNotReadyError';
25
+ }
26
+ }
27
+ /**
28
+ * Poll `testRun.infoByPipeline` until the run's `status` is one of
29
+ * `targetStates`, then return that run. Reuses the SDK's cancellable
30
+ * `wait()` helper to space polls — no bare `setTimeout` loop.
31
+ *
32
+ * Transient-error handling: errors from `infoByPipeline` **propagate**;
33
+ * there is no 404/429/503 retry. This matches the closest precedent,
34
+ * `promotePipeline`, and the original CLI `waitForStates`, which had no
35
+ * retry either — adopting `waitForInfo`'s transient retry would be behavior
36
+ * the eventual CLI caller never had.
37
+ *
38
+ * On exceeding `timeoutMs` without a match, throws {@link TestRunNotReadyError}
39
+ * carrying the last observed run.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const run = await platform.testRun.waitForState(pipelineId, 42, ['debugging', 'errored'])
44
+ * ```
45
+ */
46
+ export async function waitForState(ctx, pipelineId, testRunNumber, targetStates, options = {}) {
47
+ const { intervalMs = DEFAULT_INTERVAL_MS, onPoll, signal, timeoutMs = DEFAULT_TIMEOUT_MS, } = options;
48
+ signal?.throwIfAborted();
49
+ // Scope the in-flight info call to the caller's signal so an abort takes
50
+ // effect during the API call, not just during the backoff.
51
+ const platform = signal ? ctx.platform.withOptions({ signal }) : ctx.platform;
52
+ const deadline = Date.now() + timeoutMs;
53
+ while (true) {
54
+ signal?.throwIfAborted();
55
+ const run = await platform.testRun.infoByPipeline(pipelineId, testRunNumber);
56
+ onPoll?.(run);
57
+ if (targetStates.includes(run.status)) {
58
+ return run;
59
+ }
60
+ if (Date.now() >= deadline) {
61
+ throw new TestRunNotReadyError(run, targetStates, timeoutMs);
62
+ }
63
+ await wait(intervalMs, signal);
64
+ }
65
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heroku/sdk",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Heroku SDK",
5
5
  "author": "Heroku",
6
6
  "type": "module",
@@ -50,6 +50,14 @@
50
50
  "types": "./dist/resources/platform/pipeline/*.d.ts",
51
51
  "default": "./dist/resources/platform/pipeline/*.js"
52
52
  },
53
+ "./resources/platform/test-run": {
54
+ "types": "./dist/resources/platform/test-run/index.d.ts",
55
+ "default": "./dist/resources/platform/test-run/index.js"
56
+ },
57
+ "./resources/data/redis": {
58
+ "types": "./dist/resources/data/redis/index.d.ts",
59
+ "default": "./dist/resources/data/redis/index.js"
60
+ },
53
61
  "./resources/*": {
54
62
  "types": "./dist/resources/*.d.ts",
55
63
  "default": "./dist/resources/*.js"
@@ -92,7 +100,7 @@
92
100
  },
93
101
  "dependencies": {
94
102
  "@heroku/heroku-fetch": "^0.1.1-beta",
95
- "@heroku/types": "^3.0.0-beta",
103
+ "@heroku/types": "^4.0.1",
96
104
  "debug": "^4.4.0"
97
105
  }
98
106
  }