@powerhousedao/contributor-billing 0.1.50 → 0.1.51

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 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../subgraphs/budget-statements/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,MAAM,EAAE,YAoIpB,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../subgraphs/budget-statements/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,MAAM,EAAE,YAqIpB,CAAC"}
@@ -88,6 +88,7 @@ export const schema = gql `
88
88
  Return
89
89
  Internal
90
90
  External
91
+ Swap
91
92
  }
92
93
 
93
94
  type BudgetStatementExpenseReport {
@@ -1,6 +1,5 @@
1
1
  export * as InvoiceAddonSubgraph from "./invoice-addon/index.js";
2
2
  export * as AccTxsAddonSubgraph from "./acc-txs-addon/index.js";
3
3
  export * as BudgetStatementsSubgraph from "./budget-statements/index.js";
4
- export * as ExpenseReportSubgraph from "./expense-report/index.js";
5
4
  export * as ResourcesServicesSubgraph from "./resources-services/index.js";
6
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../subgraphs/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,oBAAoB,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,mBAAmB,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,wBAAwB,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,qBAAqB,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,yBAAyB,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../subgraphs/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,oBAAoB,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,mBAAmB,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,wBAAwB,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,yBAAyB,MAAM,+BAA+B,CAAC"}
@@ -1,5 +1,4 @@
1
1
  export * as InvoiceAddonSubgraph from "./invoice-addon/index.js";
2
2
  export * as AccTxsAddonSubgraph from "./acc-txs-addon/index.js";
3
3
  export * as BudgetStatementsSubgraph from "./budget-statements/index.js";
4
- export * as ExpenseReportSubgraph from "./expense-report/index.js";
5
4
  export * as ResourcesServicesSubgraph from "./resources-services/index.js";
@@ -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;AAyB5D,eAAO,MAAM,YAAY,GAAI,UAAU,SAAS,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAkMxE,CAAC"}
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;AAkC5D,eAAO,MAAM,YAAY,GAAI,UAAU,SAAS,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAmSxE,CAAC"}
@@ -1,4 +1,7 @@
1
1
  import {} from "@powerhousedao/reactor-api";
2
+ import { addFile } from "document-drive";
3
+ import { BuilderProfile } from "@powerhousedao/builder-profile/document-models";
4
+ import { ResourceInstance } from "../../document-models/resource-instance/module.js";
2
5
  export const getResolvers = (subgraph) => {
3
6
  const reactor = subgraph.reactor;
4
7
  return {
@@ -146,8 +149,99 @@ export const getResolvers = (subgraph) => {
146
149
  return serviceOfferings;
147
150
  },
148
151
  },
152
+ Mutation: {
153
+ createResourceInstances: async (_, args) => {
154
+ const { input } = args;
155
+ const { resourceTemplateId, name, teamName } = input;
156
+ // Validate input
157
+ if (!resourceTemplateId) {
158
+ return { success: false, data: null, errors: ["Resource template ID is required"] };
159
+ }
160
+ if (!name) {
161
+ return { success: false, data: null, errors: ["Name is required"] };
162
+ }
163
+ if (!teamName) {
164
+ return { success: false, data: null, errors: ["Team name is required"] };
165
+ }
166
+ const parsedTeamName = teamName.toLowerCase().replace(/ /g, '-');
167
+ const parsedName = name.toLowerCase().replace(/ /g, '-');
168
+ try {
169
+ // create team-builder-admin drive
170
+ const teamBuilderAdminDrive = await reactor.addDrive({
171
+ global: { name: teamName, icon: "https://cdn-icons-png.flaticon.com/512/6020/6020347.png" },
172
+ id: parsedTeamName,
173
+ slug: parsedTeamName,
174
+ preferredEditor: "builder-team-admin"
175
+ });
176
+ teamBuilderAdminDrive.header.id;
177
+ // create builder-profile doc inside the team-builder-admin drive
178
+ const builderProfileDoc = await reactor.addDocument('powerhouse/builder-profile');
179
+ await reactor.addAction(teamBuilderAdminDrive.header.id, addFile({
180
+ documentType: "powerhouse/builder-profile",
181
+ id: builderProfileDoc.header.id,
182
+ name: `${parsedName} Builder Profile`,
183
+ parentFolder: teamBuilderAdminDrive.state.global.nodes?.find((node) => node.kind === 'folder')?.parentFolder,
184
+ }));
185
+ await reactor.addAction(builderProfileDoc.header.id, BuilderProfile.actions.updateProfile({
186
+ name: name,
187
+ }));
188
+ // create resource-instance doc inside the team-builder-admin drive
189
+ const resourceInstanceDoc = await reactor.addDocument('powerhouse/resource-instance');
190
+ await reactor.addAction(teamBuilderAdminDrive.header.id, addFile({
191
+ documentType: "powerhouse/resource-instance",
192
+ id: resourceInstanceDoc.header.id,
193
+ name: `${parsedName} Resource Instance`,
194
+ parentFolder: teamBuilderAdminDrive.state.global.nodes?.find((node) => node.kind === 'folder')?.parentFolder,
195
+ }));
196
+ await populateResourceInstance(reactor, resourceInstanceDoc.header.id, resourceTemplateId, builderProfileDoc.header.id, name);
197
+ // create copy of resource-instance doc inside the operator's drive
198
+ const operatorDrive = await getOperatorDrive(reactor, resourceTemplateId);
199
+ if (!operatorDrive) {
200
+ throw new Error(`Operator drive not found for resource template ${resourceTemplateId}`);
201
+ }
202
+ await reactor.addAction(operatorDrive.header.id, addFile({
203
+ documentType: "powerhouse/resource-instance",
204
+ id: resourceInstanceDoc.header.id,
205
+ name: `${parsedName} Resource Instance`,
206
+ parentFolder: operatorDrive.state.global.nodes?.find((node) => node.kind === 'folder')?.parentFolder,
207
+ }));
208
+ return {
209
+ success: true,
210
+ data: {
211
+ linkToDrive: getDriveLink(teamBuilderAdminDrive.header.id)
212
+ },
213
+ errors: [],
214
+ };
215
+ }
216
+ catch (error) {
217
+ console.error("Failed to create resource instance:", error);
218
+ return {
219
+ success: false,
220
+ data: null,
221
+ errors: [error instanceof Error ? error.message : "An unexpected error occurred"],
222
+ };
223
+ }
224
+ },
225
+ },
149
226
  };
150
227
  };
228
+ /**
229
+ * Build a link to a drive based on the current environment.
230
+ * Mirrors the logic from editors/shared/graphql.ts for server-side use.
231
+ */
232
+ function getDriveLink(driveId) {
233
+ const baseUri = process.env.BASE_URI || "";
234
+ if (baseUri.includes("-dev.")) {
235
+ return `https://connect-dev.powerhouse.xyz/?driveUrl=https://switchboard-dev.powerhouse.xyz/d/${driveId}`;
236
+ }
237
+ if (baseUri.includes("-staging.")) {
238
+ return `https://connect-staging.powerhouse.xyz/?driveUrl=https://switchboard-staging.powerhouse.xyz/d/${driveId}`;
239
+ }
240
+ if (baseUri && !baseUri.includes("localhost")) {
241
+ return `https://connect.powerhouse.xyz/?driveUrl=https://switchboard.powerhouse.xyz/d/${driveId}`;
242
+ }
243
+ return `http://localhost:3000/?driveUrl=http://localhost:4001/d/${driveId}`;
244
+ }
151
245
  /**
152
246
  * Map ResourceTemplateState from document model to GraphQL response
153
247
  */
@@ -189,6 +283,38 @@ function mapResourceTemplateState(state, doc) {
189
283
  })),
190
284
  };
191
285
  }
286
+ /**
287
+ * Populate a resource-instance document with data from a resource-template.
288
+ * Initializes basic info and sets facet configuration from template facetTargets.
289
+ */
290
+ async function populateResourceInstance(reactor, resourceInstanceDocId, resourceTemplateId, profileId, name) {
291
+ const resourceTemplateDoc = await reactor.getDocument(resourceTemplateId);
292
+ if (!resourceTemplateDoc)
293
+ return;
294
+ const templateState = resourceTemplateDoc.state.global;
295
+ // Initialize instance with basic info from template
296
+ await reactor.addAction(resourceInstanceDocId, ResourceInstance.actions.initializeInstance({
297
+ profileId,
298
+ profileDocumentType: "powerhouse/builder-profile",
299
+ resourceTemplateId,
300
+ customerId: null,
301
+ name,
302
+ thumbnailUrl: templateState.thumbnailUrl,
303
+ infoLink: templateState.infoLink,
304
+ description: templateState.description,
305
+ }));
306
+ // Populate facet configuration from template's facetTargets
307
+ for (const facetTarget of templateState.facetTargets) {
308
+ if (facetTarget.selectedOptions.length > 0) {
309
+ await reactor.addAction(resourceInstanceDocId, ResourceInstance.actions.setInstanceFacet({
310
+ id: facetTarget.id,
311
+ categoryKey: facetTarget.categoryKey,
312
+ categoryLabel: facetTarget.categoryLabel,
313
+ selectedOption: facetTarget.selectedOptions[0],
314
+ }));
315
+ }
316
+ }
317
+ }
192
318
  /**
193
319
  * Map ServiceOfferingState from document model to GraphQL response
194
320
  */
@@ -289,3 +415,12 @@ function mapServiceOfferingState(state, doc) {
289
415
  })),
290
416
  };
291
417
  }
418
+ async function getOperatorDrive(reactor, resourceTemplateId) {
419
+ const drives = await reactor.getDrives();
420
+ const results = await Promise.all(drives.map(async (drive) => {
421
+ const docIds = await reactor.getDocuments(drive);
422
+ return docIds.includes(resourceTemplateId) ? drive : null;
423
+ }));
424
+ const driveId = results.find((id) => id !== null);
425
+ return driveId ? reactor.getDrive(driveId) : undefined;
426
+ }
@@ -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,YAmOpB,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,YAmPpB,CAAC"}
@@ -8,6 +8,22 @@ export const schema = gql `
8
8
  serviceOfferings(filter: RSServiceOfferingsFilter): [RSServiceOffering!]!
9
9
  }
10
10
 
11
+ type Mutation {
12
+ createResourceInstances(input: CreateResourceInstancesInput!): CreateResourceInstancesOutput
13
+ }
14
+
15
+ input CreateResourceInstancesInput {
16
+ resourceTemplateId: PHID!
17
+ name: String!
18
+ teamName: String!
19
+ }
20
+
21
+ type CreateResourceInstancesOutput {
22
+ success: Boolean!
23
+ data: JSONObject
24
+ errors: [String!]!
25
+ }
26
+
11
27
  # ============ Filters ============
12
28
 
13
29
  input RSResourceTemplatesFilter {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/contributor-billing",
3
3
  "description": "Document models that help contributors of open organisations get paid anonymously for their work on a monthly basis.",
4
- "version": "0.1.50",
4
+ "version": "0.1.51",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
7
7
  "files": [