@crossplane-org/function-sdk-typescript 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +683 -0
- package/dist/example-function.d.ts +11 -0
- package/dist/example-function.d.ts.map +1 -0
- package/dist/example-function.js +93 -0
- package/dist/example-function.js.map +1 -0
- package/dist/function/function.d.ts +115 -0
- package/dist/function/function.d.ts.map +1 -0
- package/dist/function/function.js +111 -0
- package/dist/function/function.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +69 -0
- package/dist/main.js.map +1 -0
- package/dist/proto/google/protobuf/duration.d.ts +107 -0
- package/dist/proto/google/protobuf/duration.d.ts.map +1 -0
- package/dist/proto/google/protobuf/duration.js +90 -0
- package/dist/proto/google/protobuf/duration.js.map +1 -0
- package/dist/proto/google/protobuf/struct.d.ts +115 -0
- package/dist/proto/google/protobuf/struct.d.ts.map +1 -0
- package/dist/proto/google/protobuf/struct.js +452 -0
- package/dist/proto/google/protobuf/struct.js.map +1 -0
- package/dist/proto/run_function.d.ts +494 -0
- package/dist/proto/run_function.d.ts.map +1 -0
- package/dist/proto/run_function.js +2230 -0
- package/dist/proto/run_function.js.map +1 -0
- package/dist/request/request.d.ts +198 -0
- package/dist/request/request.d.ts.map +1 -0
- package/dist/request/request.js +219 -0
- package/dist/request/request.js.map +1 -0
- package/dist/resource/resource.d.ts +101 -0
- package/dist/resource/resource.d.ts.map +1 -0
- package/dist/resource/resource.js +98 -0
- package/dist/resource/resource.js.map +1 -0
- package/dist/response/response.d.ts +273 -0
- package/dist/response/response.d.ts.map +1 -0
- package/dist/response/response.js +339 -0
- package/dist/response/response.js.map +1 -0
- package/dist/runtime/runtime.d.ts +121 -0
- package/dist/runtime/runtime.d.ts.map +1 -0
- package/dist/runtime/runtime.js +124 -0
- package/dist/runtime/runtime.js.map +1 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +17 -0
- package/dist/vitest.config.js.map +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
# Crossplane Function SDK for TypeScript
|
|
2
|
+
|
|
3
|
+
A TypeScript SDK for building [Crossplane Composition Functions](https://docs.crossplane.io/latest/concepts/composition-functions/). This SDK provides type-safe interfaces and utilities for creating functions that generate and manage Crossplane resources.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This SDK can be used as the base of a Crossplane Composition function.
|
|
8
|
+
|
|
9
|
+
For complete usage instructions on importing this SDK into your projects, see [USAGE.md](USAGE.md).
|
|
10
|
+
|
|
11
|
+
## Quick Start (Using as an Importable SDK)
|
|
12
|
+
|
|
13
|
+
### Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @crossplane-org/function-sdk-typescript
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Creating Your Function
|
|
20
|
+
|
|
21
|
+
Implement the `FunctionHandler` interface:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import type {
|
|
25
|
+
FunctionHandler,
|
|
26
|
+
RunFunctionRequest,
|
|
27
|
+
RunFunctionResponse,
|
|
28
|
+
Logger
|
|
29
|
+
} from "@crossplane-org/function-sdk-typescript";
|
|
30
|
+
import {
|
|
31
|
+
to,
|
|
32
|
+
normal,
|
|
33
|
+
fatal,
|
|
34
|
+
setDesiredComposedResources,
|
|
35
|
+
getDesiredComposedResources,
|
|
36
|
+
getObservedCompositeResource,
|
|
37
|
+
Resource
|
|
38
|
+
} from "@crossplane-org/function-sdk-typescript";
|
|
39
|
+
|
|
40
|
+
export class MyFunction implements FunctionHandler {
|
|
41
|
+
async RunFunction(req: RunFunctionRequest, logger?: Logger): Promise<RunFunctionResponse> {
|
|
42
|
+
let rsp = to(req);
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
// Get observed composite resource and desired composed resources
|
|
46
|
+
const oxr = getObservedCompositeResource(req);
|
|
47
|
+
let dcds = getDesiredComposedResources(req);
|
|
48
|
+
|
|
49
|
+
logger?.info("Processing function request");
|
|
50
|
+
|
|
51
|
+
// Your function logic here - create a ConfigMap
|
|
52
|
+
dcds["my-resource"] = Resource.fromJSON({
|
|
53
|
+
resource: {
|
|
54
|
+
apiVersion: "v1",
|
|
55
|
+
kind: "ConfigMap",
|
|
56
|
+
metadata: { name: "my-config" },
|
|
57
|
+
data: { key: "value" }
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
rsp = setDesiredComposedResources(rsp, dcds);
|
|
62
|
+
normal(rsp, "Function completed successfully");
|
|
63
|
+
|
|
64
|
+
return rsp;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
logger?.error({ error }, "Function failed");
|
|
67
|
+
fatal(rsp, error instanceof Error ? error.message : String(error));
|
|
68
|
+
return rsp;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
See [USAGE.md](USAGE.md) for complete examples and API documentation.
|
|
75
|
+
|
|
76
|
+
## Development Setup (For SDK Contributors)
|
|
77
|
+
|
|
78
|
+
### Prerequisites
|
|
79
|
+
|
|
80
|
+
- Node.js 18+
|
|
81
|
+
- npm or yarn
|
|
82
|
+
- Docker (for building container images)
|
|
83
|
+
- protoc (Protocol Buffer compiler) - `brew install protobuf`
|
|
84
|
+
|
|
85
|
+
### Setup
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm install
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Testing
|
|
92
|
+
|
|
93
|
+
The SDK uses [Vitest](https://vitest.dev/) for testing. Tests are located alongside source files with the `.test.ts` extension.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Run tests once
|
|
97
|
+
npm test
|
|
98
|
+
|
|
99
|
+
# Run tests in watch mode (for development)
|
|
100
|
+
npm run test:watch
|
|
101
|
+
|
|
102
|
+
# Run tests with coverage report
|
|
103
|
+
npm run test:coverage
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Test files are automatically excluded from the build output.
|
|
107
|
+
|
|
108
|
+
### Running the Example Function
|
|
109
|
+
|
|
110
|
+
Start the function server in development mode:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm run build
|
|
114
|
+
npm run local-run
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The function will listen on `0.0.0.0:9443` by default.
|
|
118
|
+
|
|
119
|
+
### Testing Your Function
|
|
120
|
+
|
|
121
|
+
After running `npm run local-run` in another terminal, use the Crossplane CLI to
|
|
122
|
+
call your local function using `crossplane render`:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
cd example
|
|
126
|
+
./render.sh
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Basic Function Structure
|
|
130
|
+
|
|
131
|
+
The main function logic goes in `src/function/function.ts`:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import { Resource, RunFunctionRequest, RunFunctionResponse } from "../proto/run_function.js";
|
|
135
|
+
import { to, setDesiredComposedResources, normal } from "../response/response.js";
|
|
136
|
+
import { getDesiredComposedResources } from "../request/request.js";
|
|
137
|
+
|
|
138
|
+
export class FunctionRunner {
|
|
139
|
+
async RunFunction(
|
|
140
|
+
req: RunFunctionRequest,
|
|
141
|
+
logger?: Logger,
|
|
142
|
+
): Promise<RunFunctionResponse> {
|
|
143
|
+
// Initialize response from request
|
|
144
|
+
let rsp = to(req);
|
|
145
|
+
|
|
146
|
+
// Get desired composed resources from request
|
|
147
|
+
let dcds = getDesiredComposedResources(req);
|
|
148
|
+
|
|
149
|
+
// Create a new resource using plain JSON
|
|
150
|
+
dcds["my-deployment"] = Resource.fromJSON({
|
|
151
|
+
resource: {
|
|
152
|
+
apiVersion: "apps/v1",
|
|
153
|
+
kind: "Deployment",
|
|
154
|
+
metadata: {
|
|
155
|
+
name: "my-deployment",
|
|
156
|
+
namespace: "default",
|
|
157
|
+
},
|
|
158
|
+
spec: {
|
|
159
|
+
replicas: 3,
|
|
160
|
+
// ... deployment spec
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Set desired resources in response
|
|
166
|
+
rsp = setDesiredComposedResources(rsp, dcds);
|
|
167
|
+
|
|
168
|
+
// Add a result message
|
|
169
|
+
normal(rsp, "Resources created successfully");
|
|
170
|
+
|
|
171
|
+
return rsp;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Using Kubernetes Models
|
|
177
|
+
|
|
178
|
+
You can use type-safe Kubernetes models from the `kubernetes-models` package:
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import { Deployment } from "kubernetes-models/apps/v1";
|
|
182
|
+
import { Pod } from "kubernetes-models/v1";
|
|
183
|
+
|
|
184
|
+
// Create a type-safe Pod
|
|
185
|
+
const pod = new Pod({
|
|
186
|
+
metadata: {
|
|
187
|
+
name: "my-pod",
|
|
188
|
+
namespace: "default",
|
|
189
|
+
},
|
|
190
|
+
spec: {
|
|
191
|
+
containers: [{
|
|
192
|
+
name: "app",
|
|
193
|
+
image: "nginx:latest",
|
|
194
|
+
}],
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Validate the pod
|
|
199
|
+
pod.validate();
|
|
200
|
+
|
|
201
|
+
// Convert to Resource
|
|
202
|
+
dcds["my-pod"] = Resource.fromJSON({
|
|
203
|
+
resource: pod.toJSON()
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Helper Functions
|
|
208
|
+
|
|
209
|
+
#### Request Helpers
|
|
210
|
+
|
|
211
|
+
The SDK provides comprehensive request helpers to extract data from RunFunctionRequest:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import {
|
|
215
|
+
getObservedCompositeResource,
|
|
216
|
+
getDesiredCompositeResource,
|
|
217
|
+
getDesiredComposedResources,
|
|
218
|
+
getObservedComposedResources,
|
|
219
|
+
getInput,
|
|
220
|
+
getContextKey,
|
|
221
|
+
getRequiredResources,
|
|
222
|
+
getCredentials,
|
|
223
|
+
} from "@crossplane-org/function-sdk-typescript";
|
|
224
|
+
|
|
225
|
+
// Get the observed composite resource (XR)
|
|
226
|
+
const oxr = getObservedCompositeResource(req);
|
|
227
|
+
|
|
228
|
+
// Get the desired composite resource
|
|
229
|
+
const dxr = getDesiredCompositeResource(req);
|
|
230
|
+
|
|
231
|
+
// Get desired composed resources
|
|
232
|
+
const dcds = getDesiredComposedResources(req);
|
|
233
|
+
|
|
234
|
+
// Get observed composed resources
|
|
235
|
+
const ocds = getObservedComposedResources(req);
|
|
236
|
+
|
|
237
|
+
// Get function input configuration
|
|
238
|
+
const input = getInput(req);
|
|
239
|
+
|
|
240
|
+
// Get context value from previous function
|
|
241
|
+
const [value, exists] = getContextKey(req, "my-key");
|
|
242
|
+
|
|
243
|
+
// Get required resources
|
|
244
|
+
const required = getRequiredResources(req);
|
|
245
|
+
|
|
246
|
+
// Get credentials
|
|
247
|
+
const creds = getCredentials(req, "aws-creds");
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### Response Helpers
|
|
251
|
+
|
|
252
|
+
The SDK provides response helpers to build and manipulate RunFunctionResponse:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import {
|
|
256
|
+
to,
|
|
257
|
+
setDesiredComposedResources,
|
|
258
|
+
setDesiredCompositeResource,
|
|
259
|
+
setDesiredCompositeStatus,
|
|
260
|
+
setContextKey,
|
|
261
|
+
setOutput,
|
|
262
|
+
normal,
|
|
263
|
+
fatal,
|
|
264
|
+
warning,
|
|
265
|
+
update,
|
|
266
|
+
DEFAULT_TTL,
|
|
267
|
+
} from "@crossplane-org/function-sdk-typescript";
|
|
268
|
+
|
|
269
|
+
// Initialize response from request (with optional TTL)
|
|
270
|
+
let rsp = to(req, DEFAULT_TTL);
|
|
271
|
+
|
|
272
|
+
// Set desired composed resources (merges with existing)
|
|
273
|
+
rsp = setDesiredComposedResources(rsp, dcds);
|
|
274
|
+
|
|
275
|
+
// Set desired composite resource
|
|
276
|
+
rsp = setDesiredCompositeResource(rsp, dxr);
|
|
277
|
+
|
|
278
|
+
// Update composite resource status
|
|
279
|
+
rsp = setDesiredCompositeStatus({ rsp, status: { ready: true } });
|
|
280
|
+
|
|
281
|
+
// Set context for next function
|
|
282
|
+
rsp = setContextKey(rsp, "my-key", "my-value");
|
|
283
|
+
|
|
284
|
+
// Set output (returned to user)
|
|
285
|
+
rsp = setOutput(rsp, { result: "success" });
|
|
286
|
+
|
|
287
|
+
// Add result messages
|
|
288
|
+
normal(rsp, "Success message");
|
|
289
|
+
warning(rsp, "Warning message");
|
|
290
|
+
fatal(rsp, "Fatal error message");
|
|
291
|
+
|
|
292
|
+
// Update a resource by merging
|
|
293
|
+
const updated = update(sourceResource, targetResource);
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### Resource Helpers
|
|
297
|
+
|
|
298
|
+
The SDK provides utilities for working with Kubernetes resources:
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
import {
|
|
302
|
+
Resource,
|
|
303
|
+
asObject,
|
|
304
|
+
asStruct,
|
|
305
|
+
fromObject,
|
|
306
|
+
toObject,
|
|
307
|
+
newDesiredComposed,
|
|
308
|
+
} from "@crossplane-org/function-sdk-typescript";
|
|
309
|
+
|
|
310
|
+
// Create a Resource from a plain object
|
|
311
|
+
const resource = fromObject({
|
|
312
|
+
apiVersion: "v1",
|
|
313
|
+
kind: "ConfigMap",
|
|
314
|
+
metadata: { name: "my-config" }
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Extract plain object from Resource
|
|
318
|
+
const obj = toObject(resource);
|
|
319
|
+
|
|
320
|
+
// Convert between struct and object formats
|
|
321
|
+
const struct = asStruct(obj);
|
|
322
|
+
const plainObj = asObject(struct);
|
|
323
|
+
|
|
324
|
+
// Create a new empty DesiredComposed resource
|
|
325
|
+
const desired = newDesiredComposed();
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Error Handling
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
try {
|
|
332
|
+
// Your function logic
|
|
333
|
+
} catch (error) {
|
|
334
|
+
fatal(rsp, error instanceof Error ? error.message : String(error));
|
|
335
|
+
return rsp;
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Publishing the SDK
|
|
340
|
+
|
|
341
|
+
This section is for SDK maintainers who want to publish updates to npm.
|
|
342
|
+
|
|
343
|
+
### Prepare for Publishing
|
|
344
|
+
|
|
345
|
+
1. Update version in [package.json](package.json)
|
|
346
|
+
2. Build the TypeScript code:
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
npm run build
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
3. Verify the build output in `dist/`:
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
ls -la dist/
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Test the Package Locally
|
|
359
|
+
|
|
360
|
+
Before publishing, test the package locally:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
# Create a tarball
|
|
364
|
+
npm pack
|
|
365
|
+
|
|
366
|
+
# This creates function-sdk-typescript-<version>.tgz
|
|
367
|
+
# Install it in another project to test
|
|
368
|
+
npm install /path/to/function-sdk-typescript-<version>.tgz
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Publish to npm
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
# Dry run to see what will be published
|
|
375
|
+
npm publish --dry-run
|
|
376
|
+
|
|
377
|
+
# Publish to npm (requires authentication)
|
|
378
|
+
npm publish
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
The [package.json](package.json) `files` field ensures only necessary files are included:
|
|
382
|
+
|
|
383
|
+
- `dist/` - Compiled JavaScript and type definitions
|
|
384
|
+
- `README.md` - Documentation
|
|
385
|
+
|
|
386
|
+
### Building Function Containers
|
|
387
|
+
|
|
388
|
+
If you're developing a function based on this SDK and need to containerize it:
|
|
389
|
+
|
|
390
|
+
1. Create a `Dockerfile` for your function
|
|
391
|
+
2. Build the image with your function code
|
|
392
|
+
3. Package as a Crossplane function package
|
|
393
|
+
|
|
394
|
+
See the [Crossplane documentation](https://docs.crossplane.io/latest/concepts/composition-functions/#build-a-function) for details on building and packaging functions.
|
|
395
|
+
|
|
396
|
+
## Development
|
|
397
|
+
|
|
398
|
+
### Generating Protobuf Code
|
|
399
|
+
|
|
400
|
+
This repo uses the Protobuf definitions from [Crossplane](https://github.com/crossplane/crossplane/tree/main/proto/fn). If the upstream definition is updated, copy it into this repo and regenerate the TypeScript code.
|
|
401
|
+
|
|
402
|
+
#### Protocol Buffers Prerequisites
|
|
403
|
+
|
|
404
|
+
You need the Protocol Buffer compiler (`protoc`) installed:
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
# macOS
|
|
408
|
+
brew install protobuf
|
|
409
|
+
|
|
410
|
+
# Verify installation
|
|
411
|
+
protoc --version # Should be 3.x or higher
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
#### Regenerating Code
|
|
415
|
+
|
|
416
|
+
To regenerate TypeScript code from the Protobuf definitions:
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
./scripts/protoc-gen.sh
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
This script uses [ts-proto](https://github.com/stephenh/ts-proto) to generate:
|
|
423
|
+
|
|
424
|
+
- Type definitions from protobuf messages
|
|
425
|
+
- gRPC service stubs for the FunctionRunner service
|
|
426
|
+
- Conversion utilities for Protocol Buffer types
|
|
427
|
+
|
|
428
|
+
After regenerating, rebuild the project:
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
npm run build
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Local Development Workflow
|
|
435
|
+
|
|
436
|
+
For SDK contributors making changes to the SDK itself:
|
|
437
|
+
|
|
438
|
+
1. Make changes to source files in `src/`
|
|
439
|
+
2. Build the SDK: `npm run build`
|
|
440
|
+
3. Test locally by creating a tarball: `npm pack`
|
|
441
|
+
4. Install the tarball in a test project to verify changes
|
|
442
|
+
|
|
443
|
+
For testing with an example function:
|
|
444
|
+
|
|
445
|
+
1. Implement an example function using the SDK
|
|
446
|
+
2. Build: `npm run build`
|
|
447
|
+
3. Run the function server locally (if you have a main entry point)
|
|
448
|
+
4. Test with `crossplane beta render` using example compositions
|
|
449
|
+
|
|
450
|
+
### Using with Crossplane
|
|
451
|
+
|
|
452
|
+
Create a `Function` resource in your cluster:
|
|
453
|
+
|
|
454
|
+
```yaml
|
|
455
|
+
apiVersion: pkg.crossplane.io/v1beta1
|
|
456
|
+
kind: Function
|
|
457
|
+
metadata:
|
|
458
|
+
name: your-registry-function-typescript
|
|
459
|
+
spec:
|
|
460
|
+
package: your-registry/function-typescript:v0.1.0
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
Reference it in your Composition:
|
|
464
|
+
|
|
465
|
+
```yaml
|
|
466
|
+
apiVersion: apiextensions.crossplane.io/v1
|
|
467
|
+
kind: Composition
|
|
468
|
+
metadata:
|
|
469
|
+
name: my-composition
|
|
470
|
+
spec:
|
|
471
|
+
mode: Pipeline
|
|
472
|
+
pipeline:
|
|
473
|
+
- step: run-typescript-function
|
|
474
|
+
functionRef:
|
|
475
|
+
name: function-typescript
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Creating Resources
|
|
479
|
+
|
|
480
|
+
Resources can be created from Typescript Objects using `Resource.fromJSON()`:
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
// Plain JSON object automatically converted to Struct
|
|
484
|
+
Resource.fromJSON({
|
|
485
|
+
resource: {
|
|
486
|
+
apiVersion: "v1",
|
|
487
|
+
kind: "ConfigMap",
|
|
488
|
+
// ... any valid Kubernetes resource
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
## API Reference
|
|
494
|
+
|
|
495
|
+
### Exported Types and Interfaces
|
|
496
|
+
|
|
497
|
+
The SDK exports all types and interfaces from a single entry point:
|
|
498
|
+
|
|
499
|
+
```typescript
|
|
500
|
+
import {
|
|
501
|
+
// Core interfaces
|
|
502
|
+
FunctionHandler,
|
|
503
|
+
FunctionRunner,
|
|
504
|
+
Logger,
|
|
505
|
+
|
|
506
|
+
// Request/Response types
|
|
507
|
+
RunFunctionRequest,
|
|
508
|
+
RunFunctionResponse,
|
|
509
|
+
Resource,
|
|
510
|
+
|
|
511
|
+
// Resource types
|
|
512
|
+
Composite,
|
|
513
|
+
ObservedComposed,
|
|
514
|
+
DesiredComposed,
|
|
515
|
+
ConnectionDetails,
|
|
516
|
+
|
|
517
|
+
// Protocol buffer types
|
|
518
|
+
Severity,
|
|
519
|
+
Result,
|
|
520
|
+
State,
|
|
521
|
+
Ready,
|
|
522
|
+
Target,
|
|
523
|
+
Status,
|
|
524
|
+
Condition,
|
|
525
|
+
Resources,
|
|
526
|
+
Credentials,
|
|
527
|
+
CredentialData,
|
|
528
|
+
|
|
529
|
+
// Runtime types
|
|
530
|
+
ServerOptions,
|
|
531
|
+
} from "@crossplane-org/function-sdk-typescript";
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Core Functions
|
|
535
|
+
|
|
536
|
+
- **`to(req, ttl?)`** - Initialize a response from a request
|
|
537
|
+
- **`normal(rsp, message)`** - Add a normal (info) result
|
|
538
|
+
- **`warning(rsp, message)`** - Add a warning result
|
|
539
|
+
- **`fatal(rsp, message)`** - Add a fatal error result
|
|
540
|
+
- **`getObservedCompositeResource(req)`** - Get the observed XR
|
|
541
|
+
- **`getDesiredCompositeResource(req)`** - Get the desired XR
|
|
542
|
+
- **`getDesiredComposedResources(req)`** - Get desired composed resources
|
|
543
|
+
- **`getObservedComposedResources(req)`** - Get observed composed resources
|
|
544
|
+
- **`setDesiredComposedResources(rsp, resources)`** - Set desired composed resources
|
|
545
|
+
- **`setDesiredCompositeStatus({rsp, status})`** - Update XR status
|
|
546
|
+
- **`setContextKey(rsp, key, value)`** - Set context for next function
|
|
547
|
+
- **`getContextKey(req, key)`** - Get context from previous function
|
|
548
|
+
- **`getInput(req)`** - Get function input configuration
|
|
549
|
+
- **`getRequiredResources(req)`** - Get required resources
|
|
550
|
+
- **`getCredentials(req, name)`** - Get credentials by name (throws error if not found)
|
|
551
|
+
|
|
552
|
+
See [USAGE.md](USAGE.md) for detailed API documentation and examples.
|
|
553
|
+
|
|
554
|
+
## Dependencies
|
|
555
|
+
|
|
556
|
+
### Runtime Dependencies
|
|
557
|
+
|
|
558
|
+
- **`@grpc/grpc-js`** - gRPC implementation for Node.js
|
|
559
|
+
- **`@grpc/proto-loader`** - Protocol buffer loader
|
|
560
|
+
- **`google-protobuf`** - Google Protocol Buffers runtime
|
|
561
|
+
- **`ts-proto`** - TypeScript protobuf code generator
|
|
562
|
+
- **`ts-deepmerge`** - Deep merging utility for resources
|
|
563
|
+
- **`pino`** - Fast, structured JSON logger
|
|
564
|
+
- **`kubernetes-models`** - Type-safe Kubernetes resource models (optional)
|
|
565
|
+
|
|
566
|
+
### Development Dependencies
|
|
567
|
+
|
|
568
|
+
- **`typescript`** - TypeScript compiler (v5.7+)
|
|
569
|
+
- **`@types/node`** - Node.js type definitions
|
|
570
|
+
- **`@types/google-protobuf`** - Google Protobuf type definitions
|
|
571
|
+
- **`ts-node`** - TypeScript execution engine
|
|
572
|
+
- **`vitest`** - Fast unit test framework
|
|
573
|
+
- **`@vitest/coverage-v8`** - Code coverage reporting
|
|
574
|
+
- **Protocol Buffer compiler (`protoc`)** - Required for regenerating protobuf code
|
|
575
|
+
|
|
576
|
+
## Troubleshooting
|
|
577
|
+
|
|
578
|
+
### Installation Issues
|
|
579
|
+
|
|
580
|
+
**Problem**: Package not found or installation fails
|
|
581
|
+
|
|
582
|
+
```bash
|
|
583
|
+
# Verify npm registry access
|
|
584
|
+
npm ping
|
|
585
|
+
|
|
586
|
+
# Try installing with verbose output
|
|
587
|
+
npm install @crossplane-org/function-sdk-typescript --verbose
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Type Errors
|
|
591
|
+
|
|
592
|
+
**Problem**: TypeScript can't find types from the SDK
|
|
593
|
+
|
|
594
|
+
**Solution**: Ensure your `tsconfig.json` includes:
|
|
595
|
+
|
|
596
|
+
```json
|
|
597
|
+
{
|
|
598
|
+
"compilerOptions": {
|
|
599
|
+
"moduleResolution": "node",
|
|
600
|
+
"esModuleInterop": true
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
### Import Errors
|
|
606
|
+
|
|
607
|
+
**Problem**: `Cannot find module '@crossplane-org/function-sdk-typescript'`
|
|
608
|
+
|
|
609
|
+
**Solution**: Verify the package is installed:
|
|
610
|
+
|
|
611
|
+
```bash
|
|
612
|
+
npm list @crossplane-org/function-sdk-typescript
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
If missing, reinstall:
|
|
616
|
+
|
|
617
|
+
```bash
|
|
618
|
+
npm install @crossplane-org/function-sdk-typescript
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### Port Already in Use (when running functions)
|
|
622
|
+
|
|
623
|
+
**Problem**: `EADDRINUSE` error when starting function server
|
|
624
|
+
|
|
625
|
+
**Solution**: Kill the process using the port:
|
|
626
|
+
|
|
627
|
+
```bash
|
|
628
|
+
# Find and kill process on port 9443
|
|
629
|
+
lsof -ti:9443 | xargs kill -9
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### Protocol Buffer Compilation Errors (for SDK contributors)
|
|
633
|
+
|
|
634
|
+
**Problem**: Errors when running `./scripts/protoc-gen.sh`
|
|
635
|
+
|
|
636
|
+
**Solution**: Ensure Protocol Buffer compiler is installed:
|
|
637
|
+
|
|
638
|
+
```bash
|
|
639
|
+
# Check version
|
|
640
|
+
protoc --version # Should be 3.x or higher
|
|
641
|
+
|
|
642
|
+
# macOS installation
|
|
643
|
+
brew install protobuf
|
|
644
|
+
|
|
645
|
+
# After installing, regenerate
|
|
646
|
+
./scripts/protoc-gen.sh
|
|
647
|
+
npm run build
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
## Contributing
|
|
651
|
+
|
|
652
|
+
Contributions are welcome! Please:
|
|
653
|
+
|
|
654
|
+
1. Fork the repository
|
|
655
|
+
2. Create a feature branch
|
|
656
|
+
3. Make your changes
|
|
657
|
+
4. Add tests if applicable (use `npm test` to run tests)
|
|
658
|
+
5. Ensure all tests pass and the build succeeds (`npm run build`)
|
|
659
|
+
6. Submit a pull request
|
|
660
|
+
|
|
661
|
+
## License
|
|
662
|
+
|
|
663
|
+
Apache 2.0
|
|
664
|
+
|
|
665
|
+
## Resources
|
|
666
|
+
|
|
667
|
+
### Crossplane Documentation
|
|
668
|
+
|
|
669
|
+
- [Crossplane Documentation](https://docs.crossplane.io)
|
|
670
|
+
- [Composition Functions](https://docs.crossplane.io/latest/concepts/composition-functions/)
|
|
671
|
+
- [Write a Composition Function](https://docs.crossplane.io/latest/concepts/composition-functions/#write-a-composition-function)
|
|
672
|
+
- [Composition Function API](https://docs.crossplane.io/latest/concepts/composition-functions/#composition-function-api)
|
|
673
|
+
|
|
674
|
+
### SDK Documentation
|
|
675
|
+
|
|
676
|
+
- [USAGE.md](USAGE.md) - Complete usage guide for this SDK
|
|
677
|
+
|
|
678
|
+
### Related Tools
|
|
679
|
+
|
|
680
|
+
- [ts-proto](https://github.com/stephenh/ts-proto) - TypeScript protobuf code generator
|
|
681
|
+
- [kubernetes-models](https://github.com/tommy351/kubernetes-models-ts) - Type-safe Kubernetes resource models for TypeScript
|
|
682
|
+
- [Pino](https://getpino.io/) - Fast JSON logger
|
|
683
|
+
- [gRPC-js](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) - Pure JavaScript gRPC implementation
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RunFunctionRequest, RunFunctionResponse } from "./proto/run_function.js";
|
|
2
|
+
import type { Logger } from "pino";
|
|
3
|
+
import type { FunctionHandler } from "./function/function.js";
|
|
4
|
+
/**
|
|
5
|
+
* ExampleFunction is a sample implementation showing how to use the SDK
|
|
6
|
+
* This creates a Deployment and Pod as example resources
|
|
7
|
+
*/
|
|
8
|
+
export declare class ExampleFunction implements FunctionHandler {
|
|
9
|
+
RunFunction(req: RunFunctionRequest, logger?: Logger): Promise<RunFunctionResponse>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=example-function.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example-function.d.ts","sourceRoot":"","sources":["../src/example-function.ts"],"names":[],"mappings":"AACA,OAAO,EAEH,kBAAkB,EAClB,mBAAmB,EACtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAanC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;GAGG;AACH,qBAAa,eAAgB,YAAW,eAAe;IAC7C,WAAW,CACb,GAAG,EAAE,kBAAkB,EACvB,MAAM,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,CAAC;CA4FlC"}
|