@powerhousedao/service-offering 1.0.0-dev.3 → 1.0.0-dev.4

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.
@@ -1,3 +1,3 @@
1
- import { type ISubgraph } from "@powerhousedao/reactor-api";
2
- export declare const getResolvers: (subgraph: ISubgraph) => Record<string, unknown>;
1
+ import { BaseSubgraph } from "@powerhousedao/reactor-api";
2
+ export declare const getResolvers: (subgraph: BaseSubgraph) => Record<string, unknown>;
3
3
  //# sourceMappingURL=resolvers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolvers.d.ts","sourceRoot":"","sources":["../../../subgraphs/resources-services/resolvers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAsD5D,eAAO,MAAM,YAAY,GAAI,UAAU,SAAS,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CA6fxE,CAAC"}
1
+ {"version":3,"file":"resolvers.d.ts","sourceRoot":"","sources":["../../../subgraphs/resources-services/resolvers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAsD1D,eAAO,MAAM,YAAY,GAAI,UAAU,YAAY,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAib3E,CAAC"}
@@ -1,150 +1,95 @@
1
- import {} from "@powerhousedao/reactor-api";
1
+ import { BaseSubgraph } from "@powerhousedao/reactor-api";
2
2
  import { createAction, generateId } from "document-model/core";
3
3
  import { addFile } from "document-drive";
4
4
  import { ResourceInstanceV1, SubscriptionInstanceV1, } from "@powerhousedao/service-offering/document-models";
5
5
  export const getResolvers = (subgraph) => {
6
6
  const reactor = subgraph.reactor;
7
+ const reactorClient = subgraph.reactorClient;
7
8
  return {
8
9
  Query: {
9
10
  resourceTemplates: async (_, args) => {
10
11
  const { id, status, operatorId } = args.filter || {};
11
- // If filtering by specific id, try to fetch directly
12
+ // If filtering by specific id, fetch directly
12
13
  if (id) {
13
14
  try {
14
- const doc = await reactor.getDocument(id);
15
- if (doc &&
16
- doc.header.documentType === "powerhouse/resource-template") {
17
- const state = doc.state.global;
18
- // Check status filter if provided
19
- if (status &&
20
- status.length > 0 &&
21
- !status.includes(state.status)) {
22
- return [];
23
- }
24
- // Check operatorId filter if provided
25
- if (operatorId && state.operatorId !== operatorId) {
26
- return [];
27
- }
28
- return [mapResourceTemplateState(state, doc)];
15
+ const result = await reactorClient.find({ type: "powerhouse/resource-template", ids: [id] });
16
+ const docs = result.results;
17
+ if (docs.length === 0)
18
+ return [];
19
+ const doc = docs[0];
20
+ const state = doc.state.global;
21
+ if (status && status.length > 0 && !status.includes(state.status)) {
22
+ return [];
29
23
  }
24
+ if (operatorId && state.operatorId !== operatorId) {
25
+ return [];
26
+ }
27
+ return [mapResourceTemplateState(state, doc)];
30
28
  }
31
29
  catch {
32
- // Document not found
30
+ return [];
33
31
  }
34
- return [];
35
32
  }
36
- // Scan all drives for resource template documents
37
- const drives = await reactor.getDrives();
33
+ // Find all resource template documents
34
+ const result = await reactorClient.find({ type: "powerhouse/resource-template" });
35
+ const docs = result.results;
38
36
  const resourceTemplates = [];
39
- for (const driveId of drives) {
40
- try {
41
- const docIds = await reactor.getDocuments(driveId);
42
- const docs = await Promise.all(docIds.map(async (docId) => {
43
- try {
44
- return await reactor.getDocument(docId);
45
- }
46
- catch {
47
- return null;
48
- }
49
- }));
50
- for (const doc of docs) {
51
- if (doc &&
52
- doc.header.documentType === "powerhouse/resource-template") {
53
- const resourceDoc = doc;
54
- const state = resourceDoc.state.global;
55
- // Apply status filter if provided
56
- if (status &&
57
- status.length > 0 &&
58
- !status.includes(state.status)) {
59
- continue;
60
- }
61
- // Apply operatorId filter if provided
62
- if (operatorId && state.operatorId !== operatorId) {
63
- continue;
64
- }
65
- resourceTemplates.push(mapResourceTemplateState(state, doc));
66
- }
67
- }
37
+ for (const doc of docs) {
38
+ const state = doc.state.global;
39
+ if (status && status.length > 0 && !status.includes(state.status)) {
40
+ continue;
68
41
  }
69
- catch (error) {
70
- console.warn(`Failed to inspect drive ${driveId}:`, error);
42
+ if (operatorId && state.operatorId !== operatorId) {
43
+ continue;
71
44
  }
45
+ resourceTemplates.push(mapResourceTemplateState(state, doc));
72
46
  }
73
47
  return resourceTemplates;
74
48
  },
75
49
  serviceOfferings: async (_, args) => {
76
50
  const { id, status, operatorId, resourceTemplateId } = args.filter || {};
77
- // If filtering by specific id, try to fetch directly
51
+ // If filtering by specific id, fetch directly
78
52
  if (id) {
79
53
  try {
80
- const doc = await reactor.getDocument(id);
81
- if (doc &&
82
- doc.header.documentType === "powerhouse/service-offering") {
83
- const state = doc.state.global;
84
- // Check status filter if provided
85
- if (status &&
86
- status.length > 0 &&
87
- !status.includes(state.status)) {
88
- return [];
89
- }
90
- // Check operatorId filter if provided
91
- if (operatorId && state.operatorId !== operatorId) {
92
- return [];
93
- }
94
- // Check resourceTemplateId filter if provided
95
- if (resourceTemplateId &&
96
- state.resourceTemplateId !== resourceTemplateId) {
97
- return [];
98
- }
99
- return [mapServiceOfferingState(state, doc)];
54
+ const result = await reactorClient.find({ type: "powerhouse/service-offering", ids: [id] });
55
+ const docs = result.results;
56
+ if (docs.length === 0)
57
+ return [];
58
+ const doc = docs[0];
59
+ const state = doc.state.global;
60
+ if (status && status.length > 0 && !status.includes(state.status)) {
61
+ return [];
100
62
  }
63
+ if (operatorId && state.operatorId !== operatorId) {
64
+ return [];
65
+ }
66
+ if (resourceTemplateId &&
67
+ state.resourceTemplateId !== resourceTemplateId) {
68
+ return [];
69
+ }
70
+ return [mapServiceOfferingState(state, doc)];
101
71
  }
102
72
  catch {
103
- // Document not found
73
+ return [];
104
74
  }
105
- return [];
106
75
  }
107
- // Scan all drives for service offering documents
108
- const drives = await reactor.getDrives();
76
+ // Find all service offering documents
77
+ const result = await reactorClient.find({ type: "powerhouse/service-offering" });
78
+ const docs = result.results;
109
79
  const serviceOfferings = [];
110
- for (const driveId of drives) {
111
- try {
112
- const docIds = await reactor.getDocuments(driveId);
113
- const docs = await Promise.all(docIds.map(async (docId) => {
114
- try {
115
- return await reactor.getDocument(docId);
116
- }
117
- catch {
118
- return null;
119
- }
120
- }));
121
- for (const doc of docs) {
122
- if (doc &&
123
- doc.header.documentType === "powerhouse/service-offering") {
124
- const offeringDoc = doc;
125
- const state = offeringDoc.state.global;
126
- // Apply status filter if provided
127
- if (status &&
128
- status.length > 0 &&
129
- !status.includes(state.status)) {
130
- continue;
131
- }
132
- // Apply operatorId filter if provided
133
- if (operatorId && state.operatorId !== operatorId) {
134
- continue;
135
- }
136
- // Apply resourceTemplateId filter if provided
137
- if (resourceTemplateId &&
138
- state.resourceTemplateId !== resourceTemplateId) {
139
- continue;
140
- }
141
- serviceOfferings.push(mapServiceOfferingState(state, doc));
142
- }
143
- }
80
+ for (const doc of docs) {
81
+ const state = doc.state.global;
82
+ if (status && status.length > 0 && !status.includes(state.status)) {
83
+ continue;
144
84
  }
145
- catch (error) {
146
- console.warn(`Failed to inspect drive ${driveId}:`, error);
85
+ if (operatorId && state.operatorId !== operatorId) {
86
+ continue;
147
87
  }
88
+ if (resourceTemplateId &&
89
+ state.resourceTemplateId !== resourceTemplateId) {
90
+ continue;
91
+ }
92
+ serviceOfferings.push(mapServiceOfferingState(state, doc));
148
93
  }
149
94
  return serviceOfferings;
150
95
  },
@@ -292,7 +237,7 @@ export const getResolvers = (subgraph) => {
292
237
  const subscriptionInstanceDoc = await reactor.addDocument("powerhouse/subscription-instance");
293
238
  // resolve parent folders for both drives
294
239
  const teamParentFolder = teamBuilderAdminDrive.state.global.nodes?.find((node) => node.kind === "folder")?.parentFolder;
295
- const operatorDrive = await getOperatorDrive(reactor, resourceTemplateId);
240
+ const operatorDrive = await getOperatorDrive(reactorClient, resourceTemplateId);
296
241
  if (!operatorDrive) {
297
242
  throw new Error(`Operator drive not found for resource template ${resourceTemplateId}`);
298
243
  }
@@ -436,6 +381,12 @@ function mapResourceTemplateState(state, doc) {
436
381
  parentServiceId: service.parentServiceId || null,
437
382
  isSetupFormation: service.isSetupFormation,
438
383
  optionGroupId: service.optionGroupId || null,
384
+ facetBindings: (service.facetBindings || []).map((binding) => ({
385
+ id: binding.id,
386
+ facetName: binding.facetName,
387
+ facetType: binding.facetType,
388
+ supportedOptions: binding.supportedOptions,
389
+ })),
439
390
  })),
440
391
  optionGroups: (state.optionGroups || []).map((group) => ({
441
392
  id: group.id,
@@ -526,10 +477,10 @@ function mapServiceOfferingState(state, doc) {
526
477
  name: tier.name,
527
478
  description: tier.description || null,
528
479
  isCustomPricing: tier.isCustomPricing,
529
- pricingMode: tier.pricingMode || null,
480
+ pricingMode: tier.pricingMode,
530
481
  pricing: tier.pricing
531
482
  ? {
532
- amount: tier.pricing.amount ?? null,
483
+ amount: tier.pricing.amount,
533
484
  currency: tier.pricing.currency,
534
485
  }
535
486
  : null,
@@ -543,6 +494,7 @@ function mapServiceOfferingState(state, doc) {
543
494
  id: level.id,
544
495
  serviceId: level.serviceId,
545
496
  level: level.level,
497
+ description: level.description || null,
546
498
  })),
547
499
  usageLimits: tier.usageLimits.map((limit) => ({
548
500
  id: limit.id,
@@ -557,7 +509,7 @@ function mapServiceOfferingState(state, doc) {
557
509
  description: group.description || null,
558
510
  isAddOn: group.isAddOn,
559
511
  defaultSelected: group.defaultSelected,
560
- pricingMode: group.pricingMode || null,
512
+ pricingMode: group.pricingMode,
561
513
  standalonePricing: group.standalonePricing
562
514
  ? {
563
515
  amount: group.standalonePricing.amount,
@@ -582,12 +534,12 @@ function mapServiceOfferingState(state, doc) {
582
534
  })),
583
535
  };
584
536
  }
585
- async function getOperatorDrive(reactor, resourceTemplateId) {
586
- const drives = await reactor.getDrives();
587
- const results = await Promise.all(drives.map(async (drive) => {
588
- const docIds = await reactor.getDocuments(drive);
589
- return docIds.includes(resourceTemplateId) ? drive : null;
590
- }));
591
- const driveId = results.find((id) => id !== null);
592
- return driveId ? reactor.getDrive(driveId) : undefined;
537
+ /**
538
+ * Find the drive that contains a given resource template document.
539
+ * Uses reactorClient to find the parent drive.
540
+ */
541
+ async function getOperatorDrive(reactorClient, resourceTemplateId) {
542
+ const result = await reactorClient.getParents(resourceTemplateId);
543
+ const parentDrive = result.results.find((doc) => doc.header.documentType === "powerhouse/document-drive");
544
+ return parentDrive;
593
545
  }
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../subgraphs/resources-services/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,MAAM,EAAE,YAsVpB,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../subgraphs/resources-services/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,MAAM,EAAE,YAoRpB,CAAC"}
@@ -45,7 +45,7 @@ export const schema = gql `
45
45
 
46
46
  input RSResourceTemplatesFilter {
47
47
  id: PHID
48
- status: [RSTemplateStatusInput!]
48
+ status: [RSTemplateStatus!]
49
49
  operatorId: PHID
50
50
  }
51
51
 
@@ -58,7 +58,7 @@ export const schema = gql `
58
58
 
59
59
  # ============ Resource Template Types ============
60
60
 
61
- enum RSTemplateStatusInput {
61
+ enum RSTemplateStatus {
62
62
  DRAFT
63
63
  COMING_SOON
64
64
  ACTIVE
@@ -81,30 +81,16 @@ export const schema = gql `
81
81
  facetTargets: [RSFacetTarget!]!
82
82
  services: [RSService!]!
83
83
  optionGroups: [RSOptionGroup!]!
84
- faqFields: [RSFaqField!]
84
+ faqFields: [RSFaqField!]!
85
85
  contentSections: [RSContentSection!]!
86
86
  }
87
87
 
88
- enum RSTemplateStatus {
89
- DRAFT
90
- COMING_SOON
91
- ACTIVE
92
- DEPRECATED
93
- }
94
-
95
88
  type RSTargetAudience {
96
89
  id: OID!
97
90
  label: String!
98
91
  color: String
99
92
  }
100
93
 
101
- type RSOfferingFacetTarget {
102
- id: OID!
103
- categoryKey: String!
104
- categoryLabel: String!
105
- selectedOptions: [String!]!
106
- }
107
-
108
94
  type RSService {
109
95
  id: OID!
110
96
  title: String!
@@ -116,6 +102,13 @@ export const schema = gql `
116
102
  facetBindings: [RSResourceFacetBinding!]!
117
103
  }
118
104
 
105
+ type RSResourceFacetBinding {
106
+ id: OID!
107
+ facetName: String!
108
+ facetType: PHID!
109
+ supportedOptions: [OID!]!
110
+ }
111
+
119
112
  type RSOptionGroup {
120
113
  id: OID!
121
114
  name: String!
@@ -152,7 +145,7 @@ export const schema = gql `
152
145
  status: RSServiceStatus!
153
146
  lastModified: DateTime!
154
147
  availableBillingCycles: [RSBillingCycle!]!
155
- facetTargets: [RSOfferingFacetTarget!]!
148
+ facetTargets: [RSFacetTarget!]!
156
149
  services: [RSOfferingService!]!
157
150
  tiers: [RSServiceSubscriptionTier!]!
158
151
  optionGroups: [RSOfferingOptionGroup!]!
@@ -172,40 +165,34 @@ export const schema = gql `
172
165
  selectedOptions: [String!]!
173
166
  }
174
167
 
175
- # ---------- Discount & Pricing Primitives ----------
168
+ # ---------- Primitives ----------
176
169
 
177
170
  enum RSDiscountType {
178
171
  PERCENTAGE
179
- FLAT_AMOUNT
172
+ FIXED_AMOUNT
180
173
  }
181
174
 
182
- type RSDiscountRule {
183
- discountType: RSDiscountType!
184
- discountValue: Float!
175
+ enum RSBillingCycle {
176
+ MONTHLY
177
+ QUARTERLY
178
+ SEMI_ANNUAL
179
+ ANNUAL
185
180
  }
186
181
 
187
182
  type RSBillingCycleDiscount {
188
- billingCycle: RSBillingCycle!
189
- discountRule: RSDiscountRule!
190
- }
191
-
192
- type RSSetupCost {
193
- amount: Amount_Money!
194
- currency: Currency!
195
- discount: RSDiscountRule
183
+ cycle: RSBillingCycle!
184
+ discountType: RSDiscountType!
185
+ discountValue: Float!
196
186
  }
197
187
 
198
- type RSRecurringPriceOption {
199
- id: OID!
200
- billingCycle: RSBillingCycle!
188
+ type RSPricing {
201
189
  amount: Amount_Money!
202
190
  currency: Currency!
203
- discount: RSDiscountRule
204
191
  }
205
192
 
206
193
  enum RSDiscountMode {
207
194
  INHERIT_TIER
208
- INDEPENDENT
195
+ OWN_DISCOUNTS
209
196
  }
210
197
 
211
198
  # ---------- Services ----------
@@ -219,18 +206,12 @@ export const schema = gql `
219
206
  optionGroupId: OID
220
207
  }
221
208
 
222
- type RSResourceFacetBinding {
223
- id: OID!
224
- facetName: String!
225
- facetType: PHID!
226
- supportedOptions: [OID!]!
227
- }
228
-
229
209
  # ---------- Tiers ----------
230
210
 
231
211
  enum RSTierPricingMode {
232
- CALCULATED
233
- MANUAL_OVERRIDE
212
+ CUSTOM
213
+ FIXED
214
+ PER_SEAT
234
215
  }
235
216
 
236
217
  type RSServiceSubscriptionTier {
@@ -238,66 +219,26 @@ export const schema = gql `
238
219
  name: String!
239
220
  description: String
240
221
  isCustomPricing: Boolean!
241
- pricingMode: RSTierPricingMode
242
- pricing: RSServicePricing!
222
+ pricingMode: RSTierPricingMode!
223
+ pricing: RSPricing
243
224
  defaultBillingCycle: RSBillingCycle
244
225
  billingCycleDiscounts: [RSBillingCycleDiscount!]!
245
226
  serviceLevels: [RSServiceLevelBinding!]!
246
- usageLimits: [RSServiceUsageLimit!]!
247
- }
248
-
249
- type RSServicePricing {
250
- amount: Amount_Money
251
- currency: Currency!
252
- }
253
-
254
- enum RSBillingCycle {
255
- MONTHLY
256
- QUARTERLY
257
- SEMI_ANNUAL
258
- ANNUAL
259
- ONE_TIME
227
+ usageLimits: [RSUsageLimit!]!
260
228
  }
261
229
 
262
230
  type RSServiceLevelBinding {
263
231
  id: OID!
264
232
  serviceId: OID!
265
- level: RSServiceLevel!
266
- customValue: String
267
- optionGroupId: OID
268
- }
269
-
270
- enum RSServiceLevel {
271
- INCLUDED
272
- NOT_INCLUDED
273
- OPTIONAL
274
- CUSTOM
275
- VARIABLE
276
- NOT_APPLICABLE
233
+ level: String!
234
+ description: String
277
235
  }
278
236
 
279
- type RSServiceUsageLimit {
237
+ type RSUsageLimit {
280
238
  id: OID!
281
- serviceId: OID!
282
- metric: String!
283
- unitName: String
284
- freeLimit: Int
285
- paidLimit: Int
286
- resetCycle: RSUsageResetCycle
287
- notes: String
288
- unitPrice: Amount_Money
289
- unitPriceCurrency: Currency
290
- }
291
-
292
- enum RSUsageResetCycle {
293
- NONE
294
- HOURLY
295
- DAILY
296
- WEEKLY
297
- MONTHLY
298
- QUARTERLY
299
- SEMI_ANNUAL
300
- ANNUAL
239
+ name: String!
240
+ limit: Int!
241
+ unit: String
301
242
  }
302
243
 
303
244
  # ---------- Option Groups ----------
@@ -318,9 +259,9 @@ export const schema = gql `
318
259
  description: String
319
260
  isAddOn: Boolean!
320
261
  defaultSelected: Boolean!
321
- pricingMode: RSAddOnPricingMode
322
- standalonePricing: RSStandalonePricing
323
- tierDependentPricing: [RSOptionGroupTierPricing!]
262
+ pricingMode: RSAddOnPricingMode!
263
+ standalonePricing: RSPricing
264
+ tierDependentPricing: [RSTierDependentPricing!]!
324
265
  costType: RSGroupCostType
325
266
  availableBillingCycles: [RSBillingCycle!]!
326
267
  billingCycleDiscounts: [RSBillingCycleDiscount!]!
@@ -329,16 +270,9 @@ export const schema = gql `
329
270
  currency: Currency
330
271
  }
331
272
 
332
- type RSStandalonePricing {
333
- setupCost: RSSetupCost
334
- recurringPricing: [RSRecurringPriceOption!]!
335
- }
336
-
337
- type RSOptionGroupTierPricing {
338
- id: OID!
273
+ type RSTierDependentPricing {
339
274
  tierId: OID!
340
- setupCost: RSSetupCost
341
- setupCostDiscounts: [RSBillingCycleDiscount!]!
342
- recurringPricing: [RSRecurringPriceOption!]!
275
+ amount: Amount_Money!
276
+ currency: Currency!
343
277
  }
344
278
  `;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/service-offering",
3
3
  "description": "service offering document models",
4
- "version": "1.0.0-dev.3",
4
+ "version": "1.0.0-dev.4",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
7
7
  "type": "git",