Skip to content

Commit 4f01339

Browse files
authored
feat: adding network policies oo concepts (#680)
* cp dines * cp dines * cp dines * cp dines * cp dines * cp dines * cp dines * cp dines * cp dines
1 parent a27ee7c commit 4f01339

15 files changed

Lines changed: 2137 additions & 8915 deletions

package-lock.json

Lines changed: 0 additions & 8009 deletions
This file was deleted.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@
6565
"eslint-plugin-unused-imports": "^3.0.0",
6666
"gh-pages": "^6.3.0",
6767
"iconv-lite": "^0.6.3",
68-
"jest": "^29.4.0",
68+
"jest": "^30.2.0",
6969
"prettier": "^3.0.0",
70-
"ts-jest": "^29.1.0",
71-
"ts-node": "^10.5.0",
70+
"ts-jest": "^29.4.6",
71+
"ts-node": "^10.9.2",
7272
"tsc-multi": "^1.1.0",
7373
"tsconfig-paths": "^4.0.0",
7474
"typedoc": "^0.28.14",

src/lib/polling.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export interface PollingOptions<T> {
55
initialDelayMs?: number;
66
/** Delay between subsequent polling attempts (in milliseconds) */
77
pollingIntervalMs?: number;
8-
/** Maximum number of polling attempts before throwing an error */
8+
/** Maximum number of polling attempts before throwing an error. Defaults to infinite (no limit). */
99
maxAttempts?: number;
1010
/** Optional timeout for the entire polling operation (in milliseconds) */
1111
timeoutMs?: number;
@@ -26,7 +26,6 @@ export interface PollingOptions<T> {
2626
const DEFAULT_OPTIONS: Partial<PollingOptions<any>> = {
2727
initialDelayMs: 1000,
2828
pollingIntervalMs: 1000,
29-
maxAttempts: 120,
3029
};
3130

3231
export class PollingTimeoutError extends Error {
@@ -112,7 +111,8 @@ export async function poll<T>(
112111

113112
let attempts = 0;
114113

115-
while (attempts < maxAttempts!) {
114+
// maxAttempts === undefined means infinite polling (by design, see PollingOptions.maxAttempts JSDoc)
115+
while (maxAttempts === undefined || attempts < maxAttempts) {
116116
++attempts;
117117

118118
const pollingPromise = async () => {
@@ -132,7 +132,7 @@ export async function poll<T>(
132132
return result;
133133
}
134134

135-
if (attempts === maxAttempts) {
135+
if (maxAttempts !== undefined && attempts === maxAttempts) {
136136
throw new MaxAttemptsExceededError(`Polling exceeded maximum attempts (${maxAttempts})`, result);
137137
}
138138

@@ -150,7 +150,8 @@ export async function poll<T>(
150150
}
151151
}
152152

153-
throw new MaxAttemptsExceededError(`Polling exceeded maximum attempts (${maxAttempts})`, result);
153+
// This should only be reachable if maxAttempts is defined
154+
throw new MaxAttemptsExceededError(`Polling exceeded maximum attempts (${maxAttempts})`, result!);
154155
} catch (error) {
155156
clearTimeoutIfExists();
156157
throw error;

src/sdk.ts

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Snapshot } from './sdk/snapshot';
77
import { StorageObject } from './sdk/storage-object';
88
import { Agent } from './sdk/agent';
99
import { Scorer } from './sdk/scorer';
10+
import { NetworkPolicy } from './sdk/network-policy';
1011

1112
// Import types used in this file
1213
import type {
@@ -19,6 +20,7 @@ import type { BlueprintListParams } from './resources/blueprints';
1920
import type { ObjectCreateParams, ObjectListParams } from './resources/objects';
2021
import type { AgentCreateParams, AgentListParams } from './resources/agents';
2122
import type { ScorerCreateParams, ScorerListParams } from './resources/scenarios/scorers';
23+
import type { NetworkPolicyCreateParams, NetworkPolicyListParams } from './resources/network-policies';
2224
import { PollingOptions } from './lib/polling';
2325
import * as Shared from './resources/shared';
2426

@@ -193,6 +195,7 @@ type ContentType = ObjectCreateParams['content_type'];
193195
* - `storageObject` - {@link StorageObjectOps}
194196
* - `agent` - {@link AgentOps}
195197
* - `scorer` - {@link ScorerOps}
198+
* - `networkPolicy` - {@link NetworkPolicyOps}
196199
*
197200
* See the documentation for each Operations class for more details.
198201
*
@@ -271,6 +274,14 @@ export class RunloopSDK {
271274
*/
272275
public readonly scorer: ScorerOps;
273276

277+
/**
278+
* **Network Policy Operations** - {@link NetworkPolicyOps} for creating and accessing {@link NetworkPolicy} class instances.
279+
*
280+
* Network policies define egress network access rules for devboxes. Policies can be applied to
281+
* blueprints, devboxes, and snapshot resumes to control network access.
282+
*/
283+
public readonly networkPolicy: NetworkPolicyOps;
284+
274285
/**
275286
* Creates a new RunloopSDK instance.
276287
* @param {ClientOptions} [options] - Optional client configuration options.
@@ -283,6 +294,7 @@ export class RunloopSDK {
283294
this.storageObject = new StorageObjectOps(this.api);
284295
this.agent = new AgentOps(this.api);
285296
this.scorer = new ScorerOps(this.api);
297+
this.networkPolicy = new NetworkPolicyOps(this.api);
286298
}
287299
}
288300

@@ -1382,6 +1394,109 @@ export class ScorerOps {
13821394
}
13831395
}
13841396

1397+
/**
1398+
* Network Policy SDK interface for managing network policies.
1399+
*
1400+
* @category Network Policy
1401+
*
1402+
* @remarks
1403+
* ## Overview
1404+
*
1405+
* The `NetworkPolicyOps` class provides a high-level abstraction for managing network policies,
1406+
* which define egress network access rules for devboxes. Policies can be applied to blueprints,
1407+
* devboxes, and snapshot resumes to control network access.
1408+
*
1409+
* ## Usage
1410+
*
1411+
* This interface is accessed via {@link RunloopSDK.networkPolicy}. You should construct
1412+
* a {@link RunloopSDK} instance and use it from there:
1413+
*
1414+
* @example
1415+
* ```typescript
1416+
* const runloop = new RunloopSDK();
1417+
* const policy = await runloop.networkPolicy.create({
1418+
* name: 'restricted-policy',
1419+
* allow_all: false,
1420+
* allowed_hostnames: ['github.com', 'api.openai.com'],
1421+
* });
1422+
*
1423+
* const info = await policy.getInfo();
1424+
* console.log(`Policy: ${info.name}`);
1425+
* ```
1426+
*/
1427+
export class NetworkPolicyOps {
1428+
/**
1429+
* @private
1430+
*/
1431+
constructor(private client: RunloopAPI) {}
1432+
1433+
/**
1434+
* Create a new network policy.
1435+
*
1436+
* @example
1437+
* ```typescript
1438+
* const runloop = new RunloopSDK();
1439+
* const policy = await runloop.networkPolicy.create({
1440+
* name: 'my-policy',
1441+
* allow_all: false,
1442+
* allowed_hostnames: ['github.com', '*.npmjs.org'],
1443+
* allow_devbox_to_devbox: true,
1444+
* description: 'Policy for restricted network access',
1445+
* });
1446+
* ```
1447+
*
1448+
* @param {NetworkPolicyCreateParams} params - Parameters for creating the network policy.
1449+
* @param {Core.RequestOptions} [options] - Request options.
1450+
* @returns {Promise<NetworkPolicy>} A {@link NetworkPolicy} instance.
1451+
*/
1452+
async create(params: NetworkPolicyCreateParams, options?: Core.RequestOptions): Promise<NetworkPolicy> {
1453+
return NetworkPolicy.create(this.client, params, options);
1454+
}
1455+
1456+
/**
1457+
* Get a network policy object by its ID.
1458+
*
1459+
* @example
1460+
* ```typescript
1461+
* const runloop = new RunloopSDK();
1462+
* const policy = runloop.networkPolicy.fromId('npol_1234567890');
1463+
* const info = await policy.getInfo();
1464+
* console.log(`Policy name: ${info.name}`);
1465+
* ```
1466+
*
1467+
* @param {string} id - The ID of the network policy.
1468+
* @returns {NetworkPolicy} A {@link NetworkPolicy} instance.
1469+
*/
1470+
fromId(id: string): NetworkPolicy {
1471+
return NetworkPolicy.fromId(this.client, id);
1472+
}
1473+
1474+
/**
1475+
* List all network policies with optional filters.
1476+
*
1477+
* @example
1478+
* ```typescript
1479+
* const runloop = new RunloopSDK();
1480+
* const policies = await runloop.networkPolicy.list({ limit: 10 });
1481+
* console.log(policies.map((p) => p.id));
1482+
* ```
1483+
*
1484+
* @param {NetworkPolicyListParams} [params] - Optional filter parameters.
1485+
* @param {Core.RequestOptions} [options] - Request options.
1486+
* @returns {Promise<NetworkPolicy[]>} An array of {@link NetworkPolicy} instances.
1487+
*/
1488+
async list(params?: NetworkPolicyListParams, options?: Core.RequestOptions): Promise<NetworkPolicy[]> {
1489+
const result = await this.client.networkPolicies.list(params, options);
1490+
const policies: NetworkPolicy[] = [];
1491+
1492+
for await (const policy of result) {
1493+
policies.push(NetworkPolicy.fromId(this.client, policy.id));
1494+
}
1495+
1496+
return policies;
1497+
}
1498+
}
1499+
13851500
// @deprecated Use {@link RunloopSDK} instead.
13861501
/**
13871502
* @deprecated Use {@link RunloopSDK} instead.
@@ -1403,12 +1518,14 @@ export declare namespace RunloopSDK {
14031518
StorageObjectOps as StorageObjectOps,
14041519
AgentOps as AgentOps,
14051520
ScorerOps as ScorerOps,
1521+
NetworkPolicyOps as NetworkPolicyOps,
14061522
Devbox as Devbox,
14071523
Blueprint as Blueprint,
14081524
Snapshot as Snapshot,
14091525
StorageObject as StorageObject,
14101526
Agent as Agent,
14111527
Scorer as Scorer,
1528+
NetworkPolicy as NetworkPolicy,
14121529
};
14131530
}
14141531
// Export SDK classes from sdk/sdk.ts - these are separate from RunloopSDK to avoid circular dependencies
@@ -1423,6 +1540,7 @@ export {
14231540
StorageObject,
14241541
Agent,
14251542
Scorer,
1543+
NetworkPolicy,
14261544
Execution,
14271545
ExecutionResult,
14281546
} from './sdk/index';

src/sdk/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export { Agent } from './agent';
66
export { Execution } from './execution';
77
export { ExecutionResult } from './execution-result';
88
export { Scorer } from './scorer';
9+
export { NetworkPolicy } from './network-policy';

0 commit comments

Comments
 (0)