services-as-software 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 +303 -0
- package/dist/index.d.ts +216 -0
- package/dist/index.js +172 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# services-as-software
|
|
2
|
+
|
|
3
|
+
Define services with objectives, key results, and various pricing models for the agentic services architecture.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install services-as-software
|
|
9
|
+
# or
|
|
10
|
+
yarn add services-as-software
|
|
11
|
+
# or
|
|
12
|
+
pnpm add services-as-software
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
The `services-as-software` package enables defining services with clear objectives, measurable key results, and support for multiple pricing models. It allows Functions, Workflows, and Agents to be offered as Services with appropriate pricing and business models.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Basic Service Definition
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { Service } from 'services-as-software'
|
|
25
|
+
|
|
26
|
+
const myService = Service({
|
|
27
|
+
name: 'Content Generation Service',
|
|
28
|
+
description: 'AI-powered content generation for marketing teams',
|
|
29
|
+
objective: {
|
|
30
|
+
description: 'Provide high-quality content generation that increases marketing efficiency',
|
|
31
|
+
keyResults: [],
|
|
32
|
+
},
|
|
33
|
+
keyResults: [
|
|
34
|
+
{
|
|
35
|
+
description: 'Reduce content creation time',
|
|
36
|
+
target: 50,
|
|
37
|
+
currentValue: 0,
|
|
38
|
+
unit: 'percent',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
description: 'Maintain content quality score',
|
|
42
|
+
target: 8,
|
|
43
|
+
currentValue: 0,
|
|
44
|
+
unit: 'rating',
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
pricing: {
|
|
48
|
+
model: 'cost-based',
|
|
49
|
+
costBase: 10,
|
|
50
|
+
fixedCosts: 5,
|
|
51
|
+
variableCosts: 2,
|
|
52
|
+
},
|
|
53
|
+
implementation: {
|
|
54
|
+
type: 'function',
|
|
55
|
+
id: 'content-generator-123',
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
// Register the service
|
|
60
|
+
const registeredService = await myService.register()
|
|
61
|
+
|
|
62
|
+
// Calculate price
|
|
63
|
+
const price = myService.calculatePrice({ quantity: 5 })
|
|
64
|
+
|
|
65
|
+
// Track progress towards key results
|
|
66
|
+
myService.trackProgress({
|
|
67
|
+
'Reduce content creation time': 30,
|
|
68
|
+
'Maintain content quality score': 9,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
// Check if objective is achieved
|
|
72
|
+
const achieved = myService.isObjectiveAchieved()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Pricing Models
|
|
76
|
+
|
|
77
|
+
The package supports four pricing models:
|
|
78
|
+
|
|
79
|
+
#### 1. Cost-based Pricing
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const service = Service({
|
|
83
|
+
// ...other properties
|
|
84
|
+
pricing: {
|
|
85
|
+
model: 'cost-based',
|
|
86
|
+
costBase: 100,
|
|
87
|
+
fixedCosts: 50,
|
|
88
|
+
variableCosts: 10,
|
|
89
|
+
},
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
// Calculate price for 5 units
|
|
93
|
+
const price = service.calculatePrice({ quantity: 5 }) // 200 (100 + 50 + 10*5)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### 2. Margin-based Pricing
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
const service = Service({
|
|
100
|
+
// ...other properties
|
|
101
|
+
pricing: {
|
|
102
|
+
model: 'margin-based',
|
|
103
|
+
costBase: 100,
|
|
104
|
+
marginPercentage: 20,
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
// Calculate price for 2 units
|
|
109
|
+
const price = service.calculatePrice({ quantity: 2 }) // 240 (100*2 + 20% margin)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### 3. Activity-based Pricing
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const service = Service({
|
|
116
|
+
// ...other properties
|
|
117
|
+
pricing: {
|
|
118
|
+
model: 'activity-based',
|
|
119
|
+
activities: [
|
|
120
|
+
{ name: 'research', rate: 50 },
|
|
121
|
+
{ name: 'writing', rate: 100 },
|
|
122
|
+
{ name: 'editing', rate: 30 },
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
// Calculate price based on activities performed
|
|
128
|
+
const price = service.calculatePrice({
|
|
129
|
+
activities: {
|
|
130
|
+
research: 2,
|
|
131
|
+
writing: 1,
|
|
132
|
+
editing: 3,
|
|
133
|
+
},
|
|
134
|
+
}) // 290 (50*2 + 100*1 + 30*3)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### 4. Outcome-based Pricing
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
const service = Service({
|
|
141
|
+
// ...other properties
|
|
142
|
+
pricing: {
|
|
143
|
+
model: 'outcome-based',
|
|
144
|
+
outcomes: [
|
|
145
|
+
{ metric: 'conversion-rate', targetValue: 5, price: 500 },
|
|
146
|
+
{ metric: 'engagement', targetValue: 10000, price: 300 },
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// Calculate price based on achieved outcomes
|
|
152
|
+
const price = service.calculatePrice({
|
|
153
|
+
outcomes: {
|
|
154
|
+
'conversion-rate': 6.5,
|
|
155
|
+
engagement: 8000,
|
|
156
|
+
},
|
|
157
|
+
}) // 500 (only conversion-rate target was met)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Offering Functions as Services
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { Service } from 'services-as-software'
|
|
164
|
+
|
|
165
|
+
const functionAsService = Service({
|
|
166
|
+
name: 'Text Summarization',
|
|
167
|
+
objective: {
|
|
168
|
+
description: 'Provide accurate text summarization',
|
|
169
|
+
keyResults: [],
|
|
170
|
+
},
|
|
171
|
+
keyResults: [
|
|
172
|
+
{
|
|
173
|
+
description: 'Summarization accuracy',
|
|
174
|
+
target: 90,
|
|
175
|
+
unit: 'percent',
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
pricing: {
|
|
179
|
+
model: 'cost-based',
|
|
180
|
+
costBase: 5,
|
|
181
|
+
variableCosts: 0.01,
|
|
182
|
+
},
|
|
183
|
+
implementation: {
|
|
184
|
+
type: 'function',
|
|
185
|
+
id: 'text-summarizer-function',
|
|
186
|
+
},
|
|
187
|
+
})
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Offering Workflows as Services
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
import { Service } from 'services-as-software'
|
|
194
|
+
|
|
195
|
+
const workflowAsService = Service({
|
|
196
|
+
name: 'Content Production Pipeline',
|
|
197
|
+
objective: {
|
|
198
|
+
description: 'End-to-end content production',
|
|
199
|
+
keyResults: [],
|
|
200
|
+
},
|
|
201
|
+
keyResults: [
|
|
202
|
+
{
|
|
203
|
+
description: 'Average production time',
|
|
204
|
+
target: 24,
|
|
205
|
+
unit: 'hours',
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
pricing: {
|
|
209
|
+
model: 'activity-based',
|
|
210
|
+
activities: [
|
|
211
|
+
{ name: 'research', rate: 100 },
|
|
212
|
+
{ name: 'writing', rate: 200 },
|
|
213
|
+
{ name: 'editing', rate: 50 },
|
|
214
|
+
{ name: 'publishing', rate: 30 },
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
implementation: {
|
|
218
|
+
type: 'workflow',
|
|
219
|
+
id: 'content-production-workflow',
|
|
220
|
+
},
|
|
221
|
+
})
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Offering Agents as Services
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import { Service } from 'services-as-software'
|
|
228
|
+
|
|
229
|
+
const agentAsService = Service({
|
|
230
|
+
name: 'Customer Support Agent',
|
|
231
|
+
objective: {
|
|
232
|
+
description: 'Provide excellent customer support',
|
|
233
|
+
keyResults: [],
|
|
234
|
+
},
|
|
235
|
+
keyResults: [
|
|
236
|
+
{
|
|
237
|
+
description: 'Customer satisfaction score',
|
|
238
|
+
target: 4.5,
|
|
239
|
+
unit: 'rating',
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
description: 'First response time',
|
|
243
|
+
target: 5,
|
|
244
|
+
unit: 'minutes',
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
pricing: {
|
|
248
|
+
model: 'outcome-based',
|
|
249
|
+
outcomes: [
|
|
250
|
+
{ metric: 'resolution-rate', targetValue: 95, price: 1000 },
|
|
251
|
+
{ metric: 'satisfaction-score', targetValue: 4.8, price: 500 },
|
|
252
|
+
],
|
|
253
|
+
},
|
|
254
|
+
implementation: {
|
|
255
|
+
type: 'agent',
|
|
256
|
+
id: 'customer-support-agent',
|
|
257
|
+
},
|
|
258
|
+
})
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## API Reference
|
|
262
|
+
|
|
263
|
+
### Service Function
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
function Service(definition: ServiceDefinition): ServiceObject
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Creates a service with the given definition.
|
|
270
|
+
|
|
271
|
+
### ServiceDefinition
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
interface ServiceDefinition {
|
|
275
|
+
name: string
|
|
276
|
+
description?: string
|
|
277
|
+
objective: Objective
|
|
278
|
+
keyResults: KeyResult[]
|
|
279
|
+
pricing: ServicePricing
|
|
280
|
+
implementation: ImplementationDetails
|
|
281
|
+
metadata?: Record<string, any>
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Pricing Models
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
type PricingModel = 'cost-based' | 'margin-based' | 'activity-based' | 'outcome-based'
|
|
289
|
+
|
|
290
|
+
type ServicePricing = CostBasedPricing | MarginBasedPricing | ActivityBasedPricing | OutcomeBasedPricing
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Integration with Existing Services
|
|
294
|
+
|
|
295
|
+
The `services-as-software` package is designed to work with the existing services ecosystem:
|
|
296
|
+
|
|
297
|
+
- Integrates with the `services.do` SDK for service registration
|
|
298
|
+
- Extends the business model concepts from `Business-as-Code`
|
|
299
|
+
- Compatible with Functions, Workflows, and Agents collections
|
|
300
|
+
|
|
301
|
+
## License
|
|
302
|
+
|
|
303
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { Objective as Objective$1, KeyResult as KeyResult$1 } from 'business-as-code';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pricing model types for services
|
|
5
|
+
*/
|
|
6
|
+
type PricingModel = 'cost-based' | 'margin-based' | 'activity-based' | 'outcome-based';
|
|
7
|
+
/**
|
|
8
|
+
* Cost-based pricing configuration
|
|
9
|
+
*/
|
|
10
|
+
interface CostBasedPricing {
|
|
11
|
+
model: 'cost-based';
|
|
12
|
+
costBase: number;
|
|
13
|
+
fixedCosts?: number;
|
|
14
|
+
variableCosts?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Margin-based pricing configuration
|
|
18
|
+
*/
|
|
19
|
+
interface MarginBasedPricing {
|
|
20
|
+
model: 'margin-based';
|
|
21
|
+
costBase: number;
|
|
22
|
+
marginPercentage: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Activity-based pricing configuration
|
|
26
|
+
*/
|
|
27
|
+
interface ActivityBasedPricing {
|
|
28
|
+
model: 'activity-based';
|
|
29
|
+
activities: {
|
|
30
|
+
name: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
rate: number;
|
|
33
|
+
}[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Outcome-based pricing configuration
|
|
37
|
+
*/
|
|
38
|
+
interface OutcomeBasedPricing {
|
|
39
|
+
model: 'outcome-based';
|
|
40
|
+
outcomes: {
|
|
41
|
+
metric: string;
|
|
42
|
+
description?: string;
|
|
43
|
+
targetValue: number;
|
|
44
|
+
price: number;
|
|
45
|
+
unit?: string;
|
|
46
|
+
}[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Union type for all pricing configurations
|
|
50
|
+
*/
|
|
51
|
+
type ServicePricing = CostBasedPricing | MarginBasedPricing | ActivityBasedPricing | OutcomeBasedPricing;
|
|
52
|
+
/**
|
|
53
|
+
* Implementation types for services
|
|
54
|
+
*/
|
|
55
|
+
type ImplementationType = 'function' | 'workflow' | 'agent';
|
|
56
|
+
/**
|
|
57
|
+
* Implementation details for a service
|
|
58
|
+
*/
|
|
59
|
+
interface ImplementationDetails {
|
|
60
|
+
type: ImplementationType;
|
|
61
|
+
id: string;
|
|
62
|
+
version?: string;
|
|
63
|
+
configuration?: Record<string, any>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Service definition with business model aspects
|
|
67
|
+
*/
|
|
68
|
+
interface ServiceDefinition {
|
|
69
|
+
/**
|
|
70
|
+
* Service name
|
|
71
|
+
*/
|
|
72
|
+
name: string;
|
|
73
|
+
/**
|
|
74
|
+
* Service description
|
|
75
|
+
*/
|
|
76
|
+
description?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Service objective
|
|
79
|
+
*/
|
|
80
|
+
objective: Objective$1;
|
|
81
|
+
/**
|
|
82
|
+
* Key results for measuring service success
|
|
83
|
+
*/
|
|
84
|
+
keyResults: KeyResult$1[];
|
|
85
|
+
/**
|
|
86
|
+
* Service pricing model
|
|
87
|
+
*/
|
|
88
|
+
pricing: ServicePricing;
|
|
89
|
+
/**
|
|
90
|
+
* Implementation details
|
|
91
|
+
*/
|
|
92
|
+
implementation: ImplementationDetails;
|
|
93
|
+
/**
|
|
94
|
+
* Additional metadata
|
|
95
|
+
*/
|
|
96
|
+
metadata?: Record<string, any>;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Registered service with additional properties
|
|
100
|
+
*/
|
|
101
|
+
interface RegisteredService extends ServiceDefinition {
|
|
102
|
+
/**
|
|
103
|
+
* Unique service identifier
|
|
104
|
+
*/
|
|
105
|
+
id: string;
|
|
106
|
+
/**
|
|
107
|
+
* Service status
|
|
108
|
+
*/
|
|
109
|
+
status: 'active' | 'inactive' | 'degraded';
|
|
110
|
+
/**
|
|
111
|
+
* Service endpoint URL
|
|
112
|
+
*/
|
|
113
|
+
endpoint: string;
|
|
114
|
+
/**
|
|
115
|
+
* Creation timestamp
|
|
116
|
+
*/
|
|
117
|
+
createdAt: string;
|
|
118
|
+
/**
|
|
119
|
+
* Last update timestamp
|
|
120
|
+
*/
|
|
121
|
+
updatedAt: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
interface Objective {
|
|
125
|
+
description: string;
|
|
126
|
+
keyResults: string[] | KeyResult[];
|
|
127
|
+
}
|
|
128
|
+
interface KeyResult {
|
|
129
|
+
description: string;
|
|
130
|
+
target?: number;
|
|
131
|
+
currentValue?: number;
|
|
132
|
+
unit?: string;
|
|
133
|
+
dueDate?: Date;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Calculate price for cost-based pricing model
|
|
138
|
+
* @param pricing Cost-based pricing configuration
|
|
139
|
+
* @param quantity Number of units
|
|
140
|
+
* @returns Calculated price
|
|
141
|
+
*/
|
|
142
|
+
declare function calculateCostBasedPrice(pricing: CostBasedPricing, quantity?: number): number;
|
|
143
|
+
/**
|
|
144
|
+
* Calculate price for margin-based pricing model
|
|
145
|
+
* @param pricing Margin-based pricing configuration
|
|
146
|
+
* @param quantity Number of units
|
|
147
|
+
* @returns Calculated price
|
|
148
|
+
*/
|
|
149
|
+
declare function calculateMarginBasedPrice(pricing: MarginBasedPricing, quantity?: number): number;
|
|
150
|
+
/**
|
|
151
|
+
* Calculate price for activity-based pricing model
|
|
152
|
+
* @param pricing Activity-based pricing configuration
|
|
153
|
+
* @param activities Record of activity names and their quantities
|
|
154
|
+
* @returns Calculated price
|
|
155
|
+
*/
|
|
156
|
+
declare function calculateActivityBasedPrice(pricing: ActivityBasedPricing, activities: Record<string, number>): number;
|
|
157
|
+
/**
|
|
158
|
+
* Calculate price for outcome-based pricing model
|
|
159
|
+
* @param pricing Outcome-based pricing configuration
|
|
160
|
+
* @param outcomes Record of metric names and their achieved values
|
|
161
|
+
* @returns Calculated price
|
|
162
|
+
*/
|
|
163
|
+
declare function calculateOutcomeBasedPrice(pricing: OutcomeBasedPricing, outcomes: Record<string, number>): number;
|
|
164
|
+
/**
|
|
165
|
+
* Calculate price based on the pricing model
|
|
166
|
+
* @param pricing Service pricing configuration
|
|
167
|
+
* @param params Additional parameters for price calculation
|
|
168
|
+
* @returns Calculated price
|
|
169
|
+
*/
|
|
170
|
+
declare function calculatePrice(pricing: ServicePricing, params?: {
|
|
171
|
+
quantity?: number;
|
|
172
|
+
activities?: Record<string, number>;
|
|
173
|
+
outcomes?: Record<string, number>;
|
|
174
|
+
}): number;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Create a service with objectives, key results, and pricing models
|
|
178
|
+
* @param definition Service definition
|
|
179
|
+
* @returns Service object with additional methods
|
|
180
|
+
*/
|
|
181
|
+
declare function Service(definition: ServiceDefinition): {
|
|
182
|
+
/**
|
|
183
|
+
* Calculate the price for this service
|
|
184
|
+
* @param params Parameters for price calculation
|
|
185
|
+
* @returns Calculated price
|
|
186
|
+
*/
|
|
187
|
+
calculatePrice(params?: Parameters<typeof calculatePrice>[1]): number;
|
|
188
|
+
/**
|
|
189
|
+
* Register the service with the service registry
|
|
190
|
+
* @param options Optional configuration for service registration
|
|
191
|
+
* @returns Promise resolving to the registered service
|
|
192
|
+
*/
|
|
193
|
+
register(options?: {
|
|
194
|
+
apiKey?: string;
|
|
195
|
+
baseUrl?: string;
|
|
196
|
+
}): Promise<RegisteredService>;
|
|
197
|
+
/**
|
|
198
|
+
* Track progress towards key results
|
|
199
|
+
* @param results Record of key result updates
|
|
200
|
+
*/
|
|
201
|
+
trackProgress(results: Record<string, number>): void;
|
|
202
|
+
/**
|
|
203
|
+
* Check if all key results have been achieved
|
|
204
|
+
* @returns Whether all key results have been achieved
|
|
205
|
+
*/
|
|
206
|
+
isObjectiveAchieved(): boolean;
|
|
207
|
+
name: string;
|
|
208
|
+
description?: string;
|
|
209
|
+
objective: Objective;
|
|
210
|
+
keyResults: KeyResult[];
|
|
211
|
+
pricing: ServicePricing;
|
|
212
|
+
implementation: ImplementationDetails;
|
|
213
|
+
metadata?: Record<string, any>;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
export { type ActivityBasedPricing, type CostBasedPricing, type ImplementationDetails, type ImplementationType, type MarginBasedPricing, type OutcomeBasedPricing, type PricingModel, type RegisteredService, Service, type ServiceDefinition, type ServicePricing, calculateActivityBasedPrice, calculateCostBasedPrice, calculateMarginBasedPrice, calculateOutcomeBasedPrice, calculatePrice };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// src/pricing/index.ts
|
|
2
|
+
function calculateCostBasedPrice(pricing, quantity = 1) {
|
|
3
|
+
const { costBase, fixedCosts = 0, variableCosts = 0 } = pricing;
|
|
4
|
+
return costBase + fixedCosts + variableCosts * quantity;
|
|
5
|
+
}
|
|
6
|
+
function calculateMarginBasedPrice(pricing, quantity = 1) {
|
|
7
|
+
const { costBase, marginPercentage } = pricing;
|
|
8
|
+
const cost = costBase * quantity;
|
|
9
|
+
const margin = cost * (marginPercentage / 100);
|
|
10
|
+
return cost + margin;
|
|
11
|
+
}
|
|
12
|
+
function calculateActivityBasedPrice(pricing, activities) {
|
|
13
|
+
return pricing.activities.reduce((total, activity) => {
|
|
14
|
+
const quantity = activities[activity.name] || 0;
|
|
15
|
+
return total + activity.rate * quantity;
|
|
16
|
+
}, 0);
|
|
17
|
+
}
|
|
18
|
+
function calculateOutcomeBasedPrice(pricing, outcomes) {
|
|
19
|
+
return pricing.outcomes.reduce((total, outcome) => {
|
|
20
|
+
const achievedValue = outcomes[outcome.metric] || 0;
|
|
21
|
+
if (achievedValue >= outcome.targetValue) {
|
|
22
|
+
return total + outcome.price;
|
|
23
|
+
}
|
|
24
|
+
return total;
|
|
25
|
+
}, 0);
|
|
26
|
+
}
|
|
27
|
+
function calculatePrice(pricing, params = {}) {
|
|
28
|
+
const { quantity = 1, activities = {}, outcomes = {} } = params;
|
|
29
|
+
switch (pricing.model) {
|
|
30
|
+
case "cost-based":
|
|
31
|
+
return calculateCostBasedPrice(pricing, quantity);
|
|
32
|
+
case "margin-based":
|
|
33
|
+
return calculateMarginBasedPrice(pricing, quantity);
|
|
34
|
+
case "activity-based":
|
|
35
|
+
return calculateActivityBasedPrice(pricing, activities);
|
|
36
|
+
case "outcome-based":
|
|
37
|
+
return calculateOutcomeBasedPrice(pricing, outcomes);
|
|
38
|
+
default:
|
|
39
|
+
throw new Error(`Unsupported pricing model: ${pricing.model}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/index.ts
|
|
44
|
+
function Service(definition) {
|
|
45
|
+
validateServiceDefinition(definition);
|
|
46
|
+
const service = {
|
|
47
|
+
...definition,
|
|
48
|
+
/**
|
|
49
|
+
* Calculate the price for this service
|
|
50
|
+
* @param params Parameters for price calculation
|
|
51
|
+
* @returns Calculated price
|
|
52
|
+
*/
|
|
53
|
+
calculatePrice(params) {
|
|
54
|
+
return calculatePrice(definition.pricing, params);
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* Register the service with the service registry
|
|
58
|
+
* @param options Optional configuration for service registration
|
|
59
|
+
* @returns Promise resolving to the registered service
|
|
60
|
+
*/
|
|
61
|
+
async register(options) {
|
|
62
|
+
try {
|
|
63
|
+
const { Services } = await import("services.do");
|
|
64
|
+
const services = new Services(options);
|
|
65
|
+
const serviceDefinition = {
|
|
66
|
+
name: definition.name,
|
|
67
|
+
description: definition.description,
|
|
68
|
+
endpoint: `https://api.services.do/implementations/${definition.implementation.type}/${definition.implementation.id}`,
|
|
69
|
+
version: definition.implementation.version,
|
|
70
|
+
metadata: {
|
|
71
|
+
...definition.metadata,
|
|
72
|
+
objective: definition.objective,
|
|
73
|
+
keyResults: definition.keyResults,
|
|
74
|
+
pricing: definition.pricing,
|
|
75
|
+
implementation: definition.implementation
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const registeredService = await services.register(serviceDefinition);
|
|
79
|
+
return {
|
|
80
|
+
...definition,
|
|
81
|
+
id: registeredService.id,
|
|
82
|
+
status: registeredService.status,
|
|
83
|
+
endpoint: registeredService.endpoint,
|
|
84
|
+
createdAt: registeredService.createdAt,
|
|
85
|
+
updatedAt: registeredService.updatedAt
|
|
86
|
+
};
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.warn("Failed to register with services.do, using mock implementation", error);
|
|
89
|
+
return {
|
|
90
|
+
...definition,
|
|
91
|
+
id: generateId(),
|
|
92
|
+
status: "active",
|
|
93
|
+
endpoint: `https://api.services.do/services/${generateId()}`,
|
|
94
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
95
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
/**
|
|
100
|
+
* Track progress towards key results
|
|
101
|
+
* @param results Record of key result updates
|
|
102
|
+
*/
|
|
103
|
+
trackProgress(results) {
|
|
104
|
+
definition.keyResults.forEach((kr) => {
|
|
105
|
+
if (kr.description in results) {
|
|
106
|
+
kr.currentValue = results[kr.description];
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
/**
|
|
111
|
+
* Check if all key results have been achieved
|
|
112
|
+
* @returns Whether all key results have been achieved
|
|
113
|
+
*/
|
|
114
|
+
isObjectiveAchieved() {
|
|
115
|
+
return definition.keyResults.every((kr) => kr.currentValue !== void 0 && kr.target !== void 0 && kr.currentValue >= kr.target);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
return service;
|
|
119
|
+
}
|
|
120
|
+
function validateServiceDefinition(definition) {
|
|
121
|
+
const { name, objective, keyResults, pricing, implementation } = definition;
|
|
122
|
+
if (!name) {
|
|
123
|
+
throw new Error("Service name is required");
|
|
124
|
+
}
|
|
125
|
+
if (!objective || !objective.description) {
|
|
126
|
+
throw new Error("Service objective with description is required");
|
|
127
|
+
}
|
|
128
|
+
if (!keyResults || !Array.isArray(keyResults) || keyResults.length === 0) {
|
|
129
|
+
throw new Error("At least one key result is required");
|
|
130
|
+
}
|
|
131
|
+
if (!pricing || !pricing.model) {
|
|
132
|
+
throw new Error("Service pricing model is required");
|
|
133
|
+
}
|
|
134
|
+
if (!implementation || !implementation.type || !implementation.id) {
|
|
135
|
+
throw new Error("Service implementation details are required");
|
|
136
|
+
}
|
|
137
|
+
switch (pricing.model) {
|
|
138
|
+
case "cost-based":
|
|
139
|
+
if (pricing.costBase === void 0) {
|
|
140
|
+
throw new Error("Cost base is required for cost-based pricing");
|
|
141
|
+
}
|
|
142
|
+
break;
|
|
143
|
+
case "margin-based":
|
|
144
|
+
if (pricing.costBase === void 0 || pricing.marginPercentage === void 0) {
|
|
145
|
+
throw new Error("Cost base and margin percentage are required for margin-based pricing");
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
case "activity-based":
|
|
149
|
+
if (!pricing.activities || !Array.isArray(pricing.activities) || pricing.activities.length === 0) {
|
|
150
|
+
throw new Error("At least one activity is required for activity-based pricing");
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
153
|
+
case "outcome-based":
|
|
154
|
+
if (!pricing.outcomes || !Array.isArray(pricing.outcomes) || pricing.outcomes.length === 0) {
|
|
155
|
+
throw new Error("At least one outcome is required for outcome-based pricing");
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
default:
|
|
159
|
+
throw new Error(`Unsupported pricing model: ${pricing.model}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function generateId() {
|
|
163
|
+
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
164
|
+
}
|
|
165
|
+
export {
|
|
166
|
+
Service,
|
|
167
|
+
calculateActivityBasedPrice,
|
|
168
|
+
calculateCostBasedPrice,
|
|
169
|
+
calculateMarginBasedPrice,
|
|
170
|
+
calculateOutcomeBasedPrice,
|
|
171
|
+
calculatePrice
|
|
172
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "services-as-software",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Define services with objectives, key results, and various pricing models",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"services",
|
|
7
|
+
"business",
|
|
8
|
+
"pricing",
|
|
9
|
+
"objectives",
|
|
10
|
+
"key results",
|
|
11
|
+
"agentic"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://mdx.org.ai",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "dist/index.js",
|
|
16
|
+
"module": "dist/index.js",
|
|
17
|
+
"types": "dist/index.d.ts",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
23
|
+
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
24
|
+
"lint": "eslint src --ext ts",
|
|
25
|
+
"clean": "rm -rf dist",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"test:watch": "vitest"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"apis.do": "0.1.0",
|
|
31
|
+
"services.do": "workspace:*"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"business-as-code": "0.0.2",
|
|
35
|
+
"tsup": "^8.0.1",
|
|
36
|
+
"typescript": "^5.2.2",
|
|
37
|
+
"vitest": "^0.34.6"
|
|
38
|
+
},
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/drivly/ai.git",
|
|
42
|
+
"directory": "pkgs/services-as-software"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/drivly/ai/issues"
|
|
46
|
+
},
|
|
47
|
+
"author": "Drivly",
|
|
48
|
+
"license": "MIT"
|
|
49
|
+
}
|