@astami/temporal-functions 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/README.md +215 -0
- package/dist/client/index.d.mts +34 -0
- package/dist/client/index.d.ts +34 -0
- package/dist/client/index.js +168 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/index.mjs +162 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/index.d.mts +133 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.js +120 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +111 -0
- package/dist/index.mjs.map +1 -0
- package/dist/testing/index.d.mts +74 -0
- package/dist/testing/index.d.ts +74 -0
- package/dist/testing/index.js +129 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/index.mjs +121 -0
- package/dist/testing/index.mjs.map +1 -0
- package/dist/types-C-cNq1Id.d.mts +292 -0
- package/dist/types-C-cNq1Id.d.ts +292 -0
- package/dist/worker/index.d.mts +37 -0
- package/dist/worker/index.d.ts +37 -0
- package/dist/worker/index.js +239 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/index.mjs +233 -0
- package/dist/worker/index.mjs.map +1 -0
- package/package.json +87 -0
package/README.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Temporal Functions
|
|
2
|
+
|
|
3
|
+
A lightweight TypeScript framework that provides a **lambda-like developer experience** on top of **Temporal's durable execution engine**.
|
|
4
|
+
|
|
5
|
+
Write only function bodies and trigger bindings — the framework handles all Temporal boilerplate (workers, activities, workflows, serialization).
|
|
6
|
+
|
|
7
|
+
## Why Temporal Functions?
|
|
8
|
+
|
|
9
|
+
| Aspect | Lambda/Serverless | Raw Temporal | Temporal Functions |
|
|
10
|
+
|--------|-------------------|--------------|-------------------|
|
|
11
|
+
| Function definition | Simple | Verbose | Simple |
|
|
12
|
+
| Durable execution | No | Yes | Yes |
|
|
13
|
+
| Retries/timeouts | Limited | Powerful | Powerful |
|
|
14
|
+
| Worker management | Managed | Manual | Abstracted |
|
|
15
|
+
| Type safety | Varies | Yes | Yes |
|
|
16
|
+
|
|
17
|
+
## Quick Example
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { tfn } from 'temporal-functions';
|
|
21
|
+
|
|
22
|
+
// Define functions (activities)
|
|
23
|
+
export const validateOrder = tfn.fn('validateOrder', async (order: Order) => {
|
|
24
|
+
// validation logic
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const chargePayment = tfn.fn('chargePayment', async (order: ValidatedOrder) => {
|
|
28
|
+
// payment logic
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Define workflow
|
|
32
|
+
export const processOrder = tfn.workflow('processOrder', async (ctx, order: Order) => {
|
|
33
|
+
const validated = await ctx.run(validateOrder, order);
|
|
34
|
+
const paid = await ctx.run(chargePayment, validated);
|
|
35
|
+
return { orderId: paid.id, status: 'complete' };
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**That's it.** No worker setup, no activity proxies, no boilerplate.
|
|
40
|
+
|
|
41
|
+
## Key Principles
|
|
42
|
+
|
|
43
|
+
1. **Lambda-like DX** — Write functions, not infrastructure
|
|
44
|
+
2. **Temporal underneath** — Get durability, retries, exactly-once semantics for free
|
|
45
|
+
3. **TypeScript native** — Full type safety, great IDE support
|
|
46
|
+
4. **Client-Worker separation** — Scale triggers and executors independently
|
|
47
|
+
5. **Minimal abstraction** — Thin layer, not a new platform
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install temporal-functions
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
### Define Functions
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { tfn } from 'temporal-functions';
|
|
61
|
+
|
|
62
|
+
export const sendEmail = tfn.fn(
|
|
63
|
+
'sendEmail',
|
|
64
|
+
async (params: EmailParams): Promise<EmailResult> => {
|
|
65
|
+
return await emailService.send(params);
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
timeout: '30s',
|
|
69
|
+
retries: 3,
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Define Workflows
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
export const processOrder = tfn.workflow(
|
|
78
|
+
'processOrder',
|
|
79
|
+
async (ctx, order: Order) => {
|
|
80
|
+
const validated = await ctx.run(validateOrder, order);
|
|
81
|
+
|
|
82
|
+
// Parallel execution
|
|
83
|
+
const [inventory, pricing] = await Promise.all([
|
|
84
|
+
ctx.run(checkInventory, validated.items),
|
|
85
|
+
ctx.run(calculatePricing, validated.items),
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
// Durable sleep
|
|
89
|
+
await ctx.sleep('5 minutes');
|
|
90
|
+
|
|
91
|
+
const payment = await ctx.run(processPayment, {
|
|
92
|
+
amount: pricing.total,
|
|
93
|
+
orderId: order.id,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return { orderId: order.id, status: 'complete' };
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Client (Trigger Workflows)
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { tfn } from 'temporal-functions/client';
|
|
105
|
+
import { processOrder } from '@myproject/functions';
|
|
106
|
+
|
|
107
|
+
const client = tfn.client({
|
|
108
|
+
temporal: {
|
|
109
|
+
address: 'localhost:7233',
|
|
110
|
+
namespace: 'default',
|
|
111
|
+
},
|
|
112
|
+
taskQueue: 'orders',
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Fire and wait
|
|
116
|
+
const result = await client.invoke(processOrder, order);
|
|
117
|
+
|
|
118
|
+
// Fire and forget
|
|
119
|
+
const handle = await client.start(processOrder, order, {
|
|
120
|
+
workflowId: `order-${order.id}`,
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Worker (Execute Functions)
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { tfn } from 'temporal-functions/worker';
|
|
128
|
+
import { validateOrder, chargePayment, processOrder } from '@myproject/functions';
|
|
129
|
+
|
|
130
|
+
const worker = tfn.worker({
|
|
131
|
+
temporal: {
|
|
132
|
+
address: 'localhost:7233',
|
|
133
|
+
namespace: 'default',
|
|
134
|
+
},
|
|
135
|
+
taskQueue: 'orders',
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
worker.register(validateOrder);
|
|
139
|
+
worker.register(chargePayment);
|
|
140
|
+
worker.register(processOrder);
|
|
141
|
+
|
|
142
|
+
await worker.start();
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Triggers
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// HTTP
|
|
149
|
+
tfn.http('POST', '/api/orders', processOrder);
|
|
150
|
+
|
|
151
|
+
// Cron
|
|
152
|
+
tfn.cron('0 9 * * *', dailyReport);
|
|
153
|
+
|
|
154
|
+
// Signal
|
|
155
|
+
tfn.signal('order.cancel', handleCancellation);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Project Structure
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
my-project/
|
|
162
|
+
├── packages/
|
|
163
|
+
│ ├── functions/ # Shared function definitions
|
|
164
|
+
│ │ └── src/
|
|
165
|
+
│ │ ├── orders/
|
|
166
|
+
│ │ └── notifications/
|
|
167
|
+
│ ├── worker/ # Worker service
|
|
168
|
+
│ │ └── src/index.ts
|
|
169
|
+
│ └── api/ # API/Client service
|
|
170
|
+
│ └── src/index.ts
|
|
171
|
+
└── package.json
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Architecture
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
178
|
+
│ TEMPORAL FUNCTIONS │
|
|
179
|
+
├─────────────────────────────────────────────────────────────┤
|
|
180
|
+
│ │
|
|
181
|
+
│ SHARED: Function Definitions │
|
|
182
|
+
│ tfn.fn() tfn.workflow() Types & Interfaces │
|
|
183
|
+
│ │
|
|
184
|
+
│ │ │ │
|
|
185
|
+
│ ▼ ▼ │
|
|
186
|
+
│ ┌──────────────┐ ┌──────────────┐ │
|
|
187
|
+
│ │ CLIENT │ │ WORKER │ │
|
|
188
|
+
│ │ Lightweight │ │ Full SDK │ │
|
|
189
|
+
│ │ ~20KB │ │ ~2MB │ │
|
|
190
|
+
│ │ │ │ │ │
|
|
191
|
+
│ │ • start() │ │ • register()│ │
|
|
192
|
+
│ │ • invoke() │ │ • start() │ │
|
|
193
|
+
│ │ • signal() │ │ │ │
|
|
194
|
+
│ └──────┬───────┘ └──────┬───────┘ │
|
|
195
|
+
│ │ │ │
|
|
196
|
+
│ └───────────┬───────────────┘ │
|
|
197
|
+
│ ▼ │
|
|
198
|
+
│ ┌─────────────────┐ │
|
|
199
|
+
│ │ TEMPORAL CLUSTER │ │
|
|
200
|
+
│ └─────────────────┘ │
|
|
201
|
+
│ │
|
|
202
|
+
└─────────────────────────────────────────────────────────────┘
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Documentation
|
|
206
|
+
|
|
207
|
+
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full architecture document.
|
|
208
|
+
|
|
209
|
+
## Status
|
|
210
|
+
|
|
211
|
+
**Design Phase** — This project is currently in the design and early implementation phase.
|
|
212
|
+
|
|
213
|
+
## License
|
|
214
|
+
|
|
215
|
+
MIT
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { g as ClientConfig, j as TFNClient } from '../types-C-cNq1Id.mjs';
|
|
2
|
+
export { S as StartWorkflowOptions, i as WorkflowHandle } from '../types-C-cNq1Id.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Temporal Functions - Client Package
|
|
6
|
+
*
|
|
7
|
+
* Lightweight client for triggering workflows.
|
|
8
|
+
* Import from 'temporal-functions/client'.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Create a Temporal Functions client
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { tfn } from 'temporal-functions/client';
|
|
17
|
+
*
|
|
18
|
+
* const client = tfn.client({
|
|
19
|
+
* temporal: {
|
|
20
|
+
* address: 'localhost:7233',
|
|
21
|
+
* namespace: 'default',
|
|
22
|
+
* },
|
|
23
|
+
* taskQueue: 'my-queue',
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* const result = await client.invoke(myWorkflow, { data: 'hello' });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare function createClient(config: ClientConfig): TFNClient;
|
|
30
|
+
declare const tfn: {
|
|
31
|
+
client: typeof createClient;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export { ClientConfig, TFNClient, createClient, tfn as default, tfn };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { g as ClientConfig, j as TFNClient } from '../types-C-cNq1Id.js';
|
|
2
|
+
export { S as StartWorkflowOptions, i as WorkflowHandle } from '../types-C-cNq1Id.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Temporal Functions - Client Package
|
|
6
|
+
*
|
|
7
|
+
* Lightweight client for triggering workflows.
|
|
8
|
+
* Import from 'temporal-functions/client'.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Create a Temporal Functions client
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { tfn } from 'temporal-functions/client';
|
|
17
|
+
*
|
|
18
|
+
* const client = tfn.client({
|
|
19
|
+
* temporal: {
|
|
20
|
+
* address: 'localhost:7233',
|
|
21
|
+
* namespace: 'default',
|
|
22
|
+
* },
|
|
23
|
+
* taskQueue: 'my-queue',
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* const result = await client.invoke(myWorkflow, { data: 'hello' });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare function createClient(config: ClientConfig): TFNClient;
|
|
30
|
+
declare const tfn: {
|
|
31
|
+
client: typeof createClient;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export { ClientConfig, TFNClient, createClient, tfn as default, tfn };
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var client = require('@temporalio/client');
|
|
6
|
+
|
|
7
|
+
// src/client/index.ts
|
|
8
|
+
var TemporalFunctionsClient = class {
|
|
9
|
+
client = null;
|
|
10
|
+
config;
|
|
11
|
+
connectionPromise = null;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = {
|
|
14
|
+
...config,
|
|
15
|
+
temporal: {
|
|
16
|
+
namespace: "default",
|
|
17
|
+
...config.temporal
|
|
18
|
+
},
|
|
19
|
+
taskQueue: config.taskQueue || "default"
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Lazily connect to Temporal
|
|
24
|
+
*/
|
|
25
|
+
async getClient() {
|
|
26
|
+
if (this.client) {
|
|
27
|
+
return this.client;
|
|
28
|
+
}
|
|
29
|
+
if (this.connectionPromise) {
|
|
30
|
+
return this.connectionPromise;
|
|
31
|
+
}
|
|
32
|
+
this.connectionPromise = (async () => {
|
|
33
|
+
const connection = await client.Connection.connect({
|
|
34
|
+
address: this.config.temporal.address,
|
|
35
|
+
tls: this.config.temporal.tls ? {
|
|
36
|
+
clientCertPair: this.config.temporal.tls.clientCertPath ? {
|
|
37
|
+
crt: await import('fs').then(
|
|
38
|
+
(fs) => fs.promises.readFile(this.config.temporal.tls.clientCertPath)
|
|
39
|
+
),
|
|
40
|
+
key: await import('fs').then(
|
|
41
|
+
(fs) => fs.promises.readFile(this.config.temporal.tls.clientKeyPath)
|
|
42
|
+
)
|
|
43
|
+
} : void 0
|
|
44
|
+
} : void 0
|
|
45
|
+
});
|
|
46
|
+
this.client = new client.Client({
|
|
47
|
+
connection,
|
|
48
|
+
namespace: this.config.temporal.namespace
|
|
49
|
+
});
|
|
50
|
+
return this.client;
|
|
51
|
+
})();
|
|
52
|
+
return this.connectionPromise;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Generate a workflow ID if not provided
|
|
56
|
+
*/
|
|
57
|
+
generateWorkflowId(workflowName) {
|
|
58
|
+
const timestamp = Date.now();
|
|
59
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
60
|
+
return `${workflowName}-${timestamp}-${random}`;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Start a workflow and wait for the result
|
|
64
|
+
*/
|
|
65
|
+
async invoke(workflow, input, options = {}) {
|
|
66
|
+
const handle = await this.start(workflow, input, options);
|
|
67
|
+
return handle.result();
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Start a workflow without waiting (fire and forget)
|
|
71
|
+
*/
|
|
72
|
+
async start(workflow, input, options = {}) {
|
|
73
|
+
const client = await this.getClient();
|
|
74
|
+
const workflowId = options.workflowId || this.generateWorkflowId(workflow.name);
|
|
75
|
+
const taskQueue = options.taskQueue || workflow.options.taskQueue || this.config.taskQueue || "default";
|
|
76
|
+
const handle = await client.workflow.start(workflow.name, {
|
|
77
|
+
workflowId,
|
|
78
|
+
taskQueue,
|
|
79
|
+
args: [input],
|
|
80
|
+
workflowExecutionTimeout: options.workflowExecutionTimeout,
|
|
81
|
+
memo: options.memo
|
|
82
|
+
// searchAttributes requires specific types, omit for now if not properly typed
|
|
83
|
+
});
|
|
84
|
+
return this.wrapHandle(handle);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get a handle to an existing workflow
|
|
88
|
+
*/
|
|
89
|
+
getHandle(workflowId) {
|
|
90
|
+
return {
|
|
91
|
+
workflowId,
|
|
92
|
+
runId: "",
|
|
93
|
+
// Will be populated when we fetch
|
|
94
|
+
result: async () => {
|
|
95
|
+
const client = await this.getClient();
|
|
96
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
97
|
+
return handle.result();
|
|
98
|
+
},
|
|
99
|
+
query: async (queryName) => {
|
|
100
|
+
const client = await this.getClient();
|
|
101
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
102
|
+
return handle.query(queryName);
|
|
103
|
+
},
|
|
104
|
+
signal: async (signalName, payload) => {
|
|
105
|
+
const client = await this.getClient();
|
|
106
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
107
|
+
await handle.signal(signalName, payload);
|
|
108
|
+
},
|
|
109
|
+
cancel: async () => {
|
|
110
|
+
const client = await this.getClient();
|
|
111
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
112
|
+
await handle.cancel();
|
|
113
|
+
},
|
|
114
|
+
terminate: async (reason) => {
|
|
115
|
+
const client = await this.getClient();
|
|
116
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
117
|
+
await handle.terminate(reason);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Signal an existing workflow
|
|
123
|
+
*/
|
|
124
|
+
async signal(workflowId, signalName, payload) {
|
|
125
|
+
const client = await this.getClient();
|
|
126
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
127
|
+
await handle.signal(signalName, payload);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Query an existing workflow
|
|
131
|
+
*/
|
|
132
|
+
async query(workflowId, queryName) {
|
|
133
|
+
const client = await this.getClient();
|
|
134
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
135
|
+
return handle.query(queryName);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Wrap a Temporal workflow handle in our interface
|
|
139
|
+
*/
|
|
140
|
+
wrapHandle(handle) {
|
|
141
|
+
return {
|
|
142
|
+
workflowId: handle.workflowId,
|
|
143
|
+
runId: handle.firstExecutionRunId,
|
|
144
|
+
result: () => handle.result(),
|
|
145
|
+
query: (queryName) => handle.query(queryName),
|
|
146
|
+
signal: (signalName, payload) => handle.signal(signalName, payload),
|
|
147
|
+
cancel: async () => {
|
|
148
|
+
await handle.cancel();
|
|
149
|
+
},
|
|
150
|
+
terminate: async (reason) => {
|
|
151
|
+
await handle.terminate(reason);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
function createClient(config) {
|
|
157
|
+
return new TemporalFunctionsClient(config);
|
|
158
|
+
}
|
|
159
|
+
var tfn = {
|
|
160
|
+
client: createClient
|
|
161
|
+
};
|
|
162
|
+
var client_default = tfn;
|
|
163
|
+
|
|
164
|
+
exports.createClient = createClient;
|
|
165
|
+
exports.default = client_default;
|
|
166
|
+
exports.tfn = tfn;
|
|
167
|
+
//# sourceMappingURL=index.js.map
|
|
168
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/client/index.ts"],"names":["Connection","Client"],"mappings":";;;;;;;AAoBA,IAAM,0BAAN,MAAmD;AAAA,EACzC,MAAA,GAAwB,IAAA;AAAA,EACxB,MAAA;AAAA,EACA,iBAAA,GAA4C,IAAA;AAAA,EAEpD,YAAY,MAAA,EAAsB;AAChC,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,GAAG,MAAA;AAAA,MACH,QAAA,EAAU;AAAA,QACR,SAAA,EAAW,SAAA;AAAA,QACX,GAAG,MAAA,CAAO;AAAA,OACZ;AAAA,MACA,SAAA,EAAW,OAAO,SAAA,IAAa;AAAA,KACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,SAAA,GAA6B;AACzC,IAAA,IAAI,KAAK,MAAA,EAAQ;AACf,MAAA,OAAO,IAAA,CAAK,MAAA;AAAA,IACd;AAEA,IAAA,IAAI,KAAK,iBAAA,EAAmB;AAC1B,MAAA,OAAO,IAAA,CAAK,iBAAA;AAAA,IACd;AAEA,IAAA,IAAA,CAAK,qBAAqB,YAAY;AACpC,MAAA,MAAM,UAAA,GAAa,MAAMA,iBAAA,CAAW,OAAA,CAAQ;AAAA,QAC1C,OAAA,EAAS,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,OAAA;AAAA,QAC9B,GAAA,EAAK,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,GAAA,GACtB;AAAA,UACE,cAAA,EAAgB,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,IAAI,cAAA,GACrC;AAAA,YACE,GAAA,EAAK,MAAM,OAAO,IAAI,CAAA,CAAE,IAAA;AAAA,cAAK,CAAC,OAC5B,EAAA,CAAG,QAAA,CAAS,SAAS,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,GAAA,CAAK,cAAe;AAAA,aAChE;AAAA,YACA,GAAA,EAAK,MAAM,OAAO,IAAI,CAAA,CAAE,IAAA;AAAA,cAAK,CAAC,OAC5B,EAAA,CAAG,QAAA,CAAS,SAAS,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,GAAA,CAAK,aAAc;AAAA;AAC/D,WACF,GACA;AAAA,SACN,GACA;AAAA,OACL,CAAA;AAED,MAAA,IAAA,CAAK,MAAA,GAAS,IAAIC,aAAA,CAAO;AAAA,QACvB,UAAA;AAAA,QACA,SAAA,EAAW,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS;AAAA,OACjC,CAAA;AAED,MAAA,OAAO,IAAA,CAAK,MAAA;AAAA,IACd,CAAA,GAAG;AAEH,IAAA,OAAO,IAAA,CAAK,iBAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,YAAA,EAA8B;AACvD,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,IAAA,MAAM,MAAA,GAAS,KAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,SAAA,CAAU,CAAA,EAAG,CAAC,CAAA;AACxD,IAAA,OAAO,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,SAAS,IAAI,MAAM,CAAA,CAAA;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAA,CACJ,QAAA,EACA,KAAA,EACA,OAAA,GAAgC,EAAC,EACf;AAClB,IAAA,MAAM,SAAS,MAAM,IAAA,CAAK,KAAA,CAAM,QAAA,EAAU,OAAO,OAAO,CAAA;AACxD,IAAA,OAAO,OAAO,MAAA,EAAO;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAA,CACJ,QAAA,EACA,KAAA,EACA,OAAA,GAAgC,EAAC,EACC;AAClC,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,EAAU;AAEpC,IAAA,MAAM,aAAa,OAAA,CAAQ,UAAA,IAAc,IAAA,CAAK,kBAAA,CAAmB,SAAS,IAAI,CAAA;AAC9E,IAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,QAAA,CAAS,QAAQ,SAAA,IAAa,IAAA,CAAK,OAAO,SAAA,IAAa,SAAA;AAE9F,IAAA,MAAM,SAAS,MAAM,MAAA,CAAO,QAAA,CAAS,KAAA,CAAM,SAAS,IAAA,EAAM;AAAA,MACxD,UAAA;AAAA,MACA,SAAA;AAAA,MACA,IAAA,EAAM,CAAC,KAAK,CAAA;AAAA,MACZ,0BAA0B,OAAA,CAAQ,wBAAA;AAAA,MAClC,MAAM,OAAA,CAAQ;AAAA;AAAA,KAEf,CAAA;AAED,IAAA,OAAO,IAAA,CAAK,WAAoB,MAAM,CAAA;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKA,UAA6B,UAAA,EAA6C;AAExE,IAAA,OAAO;AAAA,MACL,UAAA;AAAA,MACA,KAAA,EAAO,EAAA;AAAA;AAAA,MACP,QAAQ,YAAY;AAClB,QAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,EAAU;AACpC,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,SAAA,CAAU,UAAU,CAAA;AACnD,QAAA,OAAO,OAAO,MAAA,EAAO;AAAA,MACvB,CAAA;AAAA,MACA,KAAA,EAAO,OAA0B,SAAA,KAAsB;AACrD,QAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,EAAU;AACpC,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,SAAA,CAAU,UAAU,CAAA;AACnD,QAAA,OAAO,MAAA,CAAO,MAAe,SAAS,CAAA;AAAA,MACxC,CAAA;AAAA,MACA,MAAA,EAAQ,OAA2B,UAAA,EAAoB,OAAA,KAAsB;AAC3E,QAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,EAAU;AACpC,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,SAAA,CAAU,UAAU,CAAA;AACnD,QAAA,MAAM,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,OAAO,CAAA;AAAA,MACzC,CAAA;AAAA,MACA,QAAQ,YAAY;AAClB,QAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,EAAU;AACpC,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,SAAA,CAAU,UAAU,CAAA;AACnD,QAAA,MAAM,OAAO,MAAA,EAAO;AAAA,MACtB,CAAA;AAAA,MACA,SAAA,EAAW,OAAO,MAAA,KAAoB;AACpC,QAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,EAAU;AACpC,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,SAAA,CAAU,UAAU,CAAA;AACnD,QAAA,MAAM,MAAA,CAAO,UAAU,MAAM,CAAA;AAAA,MAC/B;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAA,CACJ,UAAA,EACA,UAAA,EACA,OAAA,EACe;AACf,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,EAAU;AACpC,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,SAAA,CAAU,UAAU,CAAA;AACnD,IAAA,MAAM,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,OAAO,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAA,CACJ,UAAA,EACA,SAAA,EACkB;AAClB,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,EAAU;AACpC,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,SAAA,CAAU,UAAU,CAAA;AACnD,IAAA,OAAO,MAAA,CAAO,MAAe,SAAS,CAAA;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAKQ,WACN,MAAA,EACyB;AACzB,IAAA,OAAO;AAAA,MACL,YAAY,MAAA,CAAO,UAAA;AAAA,MACnB,OAAO,MAAA,CAAO,mBAAA;AAAA,MACd,MAAA,EAAQ,MAAM,MAAA,CAAO,MAAA,EAAO;AAAA,MAC5B,KAAA,EAAO,CAAoB,SAAA,KACzB,MAAA,CAAO,MAAe,SAAS,CAAA;AAAA,MACjC,QAAQ,CAAqB,UAAA,EAAoB,YAC/C,MAAA,CAAO,MAAA,CAAO,YAAY,OAAO,CAAA;AAAA,MACnC,QAAQ,YAAY;AAClB,QAAA,MAAM,OAAO,MAAA,EAAO;AAAA,MACtB,CAAA;AAAA,MACA,SAAA,EAAW,OAAO,MAAA,KAAoB;AACpC,QAAA,MAAM,MAAA,CAAO,UAAU,MAAM,CAAA;AAAA,MAC/B;AAAA,KACF;AAAA,EACF;AACF,CAAA;AAwBA,SAAS,aAAa,MAAA,EAAiC;AACrD,EAAA,OAAO,IAAI,wBAAwB,MAAM,CAAA;AAC3C;AAMO,IAAM,GAAA,GAAM;AAAA,EACjB,MAAA,EAAQ;AACV;AAIA,IAAO,cAAA,GAAQ","file":"index.js","sourcesContent":["/**\n * Temporal Functions - Client Package\n *\n * Lightweight client for triggering workflows.\n * Import from 'temporal-functions/client'.\n */\n\nimport { Client, Connection } from '@temporalio/client';\nimport type {\n ClientConfig,\n WorkflowDef,\n StartWorkflowOptions,\n WorkflowHandle,\n TFNClient,\n} from '../types.js';\n\n// =============================================================================\n// Client Implementation\n// =============================================================================\n\nclass TemporalFunctionsClient implements TFNClient {\n private client: Client | null = null;\n private config: ClientConfig;\n private connectionPromise: Promise<Client> | null = null;\n\n constructor(config: ClientConfig) {\n this.config = {\n ...config,\n temporal: {\n namespace: 'default',\n ...config.temporal,\n },\n taskQueue: config.taskQueue || 'default',\n };\n }\n\n /**\n * Lazily connect to Temporal\n */\n private async getClient(): Promise<Client> {\n if (this.client) {\n return this.client;\n }\n\n if (this.connectionPromise) {\n return this.connectionPromise;\n }\n\n this.connectionPromise = (async () => {\n const connection = await Connection.connect({\n address: this.config.temporal.address,\n tls: this.config.temporal.tls\n ? {\n clientCertPair: this.config.temporal.tls.clientCertPath\n ? {\n crt: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientCertPath!)\n ),\n key: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientKeyPath!)\n ),\n }\n : undefined,\n }\n : undefined,\n });\n\n this.client = new Client({\n connection,\n namespace: this.config.temporal.namespace,\n });\n\n return this.client;\n })();\n\n return this.connectionPromise;\n }\n\n /**\n * Generate a workflow ID if not provided\n */\n private generateWorkflowId(workflowName: string): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 8);\n return `${workflowName}-${timestamp}-${random}`;\n }\n\n /**\n * Start a workflow and wait for the result\n */\n async invoke<TInput, TOutput>(\n workflow: WorkflowDef<TInput, TOutput>,\n input: TInput,\n options: StartWorkflowOptions = {}\n ): Promise<TOutput> {\n const handle = await this.start(workflow, input, options);\n return handle.result();\n }\n\n /**\n * Start a workflow without waiting (fire and forget)\n */\n async start<TInput, TOutput>(\n workflow: WorkflowDef<TInput, TOutput>,\n input: TInput,\n options: StartWorkflowOptions = {}\n ): Promise<WorkflowHandle<TOutput>> {\n const client = await this.getClient();\n\n const workflowId = options.workflowId || this.generateWorkflowId(workflow.name);\n const taskQueue = options.taskQueue || workflow.options.taskQueue || this.config.taskQueue || 'default';\n\n const handle = await client.workflow.start(workflow.name, {\n workflowId,\n taskQueue,\n args: [input],\n workflowExecutionTimeout: options.workflowExecutionTimeout,\n memo: options.memo,\n // searchAttributes requires specific types, omit for now if not properly typed\n });\n\n return this.wrapHandle<TOutput>(handle);\n }\n\n /**\n * Get a handle to an existing workflow\n */\n getHandle<TOutput = unknown>(workflowId: string): WorkflowHandle<TOutput> {\n // Create a lazy handle that connects when needed\n return {\n workflowId,\n runId: '', // Will be populated when we fetch\n result: async () => {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n return handle.result() as Promise<TOutput>;\n },\n query: async <TResult = unknown>(queryName: string) => {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n return handle.query<TResult>(queryName);\n },\n signal: async <TPayload = unknown>(signalName: string, payload: TPayload) => {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n await handle.signal(signalName, payload);\n },\n cancel: async () => {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n await handle.cancel();\n },\n terminate: async (reason?: string) => {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n await handle.terminate(reason);\n },\n };\n }\n\n /**\n * Signal an existing workflow\n */\n async signal<TPayload = unknown>(\n workflowId: string,\n signalName: string,\n payload: TPayload\n ): Promise<void> {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n await handle.signal(signalName, payload);\n }\n\n /**\n * Query an existing workflow\n */\n async query<TResult = unknown>(\n workflowId: string,\n queryName: string\n ): Promise<TResult> {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n return handle.query<TResult>(queryName);\n }\n\n /**\n * Wrap a Temporal workflow handle in our interface\n */\n private wrapHandle<TOutput>(\n handle: Awaited<ReturnType<Client['workflow']['start']>>\n ): WorkflowHandle<TOutput> {\n return {\n workflowId: handle.workflowId,\n runId: handle.firstExecutionRunId,\n result: () => handle.result() as Promise<TOutput>,\n query: <TResult = unknown>(queryName: string) =>\n handle.query<TResult>(queryName),\n signal: <TPayload = unknown>(signalName: string, payload: TPayload) =>\n handle.signal(signalName, payload),\n cancel: async () => {\n await handle.cancel();\n },\n terminate: async (reason?: string) => {\n await handle.terminate(reason);\n },\n };\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create a Temporal Functions client\n *\n * @example\n * ```typescript\n * import { tfn } from 'temporal-functions/client';\n *\n * const client = tfn.client({\n * temporal: {\n * address: 'localhost:7233',\n * namespace: 'default',\n * },\n * taskQueue: 'my-queue',\n * });\n *\n * const result = await client.invoke(myWorkflow, { data: 'hello' });\n * ```\n */\nfunction createClient(config: ClientConfig): TFNClient {\n return new TemporalFunctionsClient(config);\n}\n\n// =============================================================================\n// Export\n// =============================================================================\n\nexport const tfn = {\n client: createClient,\n};\n\nexport { createClient };\nexport type { ClientConfig, TFNClient, WorkflowHandle, StartWorkflowOptions };\nexport default tfn;\n"]}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { Connection, Client } from '@temporalio/client';
|
|
2
|
+
|
|
3
|
+
// src/client/index.ts
|
|
4
|
+
var TemporalFunctionsClient = class {
|
|
5
|
+
client = null;
|
|
6
|
+
config;
|
|
7
|
+
connectionPromise = null;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.config = {
|
|
10
|
+
...config,
|
|
11
|
+
temporal: {
|
|
12
|
+
namespace: "default",
|
|
13
|
+
...config.temporal
|
|
14
|
+
},
|
|
15
|
+
taskQueue: config.taskQueue || "default"
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Lazily connect to Temporal
|
|
20
|
+
*/
|
|
21
|
+
async getClient() {
|
|
22
|
+
if (this.client) {
|
|
23
|
+
return this.client;
|
|
24
|
+
}
|
|
25
|
+
if (this.connectionPromise) {
|
|
26
|
+
return this.connectionPromise;
|
|
27
|
+
}
|
|
28
|
+
this.connectionPromise = (async () => {
|
|
29
|
+
const connection = await Connection.connect({
|
|
30
|
+
address: this.config.temporal.address,
|
|
31
|
+
tls: this.config.temporal.tls ? {
|
|
32
|
+
clientCertPair: this.config.temporal.tls.clientCertPath ? {
|
|
33
|
+
crt: await import('fs').then(
|
|
34
|
+
(fs) => fs.promises.readFile(this.config.temporal.tls.clientCertPath)
|
|
35
|
+
),
|
|
36
|
+
key: await import('fs').then(
|
|
37
|
+
(fs) => fs.promises.readFile(this.config.temporal.tls.clientKeyPath)
|
|
38
|
+
)
|
|
39
|
+
} : void 0
|
|
40
|
+
} : void 0
|
|
41
|
+
});
|
|
42
|
+
this.client = new Client({
|
|
43
|
+
connection,
|
|
44
|
+
namespace: this.config.temporal.namespace
|
|
45
|
+
});
|
|
46
|
+
return this.client;
|
|
47
|
+
})();
|
|
48
|
+
return this.connectionPromise;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Generate a workflow ID if not provided
|
|
52
|
+
*/
|
|
53
|
+
generateWorkflowId(workflowName) {
|
|
54
|
+
const timestamp = Date.now();
|
|
55
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
56
|
+
return `${workflowName}-${timestamp}-${random}`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Start a workflow and wait for the result
|
|
60
|
+
*/
|
|
61
|
+
async invoke(workflow, input, options = {}) {
|
|
62
|
+
const handle = await this.start(workflow, input, options);
|
|
63
|
+
return handle.result();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Start a workflow without waiting (fire and forget)
|
|
67
|
+
*/
|
|
68
|
+
async start(workflow, input, options = {}) {
|
|
69
|
+
const client = await this.getClient();
|
|
70
|
+
const workflowId = options.workflowId || this.generateWorkflowId(workflow.name);
|
|
71
|
+
const taskQueue = options.taskQueue || workflow.options.taskQueue || this.config.taskQueue || "default";
|
|
72
|
+
const handle = await client.workflow.start(workflow.name, {
|
|
73
|
+
workflowId,
|
|
74
|
+
taskQueue,
|
|
75
|
+
args: [input],
|
|
76
|
+
workflowExecutionTimeout: options.workflowExecutionTimeout,
|
|
77
|
+
memo: options.memo
|
|
78
|
+
// searchAttributes requires specific types, omit for now if not properly typed
|
|
79
|
+
});
|
|
80
|
+
return this.wrapHandle(handle);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get a handle to an existing workflow
|
|
84
|
+
*/
|
|
85
|
+
getHandle(workflowId) {
|
|
86
|
+
return {
|
|
87
|
+
workflowId,
|
|
88
|
+
runId: "",
|
|
89
|
+
// Will be populated when we fetch
|
|
90
|
+
result: async () => {
|
|
91
|
+
const client = await this.getClient();
|
|
92
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
93
|
+
return handle.result();
|
|
94
|
+
},
|
|
95
|
+
query: async (queryName) => {
|
|
96
|
+
const client = await this.getClient();
|
|
97
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
98
|
+
return handle.query(queryName);
|
|
99
|
+
},
|
|
100
|
+
signal: async (signalName, payload) => {
|
|
101
|
+
const client = await this.getClient();
|
|
102
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
103
|
+
await handle.signal(signalName, payload);
|
|
104
|
+
},
|
|
105
|
+
cancel: async () => {
|
|
106
|
+
const client = await this.getClient();
|
|
107
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
108
|
+
await handle.cancel();
|
|
109
|
+
},
|
|
110
|
+
terminate: async (reason) => {
|
|
111
|
+
const client = await this.getClient();
|
|
112
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
113
|
+
await handle.terminate(reason);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Signal an existing workflow
|
|
119
|
+
*/
|
|
120
|
+
async signal(workflowId, signalName, payload) {
|
|
121
|
+
const client = await this.getClient();
|
|
122
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
123
|
+
await handle.signal(signalName, payload);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Query an existing workflow
|
|
127
|
+
*/
|
|
128
|
+
async query(workflowId, queryName) {
|
|
129
|
+
const client = await this.getClient();
|
|
130
|
+
const handle = client.workflow.getHandle(workflowId);
|
|
131
|
+
return handle.query(queryName);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Wrap a Temporal workflow handle in our interface
|
|
135
|
+
*/
|
|
136
|
+
wrapHandle(handle) {
|
|
137
|
+
return {
|
|
138
|
+
workflowId: handle.workflowId,
|
|
139
|
+
runId: handle.firstExecutionRunId,
|
|
140
|
+
result: () => handle.result(),
|
|
141
|
+
query: (queryName) => handle.query(queryName),
|
|
142
|
+
signal: (signalName, payload) => handle.signal(signalName, payload),
|
|
143
|
+
cancel: async () => {
|
|
144
|
+
await handle.cancel();
|
|
145
|
+
},
|
|
146
|
+
terminate: async (reason) => {
|
|
147
|
+
await handle.terminate(reason);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
function createClient(config) {
|
|
153
|
+
return new TemporalFunctionsClient(config);
|
|
154
|
+
}
|
|
155
|
+
var tfn = {
|
|
156
|
+
client: createClient
|
|
157
|
+
};
|
|
158
|
+
var client_default = tfn;
|
|
159
|
+
|
|
160
|
+
export { createClient, client_default as default, tfn };
|
|
161
|
+
//# sourceMappingURL=index.mjs.map
|
|
162
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/client/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Temporal Functions - Client Package\n *\n * Lightweight client for triggering workflows.\n * Import from 'temporal-functions/client'.\n */\n\nimport { Client, Connection } from '@temporalio/client';\nimport type {\n ClientConfig,\n WorkflowDef,\n StartWorkflowOptions,\n WorkflowHandle,\n TFNClient,\n} from '../types.js';\n\n// =============================================================================\n// Client Implementation\n// =============================================================================\n\nclass TemporalFunctionsClient implements TFNClient {\n private client: Client | null = null;\n private config: ClientConfig;\n private connectionPromise: Promise<Client> | null = null;\n\n constructor(config: ClientConfig) {\n this.config = {\n ...config,\n temporal: {\n namespace: 'default',\n ...config.temporal,\n },\n taskQueue: config.taskQueue || 'default',\n };\n }\n\n /**\n * Lazily connect to Temporal\n */\n private async getClient(): Promise<Client> {\n if (this.client) {\n return this.client;\n }\n\n if (this.connectionPromise) {\n return this.connectionPromise;\n }\n\n this.connectionPromise = (async () => {\n const connection = await Connection.connect({\n address: this.config.temporal.address,\n tls: this.config.temporal.tls\n ? {\n clientCertPair: this.config.temporal.tls.clientCertPath\n ? {\n crt: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientCertPath!)\n ),\n key: await import('fs').then((fs) =>\n fs.promises.readFile(this.config.temporal.tls!.clientKeyPath!)\n ),\n }\n : undefined,\n }\n : undefined,\n });\n\n this.client = new Client({\n connection,\n namespace: this.config.temporal.namespace,\n });\n\n return this.client;\n })();\n\n return this.connectionPromise;\n }\n\n /**\n * Generate a workflow ID if not provided\n */\n private generateWorkflowId(workflowName: string): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 8);\n return `${workflowName}-${timestamp}-${random}`;\n }\n\n /**\n * Start a workflow and wait for the result\n */\n async invoke<TInput, TOutput>(\n workflow: WorkflowDef<TInput, TOutput>,\n input: TInput,\n options: StartWorkflowOptions = {}\n ): Promise<TOutput> {\n const handle = await this.start(workflow, input, options);\n return handle.result();\n }\n\n /**\n * Start a workflow without waiting (fire and forget)\n */\n async start<TInput, TOutput>(\n workflow: WorkflowDef<TInput, TOutput>,\n input: TInput,\n options: StartWorkflowOptions = {}\n ): Promise<WorkflowHandle<TOutput>> {\n const client = await this.getClient();\n\n const workflowId = options.workflowId || this.generateWorkflowId(workflow.name);\n const taskQueue = options.taskQueue || workflow.options.taskQueue || this.config.taskQueue || 'default';\n\n const handle = await client.workflow.start(workflow.name, {\n workflowId,\n taskQueue,\n args: [input],\n workflowExecutionTimeout: options.workflowExecutionTimeout,\n memo: options.memo,\n // searchAttributes requires specific types, omit for now if not properly typed\n });\n\n return this.wrapHandle<TOutput>(handle);\n }\n\n /**\n * Get a handle to an existing workflow\n */\n getHandle<TOutput = unknown>(workflowId: string): WorkflowHandle<TOutput> {\n // Create a lazy handle that connects when needed\n return {\n workflowId,\n runId: '', // Will be populated when we fetch\n result: async () => {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n return handle.result() as Promise<TOutput>;\n },\n query: async <TResult = unknown>(queryName: string) => {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n return handle.query<TResult>(queryName);\n },\n signal: async <TPayload = unknown>(signalName: string, payload: TPayload) => {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n await handle.signal(signalName, payload);\n },\n cancel: async () => {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n await handle.cancel();\n },\n terminate: async (reason?: string) => {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n await handle.terminate(reason);\n },\n };\n }\n\n /**\n * Signal an existing workflow\n */\n async signal<TPayload = unknown>(\n workflowId: string,\n signalName: string,\n payload: TPayload\n ): Promise<void> {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n await handle.signal(signalName, payload);\n }\n\n /**\n * Query an existing workflow\n */\n async query<TResult = unknown>(\n workflowId: string,\n queryName: string\n ): Promise<TResult> {\n const client = await this.getClient();\n const handle = client.workflow.getHandle(workflowId);\n return handle.query<TResult>(queryName);\n }\n\n /**\n * Wrap a Temporal workflow handle in our interface\n */\n private wrapHandle<TOutput>(\n handle: Awaited<ReturnType<Client['workflow']['start']>>\n ): WorkflowHandle<TOutput> {\n return {\n workflowId: handle.workflowId,\n runId: handle.firstExecutionRunId,\n result: () => handle.result() as Promise<TOutput>,\n query: <TResult = unknown>(queryName: string) =>\n handle.query<TResult>(queryName),\n signal: <TPayload = unknown>(signalName: string, payload: TPayload) =>\n handle.signal(signalName, payload),\n cancel: async () => {\n await handle.cancel();\n },\n terminate: async (reason?: string) => {\n await handle.terminate(reason);\n },\n };\n }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create a Temporal Functions client\n *\n * @example\n * ```typescript\n * import { tfn } from 'temporal-functions/client';\n *\n * const client = tfn.client({\n * temporal: {\n * address: 'localhost:7233',\n * namespace: 'default',\n * },\n * taskQueue: 'my-queue',\n * });\n *\n * const result = await client.invoke(myWorkflow, { data: 'hello' });\n * ```\n */\nfunction createClient(config: ClientConfig): TFNClient {\n return new TemporalFunctionsClient(config);\n}\n\n// =============================================================================\n// Export\n// =============================================================================\n\nexport const tfn = {\n client: createClient,\n};\n\nexport { createClient };\nexport type { ClientConfig, TFNClient, WorkflowHandle, StartWorkflowOptions };\nexport default tfn;\n"]}
|