@computesdk/namespace 1.0.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 +21 -0
- package/README.md +134 -0
- package/dist/index.d.mts +38 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +216 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +189 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 computesdk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# @computesdk/namespace
|
|
2
|
+
|
|
3
|
+
Namespace provider for ComputeSDK that enables creating and managing containerized compute instances on Namespace's cloud infrastructure.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @computesdk/namespace
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
The Namespace provider requires the following environment variable:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
NSC_TOKEN=your_namespace_token
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { namespace } from '@computesdk/namespace';
|
|
23
|
+
|
|
24
|
+
const provider = namespace({
|
|
25
|
+
token: 'your_nsc_token',
|
|
26
|
+
virtualCpu: 2,
|
|
27
|
+
memoryMegabytes: 4096,
|
|
28
|
+
documentedPurpose: 'Development sandbox'
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Create a sandbox
|
|
32
|
+
const sandbox = await provider.sandbox.create({ runtime: 'node' });
|
|
33
|
+
console.log(`Created sandbox: ${sandbox.sandboxId}`);
|
|
34
|
+
|
|
35
|
+
// Get sandbox details
|
|
36
|
+
const details = await provider.sandbox.getById(sandbox.sandboxId);
|
|
37
|
+
console.log(`Sandbox status:`, details);
|
|
38
|
+
|
|
39
|
+
// List all sandboxes
|
|
40
|
+
const sandboxes = await provider.sandbox.list();
|
|
41
|
+
console.log(`Found ${sandboxes.length} sandboxes`);
|
|
42
|
+
|
|
43
|
+
// Destroy the sandbox
|
|
44
|
+
await provider.sandbox.destroy(sandbox.sandboxId);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## API Methods
|
|
48
|
+
|
|
49
|
+
### Sandbox Operations
|
|
50
|
+
|
|
51
|
+
#### `create(options?: CreateSandboxOptions)`
|
|
52
|
+
Creates a new Namespace compute instance with the specified configuration.
|
|
53
|
+
|
|
54
|
+
**Parameters:**
|
|
55
|
+
- `options.runtime` - Runtime environment ('node' | 'python')
|
|
56
|
+
|
|
57
|
+
**Returns:** `{ sandbox: NamespaceSandbox, sandboxId: string }`
|
|
58
|
+
|
|
59
|
+
#### `getById(sandboxId: string)`
|
|
60
|
+
Retrieves details for a specific sandbox instance.
|
|
61
|
+
|
|
62
|
+
**Parameters:**
|
|
63
|
+
- `sandboxId` - The instance ID to retrieve
|
|
64
|
+
|
|
65
|
+
**Returns:** `{ sandbox: NamespaceSandbox, sandboxId: string } | null`
|
|
66
|
+
|
|
67
|
+
#### `list()`
|
|
68
|
+
Lists all compute instances in your Namespace account.
|
|
69
|
+
|
|
70
|
+
**Returns:** `Array<{ sandbox: NamespaceSandbox, sandboxId: string }>`
|
|
71
|
+
|
|
72
|
+
#### `destroy(sandboxId: string)`
|
|
73
|
+
Destroys a compute instance and cleans up resources.
|
|
74
|
+
|
|
75
|
+
**Parameters:**
|
|
76
|
+
- `sandboxId` - The instance ID to destroy
|
|
77
|
+
|
|
78
|
+
## Configuration Options
|
|
79
|
+
|
|
80
|
+
### NamespaceConfig
|
|
81
|
+
|
|
82
|
+
| Option | Type | Default | Description |
|
|
83
|
+
|--------|------|---------|-------------|
|
|
84
|
+
| `token` | `string` | `process.env.NSC_TOKEN` | Namespace API authentication token |
|
|
85
|
+
| `virtualCpu` | `number` | `2` | Number of virtual CPU cores |
|
|
86
|
+
| `memoryMegabytes` | `number` | `4096` | Memory allocation in MB |
|
|
87
|
+
| `machineArch` | `string` | `'amd64'` | Machine architecture |
|
|
88
|
+
| `os` | `string` | `'linux'` | Operating system |
|
|
89
|
+
| `documentedPurpose` | `string` | `'ComputeSDK sandbox'` | Purpose documentation for the instance |
|
|
90
|
+
| `destroyReason` | `string` | `'ComputeSDK cleanup'` | Reason for instance destruction |
|
|
91
|
+
|
|
92
|
+
## Supported Runtimes
|
|
93
|
+
|
|
94
|
+
- **node** - Uses `node:alpine` Docker image
|
|
95
|
+
- **python** - Uses `python:alpine` Docker image
|
|
96
|
+
|
|
97
|
+
## Instance Lifecycle
|
|
98
|
+
|
|
99
|
+
1. **Creation** - Instances are created with specified resource allocation
|
|
100
|
+
2. **Container Setup** - Docker containers are automatically provisioned
|
|
101
|
+
3. **Startup** - Containers start with a sleep command for 300 seconds
|
|
102
|
+
4. **Management** - Full CRUD operations available via API
|
|
103
|
+
5. **Cleanup** - Graceful shutdown and resource deallocation
|
|
104
|
+
|
|
105
|
+
## API Endpoints
|
|
106
|
+
|
|
107
|
+
The provider uses Namespace's compute API:
|
|
108
|
+
|
|
109
|
+
- **Base URL:** `https://us.compute.namespaceapis.com`
|
|
110
|
+
- **Service:** `namespace.cloud.compute.v1beta.ComputeService`
|
|
111
|
+
- **Authentication:** Bearer token
|
|
112
|
+
|
|
113
|
+
## Error Handling
|
|
114
|
+
|
|
115
|
+
The provider includes comprehensive error handling:
|
|
116
|
+
|
|
117
|
+
- **Authentication errors** - Invalid or missing NSC_TOKEN
|
|
118
|
+
- **Resource limits** - Quota exceeded or invalid configurations
|
|
119
|
+
- **Network errors** - API connectivity issues
|
|
120
|
+
- **Instance errors** - Non-existent or inaccessible instances
|
|
121
|
+
|
|
122
|
+
## Environment Variables
|
|
123
|
+
|
|
124
|
+
| Variable | Required | Description |
|
|
125
|
+
|----------|----------|-------------|
|
|
126
|
+
| `NSC_TOKEN` | Yes | Namespace authentication token |
|
|
127
|
+
|
|
128
|
+
## Notes
|
|
129
|
+
|
|
130
|
+
- All operations use Namespace's REST API over HTTPS
|
|
131
|
+
- Instance IDs are globally unique within your account
|
|
132
|
+
- Resource quotas apply based on your Namespace plan
|
|
133
|
+
- Containers start with basic sleep command and can be customized
|
|
134
|
+
- Graceful error handling for destroy operations (won't fail if instance already deleted)
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as computesdk from 'computesdk';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Namespace Provider - Factory-based Implementation
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Namespace sandbox interface
|
|
8
|
+
*/
|
|
9
|
+
interface NamespaceSandbox {
|
|
10
|
+
instanceId: string;
|
|
11
|
+
name: string;
|
|
12
|
+
}
|
|
13
|
+
interface NamespaceConfig {
|
|
14
|
+
/** Namespace API token - if not provided, will fallback to NSC_TOKEN environment variable */
|
|
15
|
+
token?: string;
|
|
16
|
+
/** Virtual CPU cores for the instance */
|
|
17
|
+
virtualCpu?: number;
|
|
18
|
+
/** Memory in megabytes for the instance */
|
|
19
|
+
memoryMegabytes?: number;
|
|
20
|
+
/** Machine architecture (default: amd64) */
|
|
21
|
+
machineArch?: string;
|
|
22
|
+
/** Operating system (default: linux) */
|
|
23
|
+
os?: string;
|
|
24
|
+
/** Documented purpose for the instance */
|
|
25
|
+
documentedPurpose?: string;
|
|
26
|
+
/** Reason for destroying instances (default: "ComputeSDK cleanup") */
|
|
27
|
+
destroyReason?: string;
|
|
28
|
+
}
|
|
29
|
+
declare const getAndValidateCredentials: (config: NamespaceConfig) => {
|
|
30
|
+
token: string;
|
|
31
|
+
};
|
|
32
|
+
declare const fetchNamespace: (token: string, endpoint: string, options?: RequestInit) => Promise<any>;
|
|
33
|
+
/**
|
|
34
|
+
* Create a Namespace provider instance using the factory pattern
|
|
35
|
+
*/
|
|
36
|
+
declare const namespace: (config: NamespaceConfig) => computesdk.Provider<NamespaceSandbox, any, any>;
|
|
37
|
+
|
|
38
|
+
export { type NamespaceConfig, fetchNamespace, getAndValidateCredentials, namespace };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as computesdk from 'computesdk';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Namespace Provider - Factory-based Implementation
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Namespace sandbox interface
|
|
8
|
+
*/
|
|
9
|
+
interface NamespaceSandbox {
|
|
10
|
+
instanceId: string;
|
|
11
|
+
name: string;
|
|
12
|
+
}
|
|
13
|
+
interface NamespaceConfig {
|
|
14
|
+
/** Namespace API token - if not provided, will fallback to NSC_TOKEN environment variable */
|
|
15
|
+
token?: string;
|
|
16
|
+
/** Virtual CPU cores for the instance */
|
|
17
|
+
virtualCpu?: number;
|
|
18
|
+
/** Memory in megabytes for the instance */
|
|
19
|
+
memoryMegabytes?: number;
|
|
20
|
+
/** Machine architecture (default: amd64) */
|
|
21
|
+
machineArch?: string;
|
|
22
|
+
/** Operating system (default: linux) */
|
|
23
|
+
os?: string;
|
|
24
|
+
/** Documented purpose for the instance */
|
|
25
|
+
documentedPurpose?: string;
|
|
26
|
+
/** Reason for destroying instances (default: "ComputeSDK cleanup") */
|
|
27
|
+
destroyReason?: string;
|
|
28
|
+
}
|
|
29
|
+
declare const getAndValidateCredentials: (config: NamespaceConfig) => {
|
|
30
|
+
token: string;
|
|
31
|
+
};
|
|
32
|
+
declare const fetchNamespace: (token: string, endpoint: string, options?: RequestInit) => Promise<any>;
|
|
33
|
+
/**
|
|
34
|
+
* Create a Namespace provider instance using the factory pattern
|
|
35
|
+
*/
|
|
36
|
+
declare const namespace: (config: NamespaceConfig) => computesdk.Provider<NamespaceSandbox, any, any>;
|
|
37
|
+
|
|
38
|
+
export { type NamespaceConfig, fetchNamespace, getAndValidateCredentials, namespace };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
fetchNamespace: () => fetchNamespace,
|
|
24
|
+
getAndValidateCredentials: () => getAndValidateCredentials,
|
|
25
|
+
namespace: () => namespace
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
var import_computesdk = require("computesdk");
|
|
29
|
+
var getAndValidateCredentials = (config) => {
|
|
30
|
+
const token = config.token || typeof process !== "undefined" && process.env?.NSC_TOKEN || "";
|
|
31
|
+
if (!token) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
"Missing Namespace token. Provide token in config or set NSC_TOKEN environment variable."
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return { token };
|
|
37
|
+
};
|
|
38
|
+
var API_ENDPOINTS = {
|
|
39
|
+
CREATE_INSTANCE: "/namespace.cloud.compute.v1beta.ComputeService/CreateInstance",
|
|
40
|
+
DESCRIBE_INSTANCE: "/namespace.cloud.compute.v1beta.ComputeService/DescribeInstance",
|
|
41
|
+
LIST_INSTANCES: "/namespace.cloud.compute.v1beta.ComputeService/ListInstances",
|
|
42
|
+
DESTROY_INSTANCE: "/namespace.cloud.compute.v1beta.ComputeService/DestroyInstance"
|
|
43
|
+
};
|
|
44
|
+
var handleApiErrors = (response) => {
|
|
45
|
+
if (response.error) {
|
|
46
|
+
throw new Error(`Namespace API error: ${response.error}`);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var fetchNamespace = async (token, endpoint, options = {}) => {
|
|
50
|
+
const response = await fetch(`https://us.compute.namespaceapis.com${endpoint}`, {
|
|
51
|
+
...options,
|
|
52
|
+
headers: {
|
|
53
|
+
"Content-Type": "application/json",
|
|
54
|
+
"Authorization": `Bearer ${token}`,
|
|
55
|
+
...options.headers
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
throw new Error(`Namespace API error: ${response.status} ${response.statusText}`);
|
|
60
|
+
}
|
|
61
|
+
const data = await response.json();
|
|
62
|
+
handleApiErrors(data);
|
|
63
|
+
return data;
|
|
64
|
+
};
|
|
65
|
+
var namespace = (0, import_computesdk.createProvider)({
|
|
66
|
+
name: "namespace",
|
|
67
|
+
methods: {
|
|
68
|
+
sandbox: {
|
|
69
|
+
// Collection operations (compute.sandbox.*)
|
|
70
|
+
create: async (config, options) => {
|
|
71
|
+
const { token } = getAndValidateCredentials(config);
|
|
72
|
+
try {
|
|
73
|
+
const getImageRef = (runtime) => {
|
|
74
|
+
return runtime === "node" ? "node:alpine" : "python:alpine";
|
|
75
|
+
};
|
|
76
|
+
const requestBody = {
|
|
77
|
+
shape: {
|
|
78
|
+
virtual_cpu: config.virtualCpu || 2,
|
|
79
|
+
memory_megabytes: config.memoryMegabytes || 4096,
|
|
80
|
+
machine_arch: config.machineArch || "amd64",
|
|
81
|
+
os: config.os || "linux"
|
|
82
|
+
},
|
|
83
|
+
containers: [{
|
|
84
|
+
name: "main-container",
|
|
85
|
+
image_ref: getImageRef(options?.runtime),
|
|
86
|
+
args: ["sleep", "300"]
|
|
87
|
+
}],
|
|
88
|
+
documented_purpose: config.documentedPurpose || "ComputeSDK sandbox"
|
|
89
|
+
};
|
|
90
|
+
const responseData = await fetchNamespace(token, API_ENDPOINTS.CREATE_INSTANCE, {
|
|
91
|
+
method: "POST",
|
|
92
|
+
body: JSON.stringify(requestBody)
|
|
93
|
+
});
|
|
94
|
+
if (!responseData.metadata?.instanceId) {
|
|
95
|
+
throw new Error(`Instance ID is undefined. Full response object: ${JSON.stringify(responseData, null, 2)}`);
|
|
96
|
+
}
|
|
97
|
+
const instanceId = responseData.metadata.instanceId;
|
|
98
|
+
const instanceName = `instance-${instanceId}`;
|
|
99
|
+
const namespaceSandbox = {
|
|
100
|
+
instanceId,
|
|
101
|
+
name: instanceName
|
|
102
|
+
};
|
|
103
|
+
return {
|
|
104
|
+
sandbox: namespaceSandbox,
|
|
105
|
+
sandboxId: instanceId
|
|
106
|
+
};
|
|
107
|
+
} catch (error) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`Failed to create Namespace instance: ${error instanceof Error ? error.message : String(error)}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
getById: async (config, sandboxId) => {
|
|
114
|
+
const { token } = getAndValidateCredentials(config);
|
|
115
|
+
try {
|
|
116
|
+
const requestBody = {
|
|
117
|
+
instance_id: sandboxId
|
|
118
|
+
};
|
|
119
|
+
const responseData = await fetchNamespace(token, API_ENDPOINTS.DESCRIBE_INSTANCE, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
body: JSON.stringify(requestBody)
|
|
122
|
+
});
|
|
123
|
+
if (!responseData.metadata?.instanceId) {
|
|
124
|
+
throw new Error("Instance data is missing from Namespace response");
|
|
125
|
+
}
|
|
126
|
+
const instanceId = responseData.metadata.instanceId;
|
|
127
|
+
const instanceName = `instance-${instanceId}`;
|
|
128
|
+
const namespaceSandbox = {
|
|
129
|
+
instanceId,
|
|
130
|
+
name: instanceName
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
sandbox: namespaceSandbox,
|
|
134
|
+
sandboxId: instanceId
|
|
135
|
+
};
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (error instanceof Error && error.message.includes("404 Not Found")) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Failed to get Namespace instance: ${error instanceof Error ? error.message : String(error)}`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
list: async (config) => {
|
|
146
|
+
const { token } = getAndValidateCredentials(config);
|
|
147
|
+
try {
|
|
148
|
+
const responseData = await fetchNamespace(token, API_ENDPOINTS.LIST_INSTANCES, {
|
|
149
|
+
method: "POST",
|
|
150
|
+
body: JSON.stringify({})
|
|
151
|
+
});
|
|
152
|
+
const instances = responseData?.instances || [];
|
|
153
|
+
const namespaceSandboxes = instances.map((instanceData) => {
|
|
154
|
+
const instanceId = instanceData.instanceId || instanceData.metadata?.instanceId;
|
|
155
|
+
if (!instanceId) {
|
|
156
|
+
console.warn("Instance missing instanceId:", instanceData);
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const instanceName = `instance-${instanceId}`;
|
|
160
|
+
const namespaceSandbox = {
|
|
161
|
+
instanceId,
|
|
162
|
+
name: instanceName
|
|
163
|
+
};
|
|
164
|
+
return {
|
|
165
|
+
sandbox: namespaceSandbox,
|
|
166
|
+
sandboxId: instanceId
|
|
167
|
+
};
|
|
168
|
+
}).filter(Boolean);
|
|
169
|
+
return namespaceSandboxes;
|
|
170
|
+
} catch (error) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
`Failed to list Namespace instances: ${error instanceof Error ? error.message : String(error)}`
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
destroy: async (config, sandboxId) => {
|
|
177
|
+
const { token } = getAndValidateCredentials(config);
|
|
178
|
+
try {
|
|
179
|
+
const requestBody = {
|
|
180
|
+
instance_id: sandboxId,
|
|
181
|
+
reason: config.destroyReason || "ComputeSDK cleanup"
|
|
182
|
+
};
|
|
183
|
+
const data = await fetchNamespace(token, API_ENDPOINTS.DESTROY_INSTANCE, {
|
|
184
|
+
method: "POST",
|
|
185
|
+
body: JSON.stringify(requestBody)
|
|
186
|
+
});
|
|
187
|
+
if (data.error) {
|
|
188
|
+
console.warn(`Namespace destroy warning: ${data.error}`);
|
|
189
|
+
}
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.warn(`Namespace destroy warning: ${error instanceof Error ? error.message : String(error)}`);
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
// Instance operations (minimal stubs - not implemented yet)
|
|
195
|
+
runCode: async (_sandbox, _code, _runtime) => {
|
|
196
|
+
throw new Error("Namespace runCode method not implemented yet");
|
|
197
|
+
},
|
|
198
|
+
runCommand: async (_sandbox, _command, _args, _options) => {
|
|
199
|
+
throw new Error("Namespace runCommand method not implemented yet");
|
|
200
|
+
},
|
|
201
|
+
getInfo: async (_sandbox) => {
|
|
202
|
+
throw new Error("Namespace getInfo method not implemented yet");
|
|
203
|
+
},
|
|
204
|
+
getUrl: async (_sandbox, _options) => {
|
|
205
|
+
throw new Error("Namespace getUrl method not implemented yet");
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
211
|
+
0 && (module.exports = {
|
|
212
|
+
fetchNamespace,
|
|
213
|
+
getAndValidateCredentials,
|
|
214
|
+
namespace
|
|
215
|
+
});
|
|
216
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Namespace Provider - Factory-based Implementation\n */\n\nimport { createProvider, createBackgroundCommand } from 'computesdk';\nimport type { Runtime, ExecutionResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from 'computesdk';\n\n/**\n * Namespace sandbox interface\n */\ninterface NamespaceSandbox {\n instanceId: string;\n name: string;\n}\n\nexport interface NamespaceConfig {\n /** Namespace API token - if not provided, will fallback to NSC_TOKEN environment variable */\n token?: string;\n /** Virtual CPU cores for the instance */\n virtualCpu?: number;\n /** Memory in megabytes for the instance */\n memoryMegabytes?: number;\n /** Machine architecture (default: amd64) */\n machineArch?: string;\n /** Operating system (default: linux) */\n os?: string;\n /** Documented purpose for the instance */\n documentedPurpose?: string;\n /** Reason for destroying instances (default: \"ComputeSDK cleanup\") */\n destroyReason?: string;\n}\n\nexport const getAndValidateCredentials = (config: NamespaceConfig) => {\n const token = config.token || (typeof process !== 'undefined' && process.env?.NSC_TOKEN) || '';\n\n if (!token) {\n throw new Error(\n 'Missing Namespace token. Provide token in config or set NSC_TOKEN environment variable.'\n );\n }\n\n return { token };\n};\n\nconst API_ENDPOINTS = {\n CREATE_INSTANCE: '/namespace.cloud.compute.v1beta.ComputeService/CreateInstance',\n DESCRIBE_INSTANCE: '/namespace.cloud.compute.v1beta.ComputeService/DescribeInstance',\n LIST_INSTANCES: '/namespace.cloud.compute.v1beta.ComputeService/ListInstances',\n DESTROY_INSTANCE: '/namespace.cloud.compute.v1beta.ComputeService/DestroyInstance'\n};\n\nconst handleApiErrors = (response: any) => {\n if (response.error) {\n throw new Error(`Namespace API error: ${response.error}`);\n }\n};\n\nexport const fetchNamespace = async (\n token: string, \n endpoint: string,\n options: RequestInit = {}\n) => {\n \n const response = await fetch(`https://us.compute.namespaceapis.com${endpoint}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n ...options.headers\n }\n });\n\n if (!response.ok) {\n throw new Error(`Namespace API error: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n\n // Standard error handling for all operations\n handleApiErrors(data);\n\n return data;\n};\n\n/**\n * Create a Namespace provider instance using the factory pattern\n */\nexport const namespace = createProvider<NamespaceSandbox, NamespaceConfig>({\n name: 'namespace',\n methods: {\n sandbox: {\n // Collection operations (compute.sandbox.*)\n create: async (config: NamespaceConfig, options?: CreateSandboxOptions) => {\n const { token } = getAndValidateCredentials(config);\n\n try {\n // Get image based on runtime\n const getImageRef = (runtime?: Runtime) => {\n return runtime === 'node' ? 'node:alpine' : 'python:alpine';\n };\n\n const requestBody = {\n shape: {\n virtual_cpu: config.virtualCpu || 2,\n memory_megabytes: config.memoryMegabytes || 4096,\n machine_arch: config.machineArch || 'amd64',\n os: config.os || 'linux'\n },\n containers: [{\n name: 'main-container',\n image_ref: getImageRef(options?.runtime),\n args: ['sleep', '300']\n }],\n documented_purpose: config.documentedPurpose || 'ComputeSDK sandbox'\n };\n\n const responseData = await fetchNamespace(token, API_ENDPOINTS.CREATE_INSTANCE, {\n method: 'POST',\n body: JSON.stringify(requestBody)\n });\n \n // Extract instance ID from the Namespace API response structure\n if (!responseData.metadata?.instanceId) {\n throw new Error(`Instance ID is undefined. Full response object: ${JSON.stringify(responseData, null, 2)}`);\n }\n\n const instanceId = responseData.metadata.instanceId;\n const instanceName = `instance-${instanceId}`;\n\n const namespaceSandbox: NamespaceSandbox = {\n instanceId,\n name: instanceName,\n };\n\n return {\n sandbox: namespaceSandbox,\n sandboxId: instanceId\n };\n } catch (error) {\n throw new Error(\n `Failed to create Namespace instance: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: NamespaceConfig, sandboxId: string) => {\n const { token } = getAndValidateCredentials(config);\n\n try {\n const requestBody = {\n instance_id: sandboxId\n };\n\n const responseData = await fetchNamespace(token, API_ENDPOINTS.DESCRIBE_INSTANCE, {\n method: 'POST',\n body: JSON.stringify(requestBody)\n });\n \n // Extract instance ID from the Namespace API response structure\n if (!responseData.metadata?.instanceId) {\n throw new Error('Instance data is missing from Namespace response');\n }\n\n const instanceId = responseData.metadata.instanceId;\n const instanceName = `instance-${instanceId}`;\n\n const namespaceSandbox: NamespaceSandbox = {\n instanceId,\n name: instanceName,\n };\n\n return {\n sandbox: namespaceSandbox,\n sandboxId: instanceId\n };\n } catch (error) {\n // Handle 404 errors by returning null (instance not found)\n if (error instanceof Error && error.message.includes('404 Not Found')) {\n return null;\n }\n \n throw new Error(\n `Failed to get Namespace instance: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n \n list: async (config: NamespaceConfig) => {\n const { token } = getAndValidateCredentials(config);\n\n try {\n const responseData = await fetchNamespace(token, API_ENDPOINTS.LIST_INSTANCES, {\n method: 'POST',\n body: JSON.stringify({})\n });\n \n // Extract instances from the response\n const instances = responseData?.instances || [];\n \n // Transform each instance into the expected format\n const namespaceSandboxes = instances.map((instanceData: any) => {\n // For list response, instanceId is directly in the instance object, not in metadata\n const instanceId = instanceData.instanceId || instanceData.metadata?.instanceId;\n if (!instanceId) {\n console.warn('Instance missing instanceId:', instanceData);\n return null;\n }\n \n const instanceName = `instance-${instanceId}`;\n\n const namespaceSandbox: NamespaceSandbox = {\n instanceId,\n name: instanceName,\n };\n\n return {\n sandbox: namespaceSandbox,\n sandboxId: instanceId\n };\n }).filter(Boolean); // Remove any null entries\n\n return namespaceSandboxes;\n } catch (error) {\n throw new Error(\n `Failed to list Namespace instances: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n destroy: async (config: NamespaceConfig, sandboxId: string) => {\n const { token } = getAndValidateCredentials(config);\n\n try {\n const requestBody = {\n instance_id: sandboxId,\n reason: config.destroyReason || \"ComputeSDK cleanup\"\n };\n\n const data = await fetchNamespace(token, API_ENDPOINTS.DESTROY_INSTANCE, {\n method: 'POST',\n body: JSON.stringify(requestBody)\n });\n \n if (data.error) {\n // Log errors but don't throw for destroy operations\n console.warn(`Namespace destroy warning: ${data.error}`);\n }\n } catch (error) {\n // For destroy operations, we typically don't throw if the instance is already gone\n console.warn(`Namespace destroy warning: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n // Instance operations (minimal stubs - not implemented yet)\n runCode: async (_sandbox: NamespaceSandbox, _code: string, _runtime?: Runtime) => {\n throw new Error('Namespace runCode method not implemented yet');\n },\n\n runCommand: async (_sandbox: NamespaceSandbox, _command: string, _args?: string[], _options?: RunCommandOptions) => {\n throw new Error('Namespace runCommand method not implemented yet');\n },\n\n getInfo: async (_sandbox: NamespaceSandbox) => {\n throw new Error('Namespace getInfo method not implemented yet');\n },\n\n getUrl: async (_sandbox: NamespaceSandbox, _options: { port: number; protocol?: string }) => {\n throw new Error('Namespace getUrl method not implemented yet');\n },\n\n },\n },\n});"],"mappings":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { createProvider } from "computesdk";
|
|
3
|
+
var getAndValidateCredentials = (config) => {
|
|
4
|
+
const token = config.token || typeof process !== "undefined" && process.env?.NSC_TOKEN || "";
|
|
5
|
+
if (!token) {
|
|
6
|
+
throw new Error(
|
|
7
|
+
"Missing Namespace token. Provide token in config or set NSC_TOKEN environment variable."
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
return { token };
|
|
11
|
+
};
|
|
12
|
+
var API_ENDPOINTS = {
|
|
13
|
+
CREATE_INSTANCE: "/namespace.cloud.compute.v1beta.ComputeService/CreateInstance",
|
|
14
|
+
DESCRIBE_INSTANCE: "/namespace.cloud.compute.v1beta.ComputeService/DescribeInstance",
|
|
15
|
+
LIST_INSTANCES: "/namespace.cloud.compute.v1beta.ComputeService/ListInstances",
|
|
16
|
+
DESTROY_INSTANCE: "/namespace.cloud.compute.v1beta.ComputeService/DestroyInstance"
|
|
17
|
+
};
|
|
18
|
+
var handleApiErrors = (response) => {
|
|
19
|
+
if (response.error) {
|
|
20
|
+
throw new Error(`Namespace API error: ${response.error}`);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var fetchNamespace = async (token, endpoint, options = {}) => {
|
|
24
|
+
const response = await fetch(`https://us.compute.namespaceapis.com${endpoint}`, {
|
|
25
|
+
...options,
|
|
26
|
+
headers: {
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
"Authorization": `Bearer ${token}`,
|
|
29
|
+
...options.headers
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
throw new Error(`Namespace API error: ${response.status} ${response.statusText}`);
|
|
34
|
+
}
|
|
35
|
+
const data = await response.json();
|
|
36
|
+
handleApiErrors(data);
|
|
37
|
+
return data;
|
|
38
|
+
};
|
|
39
|
+
var namespace = createProvider({
|
|
40
|
+
name: "namespace",
|
|
41
|
+
methods: {
|
|
42
|
+
sandbox: {
|
|
43
|
+
// Collection operations (compute.sandbox.*)
|
|
44
|
+
create: async (config, options) => {
|
|
45
|
+
const { token } = getAndValidateCredentials(config);
|
|
46
|
+
try {
|
|
47
|
+
const getImageRef = (runtime) => {
|
|
48
|
+
return runtime === "node" ? "node:alpine" : "python:alpine";
|
|
49
|
+
};
|
|
50
|
+
const requestBody = {
|
|
51
|
+
shape: {
|
|
52
|
+
virtual_cpu: config.virtualCpu || 2,
|
|
53
|
+
memory_megabytes: config.memoryMegabytes || 4096,
|
|
54
|
+
machine_arch: config.machineArch || "amd64",
|
|
55
|
+
os: config.os || "linux"
|
|
56
|
+
},
|
|
57
|
+
containers: [{
|
|
58
|
+
name: "main-container",
|
|
59
|
+
image_ref: getImageRef(options?.runtime),
|
|
60
|
+
args: ["sleep", "300"]
|
|
61
|
+
}],
|
|
62
|
+
documented_purpose: config.documentedPurpose || "ComputeSDK sandbox"
|
|
63
|
+
};
|
|
64
|
+
const responseData = await fetchNamespace(token, API_ENDPOINTS.CREATE_INSTANCE, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
body: JSON.stringify(requestBody)
|
|
67
|
+
});
|
|
68
|
+
if (!responseData.metadata?.instanceId) {
|
|
69
|
+
throw new Error(`Instance ID is undefined. Full response object: ${JSON.stringify(responseData, null, 2)}`);
|
|
70
|
+
}
|
|
71
|
+
const instanceId = responseData.metadata.instanceId;
|
|
72
|
+
const instanceName = `instance-${instanceId}`;
|
|
73
|
+
const namespaceSandbox = {
|
|
74
|
+
instanceId,
|
|
75
|
+
name: instanceName
|
|
76
|
+
};
|
|
77
|
+
return {
|
|
78
|
+
sandbox: namespaceSandbox,
|
|
79
|
+
sandboxId: instanceId
|
|
80
|
+
};
|
|
81
|
+
} catch (error) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`Failed to create Namespace instance: ${error instanceof Error ? error.message : String(error)}`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
getById: async (config, sandboxId) => {
|
|
88
|
+
const { token } = getAndValidateCredentials(config);
|
|
89
|
+
try {
|
|
90
|
+
const requestBody = {
|
|
91
|
+
instance_id: sandboxId
|
|
92
|
+
};
|
|
93
|
+
const responseData = await fetchNamespace(token, API_ENDPOINTS.DESCRIBE_INSTANCE, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
body: JSON.stringify(requestBody)
|
|
96
|
+
});
|
|
97
|
+
if (!responseData.metadata?.instanceId) {
|
|
98
|
+
throw new Error("Instance data is missing from Namespace response");
|
|
99
|
+
}
|
|
100
|
+
const instanceId = responseData.metadata.instanceId;
|
|
101
|
+
const instanceName = `instance-${instanceId}`;
|
|
102
|
+
const namespaceSandbox = {
|
|
103
|
+
instanceId,
|
|
104
|
+
name: instanceName
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
sandbox: namespaceSandbox,
|
|
108
|
+
sandboxId: instanceId
|
|
109
|
+
};
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error instanceof Error && error.message.includes("404 Not Found")) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Failed to get Namespace instance: ${error instanceof Error ? error.message : String(error)}`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
list: async (config) => {
|
|
120
|
+
const { token } = getAndValidateCredentials(config);
|
|
121
|
+
try {
|
|
122
|
+
const responseData = await fetchNamespace(token, API_ENDPOINTS.LIST_INSTANCES, {
|
|
123
|
+
method: "POST",
|
|
124
|
+
body: JSON.stringify({})
|
|
125
|
+
});
|
|
126
|
+
const instances = responseData?.instances || [];
|
|
127
|
+
const namespaceSandboxes = instances.map((instanceData) => {
|
|
128
|
+
const instanceId = instanceData.instanceId || instanceData.metadata?.instanceId;
|
|
129
|
+
if (!instanceId) {
|
|
130
|
+
console.warn("Instance missing instanceId:", instanceData);
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const instanceName = `instance-${instanceId}`;
|
|
134
|
+
const namespaceSandbox = {
|
|
135
|
+
instanceId,
|
|
136
|
+
name: instanceName
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
sandbox: namespaceSandbox,
|
|
140
|
+
sandboxId: instanceId
|
|
141
|
+
};
|
|
142
|
+
}).filter(Boolean);
|
|
143
|
+
return namespaceSandboxes;
|
|
144
|
+
} catch (error) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Failed to list Namespace instances: ${error instanceof Error ? error.message : String(error)}`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
destroy: async (config, sandboxId) => {
|
|
151
|
+
const { token } = getAndValidateCredentials(config);
|
|
152
|
+
try {
|
|
153
|
+
const requestBody = {
|
|
154
|
+
instance_id: sandboxId,
|
|
155
|
+
reason: config.destroyReason || "ComputeSDK cleanup"
|
|
156
|
+
};
|
|
157
|
+
const data = await fetchNamespace(token, API_ENDPOINTS.DESTROY_INSTANCE, {
|
|
158
|
+
method: "POST",
|
|
159
|
+
body: JSON.stringify(requestBody)
|
|
160
|
+
});
|
|
161
|
+
if (data.error) {
|
|
162
|
+
console.warn(`Namespace destroy warning: ${data.error}`);
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
console.warn(`Namespace destroy warning: ${error instanceof Error ? error.message : String(error)}`);
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
// Instance operations (minimal stubs - not implemented yet)
|
|
169
|
+
runCode: async (_sandbox, _code, _runtime) => {
|
|
170
|
+
throw new Error("Namespace runCode method not implemented yet");
|
|
171
|
+
},
|
|
172
|
+
runCommand: async (_sandbox, _command, _args, _options) => {
|
|
173
|
+
throw new Error("Namespace runCommand method not implemented yet");
|
|
174
|
+
},
|
|
175
|
+
getInfo: async (_sandbox) => {
|
|
176
|
+
throw new Error("Namespace getInfo method not implemented yet");
|
|
177
|
+
},
|
|
178
|
+
getUrl: async (_sandbox, _options) => {
|
|
179
|
+
throw new Error("Namespace getUrl method not implemented yet");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
export {
|
|
185
|
+
fetchNamespace,
|
|
186
|
+
getAndValidateCredentials,
|
|
187
|
+
namespace
|
|
188
|
+
};
|
|
189
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Namespace Provider - Factory-based Implementation\n */\n\nimport { createProvider, createBackgroundCommand } from 'computesdk';\nimport type { Runtime, ExecutionResult, SandboxInfo, CreateSandboxOptions, FileEntry, RunCommandOptions } from 'computesdk';\n\n/**\n * Namespace sandbox interface\n */\ninterface NamespaceSandbox {\n instanceId: string;\n name: string;\n}\n\nexport interface NamespaceConfig {\n /** Namespace API token - if not provided, will fallback to NSC_TOKEN environment variable */\n token?: string;\n /** Virtual CPU cores for the instance */\n virtualCpu?: number;\n /** Memory in megabytes for the instance */\n memoryMegabytes?: number;\n /** Machine architecture (default: amd64) */\n machineArch?: string;\n /** Operating system (default: linux) */\n os?: string;\n /** Documented purpose for the instance */\n documentedPurpose?: string;\n /** Reason for destroying instances (default: \"ComputeSDK cleanup\") */\n destroyReason?: string;\n}\n\nexport const getAndValidateCredentials = (config: NamespaceConfig) => {\n const token = config.token || (typeof process !== 'undefined' && process.env?.NSC_TOKEN) || '';\n\n if (!token) {\n throw new Error(\n 'Missing Namespace token. Provide token in config or set NSC_TOKEN environment variable.'\n );\n }\n\n return { token };\n};\n\nconst API_ENDPOINTS = {\n CREATE_INSTANCE: '/namespace.cloud.compute.v1beta.ComputeService/CreateInstance',\n DESCRIBE_INSTANCE: '/namespace.cloud.compute.v1beta.ComputeService/DescribeInstance',\n LIST_INSTANCES: '/namespace.cloud.compute.v1beta.ComputeService/ListInstances',\n DESTROY_INSTANCE: '/namespace.cloud.compute.v1beta.ComputeService/DestroyInstance'\n};\n\nconst handleApiErrors = (response: any) => {\n if (response.error) {\n throw new Error(`Namespace API error: ${response.error}`);\n }\n};\n\nexport const fetchNamespace = async (\n token: string, \n endpoint: string,\n options: RequestInit = {}\n) => {\n \n const response = await fetch(`https://us.compute.namespaceapis.com${endpoint}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n ...options.headers\n }\n });\n\n if (!response.ok) {\n throw new Error(`Namespace API error: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n\n // Standard error handling for all operations\n handleApiErrors(data);\n\n return data;\n};\n\n/**\n * Create a Namespace provider instance using the factory pattern\n */\nexport const namespace = createProvider<NamespaceSandbox, NamespaceConfig>({\n name: 'namespace',\n methods: {\n sandbox: {\n // Collection operations (compute.sandbox.*)\n create: async (config: NamespaceConfig, options?: CreateSandboxOptions) => {\n const { token } = getAndValidateCredentials(config);\n\n try {\n // Get image based on runtime\n const getImageRef = (runtime?: Runtime) => {\n return runtime === 'node' ? 'node:alpine' : 'python:alpine';\n };\n\n const requestBody = {\n shape: {\n virtual_cpu: config.virtualCpu || 2,\n memory_megabytes: config.memoryMegabytes || 4096,\n machine_arch: config.machineArch || 'amd64',\n os: config.os || 'linux'\n },\n containers: [{\n name: 'main-container',\n image_ref: getImageRef(options?.runtime),\n args: ['sleep', '300']\n }],\n documented_purpose: config.documentedPurpose || 'ComputeSDK sandbox'\n };\n\n const responseData = await fetchNamespace(token, API_ENDPOINTS.CREATE_INSTANCE, {\n method: 'POST',\n body: JSON.stringify(requestBody)\n });\n \n // Extract instance ID from the Namespace API response structure\n if (!responseData.metadata?.instanceId) {\n throw new Error(`Instance ID is undefined. Full response object: ${JSON.stringify(responseData, null, 2)}`);\n }\n\n const instanceId = responseData.metadata.instanceId;\n const instanceName = `instance-${instanceId}`;\n\n const namespaceSandbox: NamespaceSandbox = {\n instanceId,\n name: instanceName,\n };\n\n return {\n sandbox: namespaceSandbox,\n sandboxId: instanceId\n };\n } catch (error) {\n throw new Error(\n `Failed to create Namespace instance: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n getById: async (config: NamespaceConfig, sandboxId: string) => {\n const { token } = getAndValidateCredentials(config);\n\n try {\n const requestBody = {\n instance_id: sandboxId\n };\n\n const responseData = await fetchNamespace(token, API_ENDPOINTS.DESCRIBE_INSTANCE, {\n method: 'POST',\n body: JSON.stringify(requestBody)\n });\n \n // Extract instance ID from the Namespace API response structure\n if (!responseData.metadata?.instanceId) {\n throw new Error('Instance data is missing from Namespace response');\n }\n\n const instanceId = responseData.metadata.instanceId;\n const instanceName = `instance-${instanceId}`;\n\n const namespaceSandbox: NamespaceSandbox = {\n instanceId,\n name: instanceName,\n };\n\n return {\n sandbox: namespaceSandbox,\n sandboxId: instanceId\n };\n } catch (error) {\n // Handle 404 errors by returning null (instance not found)\n if (error instanceof Error && error.message.includes('404 Not Found')) {\n return null;\n }\n \n throw new Error(\n `Failed to get Namespace instance: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n \n list: async (config: NamespaceConfig) => {\n const { token } = getAndValidateCredentials(config);\n\n try {\n const responseData = await fetchNamespace(token, API_ENDPOINTS.LIST_INSTANCES, {\n method: 'POST',\n body: JSON.stringify({})\n });\n \n // Extract instances from the response\n const instances = responseData?.instances || [];\n \n // Transform each instance into the expected format\n const namespaceSandboxes = instances.map((instanceData: any) => {\n // For list response, instanceId is directly in the instance object, not in metadata\n const instanceId = instanceData.instanceId || instanceData.metadata?.instanceId;\n if (!instanceId) {\n console.warn('Instance missing instanceId:', instanceData);\n return null;\n }\n \n const instanceName = `instance-${instanceId}`;\n\n const namespaceSandbox: NamespaceSandbox = {\n instanceId,\n name: instanceName,\n };\n\n return {\n sandbox: namespaceSandbox,\n sandboxId: instanceId\n };\n }).filter(Boolean); // Remove any null entries\n\n return namespaceSandboxes;\n } catch (error) {\n throw new Error(\n `Failed to list Namespace instances: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n },\n\n destroy: async (config: NamespaceConfig, sandboxId: string) => {\n const { token } = getAndValidateCredentials(config);\n\n try {\n const requestBody = {\n instance_id: sandboxId,\n reason: config.destroyReason || \"ComputeSDK cleanup\"\n };\n\n const data = await fetchNamespace(token, API_ENDPOINTS.DESTROY_INSTANCE, {\n method: 'POST',\n body: JSON.stringify(requestBody)\n });\n \n if (data.error) {\n // Log errors but don't throw for destroy operations\n console.warn(`Namespace destroy warning: ${data.error}`);\n }\n } catch (error) {\n // For destroy operations, we typically don't throw if the instance is already gone\n console.warn(`Namespace destroy warning: ${error instanceof Error ? error.message : String(error)}`);\n }\n },\n\n // Instance operations (minimal stubs - not implemented yet)\n runCode: async (_sandbox: NamespaceSandbox, _code: string, _runtime?: Runtime) => {\n throw new Error('Namespace runCode method not implemented yet');\n },\n\n runCommand: async (_sandbox: NamespaceSandbox, _command: string, _args?: string[], _options?: RunCommandOptions) => {\n throw new Error('Namespace runCommand method not implemented yet');\n },\n\n getInfo: async (_sandbox: NamespaceSandbox) => {\n throw new Error('Namespace getInfo method not implemented yet');\n },\n\n getUrl: async (_sandbox: NamespaceSandbox, _options: { port: number; protocol?: string }) => {\n throw new Error('Namespace getUrl method not implemented yet');\n },\n\n },\n },\n});"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@computesdk/namespace",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Namespace provider for ComputeSDK",
|
|
5
|
+
"author": "ComputeSDK Team",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.mjs",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.mjs",
|
|
14
|
+
"require": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"computesdk": "1.8.7"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"namespace",
|
|
25
|
+
"sandbox",
|
|
26
|
+
"code-execution",
|
|
27
|
+
"cloud",
|
|
28
|
+
"compute",
|
|
29
|
+
"containers"
|
|
30
|
+
],
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/computesdk/computesdk.git",
|
|
34
|
+
"directory": "packages/namespace"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/computesdk/computesdk/tree/main/packages/namespace",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/computesdk/computesdk/issues"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^20.0.0",
|
|
42
|
+
"@vitest/coverage-v8": "^1.0.0",
|
|
43
|
+
"dotenv": "^17.2.1",
|
|
44
|
+
"eslint": "^8.37.0",
|
|
45
|
+
"rimraf": "^5.0.0",
|
|
46
|
+
"tsup": "^8.0.0",
|
|
47
|
+
"typescript": "^5.0.0",
|
|
48
|
+
"vitest": "^1.0.0",
|
|
49
|
+
"@computesdk/test-utils": "1.4.1"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsup",
|
|
53
|
+
"clean": "rimraf dist",
|
|
54
|
+
"dev": "tsup --watch",
|
|
55
|
+
"test": "vitest run",
|
|
56
|
+
"test:watch": "vitest watch",
|
|
57
|
+
"test:coverage": "vitest run --coverage",
|
|
58
|
+
"typecheck": "tsc --noEmit",
|
|
59
|
+
"lint": "eslint"
|
|
60
|
+
}
|
|
61
|
+
}
|