@m5kdev/backend 0.5.0 → 0.7.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.
Files changed (53) hide show
  1. package/dist/src/modules/ai/ai.service.d.ts +11 -13
  2. package/dist/src/modules/ai/ai.service.js +6 -6
  3. package/dist/src/modules/ai/ai.trpc.d.ts +1 -1
  4. package/dist/src/modules/auth/auth.lib.d.ts +8 -12
  5. package/dist/src/modules/auth/auth.lib.js +2 -2
  6. package/dist/src/modules/auth/auth.service.d.ts +17 -47
  7. package/dist/src/modules/auth/auth.service.js +79 -66
  8. package/dist/src/modules/auth/auth.trpc.d.ts +16 -16
  9. package/dist/src/modules/base/base.abstract.d.ts +3 -2
  10. package/dist/src/modules/base/base.abstract.js +10 -1
  11. package/dist/src/modules/base/base.actor.d.ts +68 -0
  12. package/dist/src/modules/base/base.actor.js +99 -0
  13. package/dist/src/modules/base/base.actor.test.d.ts +1 -0
  14. package/dist/src/modules/base/base.actor.test.js +58 -0
  15. package/dist/src/modules/base/base.grants.d.ts +3 -7
  16. package/dist/src/modules/base/base.grants.js +22 -10
  17. package/dist/src/modules/base/base.grants.test.js +16 -45
  18. package/dist/src/modules/base/base.procedure.d.ts +109 -0
  19. package/dist/src/modules/base/base.procedure.js +301 -0
  20. package/dist/src/modules/base/base.repository.d.ts +1 -0
  21. package/dist/src/modules/base/base.repository.js +12 -2
  22. package/dist/src/modules/base/base.service.d.ts +23 -23
  23. package/dist/src/modules/base/base.service.js +26 -12
  24. package/dist/src/modules/base/base.service.test.d.ts +1 -0
  25. package/dist/src/modules/base/base.service.test.js +443 -0
  26. package/dist/src/modules/billing/billing.service.d.ts +4 -25
  27. package/dist/src/modules/billing/billing.service.js +6 -6
  28. package/dist/src/modules/billing/billing.trpc.d.ts +2 -2
  29. package/dist/src/modules/billing/billing.trpc.js +4 -6
  30. package/dist/src/modules/connect/connect.repository.d.ts +3 -3
  31. package/dist/src/modules/connect/connect.service.d.ts +21 -13
  32. package/dist/src/modules/connect/connect.service.js +10 -8
  33. package/dist/src/modules/connect/connect.trpc.d.ts +2 -2
  34. package/dist/src/modules/recurrence/recurrence.service.d.ts +59 -8
  35. package/dist/src/modules/recurrence/recurrence.service.js +16 -14
  36. package/dist/src/modules/recurrence/recurrence.trpc.d.ts +3 -3
  37. package/dist/src/modules/recurrence/recurrence.trpc.js +1 -1
  38. package/dist/src/modules/social/social.service.d.ts +3 -4
  39. package/dist/src/modules/social/social.service.js +3 -3
  40. package/dist/src/modules/tag/tag.repository.js +27 -26
  41. package/dist/src/modules/tag/tag.service.d.ts +90 -15
  42. package/dist/src/modules/tag/tag.service.js +20 -12
  43. package/dist/src/modules/tag/tag.trpc.d.ts +3 -3
  44. package/dist/src/modules/workflow/workflow.service.d.ts +48 -8
  45. package/dist/src/modules/workflow/workflow.service.js +6 -6
  46. package/dist/src/modules/workflow/workflow.trpc.d.ts +2 -2
  47. package/dist/src/types.d.ts +19 -19
  48. package/dist/src/utils/trpc.d.ts +31 -41
  49. package/dist/src/utils/trpc.js +95 -0
  50. package/dist/src/utils/trpc.test.d.ts +1 -0
  51. package/dist/src/utils/trpc.test.js +154 -0
  52. package/dist/tsconfig.tsbuildinfo +1 -1
  53. package/package.json +3 -3
@@ -0,0 +1,443 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const neverthrow_1 = require("neverthrow");
4
+ const errors_1 = require("../../utils/errors");
5
+ const base_actor_1 = require("./base.actor");
6
+ const base_service_1 = require("./base.service");
7
+ function createActor(overrides = {}) {
8
+ const actor = (0, base_actor_1.createServiceActor)({
9
+ userId: "user-1",
10
+ userRole: "member",
11
+ organizationId: null,
12
+ organizationRole: null,
13
+ teamId: null,
14
+ teamRole: null,
15
+ ...overrides,
16
+ });
17
+ if (!actor) {
18
+ throw new Error("Expected actor");
19
+ }
20
+ return actor;
21
+ }
22
+ function createOrganizationActor(overrides = {}) {
23
+ return createActor({
24
+ organizationId: "org-1",
25
+ organizationRole: "owner",
26
+ ...overrides,
27
+ });
28
+ }
29
+ function createTeamActor(overrides = {}) {
30
+ return createActor({
31
+ organizationId: "org-1",
32
+ organizationRole: "owner",
33
+ teamId: "team-1",
34
+ teamRole: "member",
35
+ ...overrides,
36
+ });
37
+ }
38
+ describe("BaseService procedure builder", () => {
39
+ it("runs chained steps in order and exposes state by step name", async () => {
40
+ const events = [];
41
+ class PipelineService extends base_service_1.BaseService {
42
+ run = this.procedure("run")
43
+ .use("trimmed", ({ input }) => {
44
+ events.push("trimmed");
45
+ return input.value.trim();
46
+ })
47
+ .use("upper", ({ state }) => {
48
+ events.push("upper");
49
+ return state.trimmed.toUpperCase();
50
+ })
51
+ .handle(({ state }) => {
52
+ events.push("handler");
53
+ return (0, neverthrow_1.ok)({
54
+ trimmed: state.trimmed,
55
+ upper: state.upper,
56
+ });
57
+ });
58
+ }
59
+ const service = new PipelineService();
60
+ const result = await service.run({ value: " hello " }, {});
61
+ expect(result.isOk()).toBe(true);
62
+ if (result.isOk()) {
63
+ expect(result.value).toEqual({
64
+ trimmed: "hello",
65
+ upper: "HELLO",
66
+ });
67
+ }
68
+ expect(events).toEqual(["trimmed", "upper", "handler"]);
69
+ });
70
+ it("addContextFilter wraps auth and maps query input with the default step name", async () => {
71
+ class QueryService extends base_service_1.BaseService {
72
+ run = this.procedure("run")
73
+ .addContextFilter(["user", "organization"])
74
+ .handle(({ input, state }) => (0, neverthrow_1.ok)({
75
+ input,
76
+ stateMatches: state.contextFilter === input,
77
+ }));
78
+ }
79
+ const service = new QueryService();
80
+ const unauthorized = await service.run({ search: "hello" }, {});
81
+ expect(unauthorized.isErr()).toBe(true);
82
+ if (unauthorized.isErr()) {
83
+ expect(unauthorized.error.code).toBe("UNAUTHORIZED");
84
+ }
85
+ const authorized = await service.run({ search: "hello" }, {
86
+ actor: createOrganizationActor(),
87
+ });
88
+ expect(authorized.isOk()).toBe(true);
89
+ if (authorized.isOk()) {
90
+ expect(authorized.value.input.search).toBe("hello");
91
+ expect(authorized.value.stateMatches).toBe(true);
92
+ expect(authorized.value.input.filters).toEqual([
93
+ {
94
+ columnId: "userId",
95
+ type: "string",
96
+ method: "equals",
97
+ value: "user-1",
98
+ },
99
+ {
100
+ columnId: "organizationId",
101
+ type: "string",
102
+ method: "equals",
103
+ value: "org-1",
104
+ },
105
+ ]);
106
+ }
107
+ });
108
+ it("addContextFilter returns FORBIDDEN when the actor scope is too small", async () => {
109
+ class QueryService extends base_service_1.BaseService {
110
+ run = this.procedure("run")
111
+ .addContextFilter(["organization"])
112
+ .handle(({ input }) => (0, neverthrow_1.ok)(input));
113
+ }
114
+ const service = new QueryService();
115
+ const result = await service.run({ search: "hello" }, {
116
+ actor: createActor(),
117
+ });
118
+ expect(result.isErr()).toBe(true);
119
+ if (result.isErr()) {
120
+ expect(result.error.code).toBe("FORBIDDEN");
121
+ }
122
+ });
123
+ it("mapInput updates the input seen by later steps and the handler", async () => {
124
+ class QueryService extends base_service_1.BaseService {
125
+ run = this.procedure("run")
126
+ .requireAuth()
127
+ .mapInput("scopedQuery", ({ input, ctx }) => this.addContextFilter(ctx.actor, { user: true, organization: true, team: true }, input, {
128
+ userId: {
129
+ columnId: "authorUserId",
130
+ method: "equals",
131
+ },
132
+ organizationId: {
133
+ columnId: "organizationId",
134
+ method: "equals",
135
+ },
136
+ teamId: {
137
+ columnId: "teamId",
138
+ method: "equals",
139
+ },
140
+ }))
141
+ .use("filterCount", ({ input }) => input.filters?.length ?? 0)
142
+ .handle(({ input, state }) => (0, neverthrow_1.ok)({
143
+ input,
144
+ filterCount: state.filterCount,
145
+ scopedInputMatches: state.scopedQuery === input,
146
+ }));
147
+ }
148
+ const service = new QueryService();
149
+ const result = await service.run({ search: "hello" }, {
150
+ actor: createTeamActor(),
151
+ });
152
+ expect(result.isOk()).toBe(true);
153
+ if (result.isOk()) {
154
+ expect(result.value.input.search).toBe("hello");
155
+ expect(result.value.filterCount).toBe(3);
156
+ expect(result.value.scopedInputMatches).toBe(true);
157
+ expect(result.value.input.filters).toEqual([
158
+ {
159
+ columnId: "authorUserId",
160
+ type: "string",
161
+ method: "equals",
162
+ value: "user-1",
163
+ },
164
+ {
165
+ columnId: "organizationId",
166
+ type: "string",
167
+ method: "equals",
168
+ value: "org-1",
169
+ },
170
+ {
171
+ columnId: "teamId",
172
+ type: "string",
173
+ method: "equals",
174
+ value: "team-1",
175
+ },
176
+ ]);
177
+ }
178
+ });
179
+ it("uses the base service default context type for procedures", async () => {
180
+ class ContextService extends base_service_1.BaseService {
181
+ run = this.procedure("run")
182
+ .requireAuth()
183
+ .handle(({ input, ctx }) => (0, neverthrow_1.ok)(`${ctx.requestId}:${ctx.actor.userId}:${input.value}`));
184
+ }
185
+ const service = new ContextService();
186
+ const result = await service.run({ value: "ok" }, {
187
+ requestId: "req-1",
188
+ actor: createActor(),
189
+ });
190
+ expect(result.isOk()).toBe(true);
191
+ if (result.isOk()) {
192
+ expect(result.value).toBe("req-1:user-1:ok");
193
+ }
194
+ });
195
+ it("requireAuth rejects missing auth context", async () => {
196
+ class ProtectedService extends base_service_1.BaseService {
197
+ run = this.procedure("run")
198
+ .requireAuth()
199
+ .handle(({ input, ctx }) => (0, neverthrow_1.ok)(`${ctx.actor.userId}:${input.value}`));
200
+ }
201
+ const service = new ProtectedService();
202
+ const result = await service.run({ value: "x" }, {});
203
+ expect(result.isErr()).toBe(true);
204
+ if (result.isErr()) {
205
+ expect(result.error.code).toBe("UNAUTHORIZED");
206
+ }
207
+ });
208
+ it("requireAuth allows valid context", async () => {
209
+ class ProtectedService extends base_service_1.BaseService {
210
+ run = this.procedure("run")
211
+ .requireAuth()
212
+ .handle(({ input, ctx }) => (0, neverthrow_1.ok)(`${ctx.actor.userId}:${input.value}`));
213
+ }
214
+ const service = new ProtectedService();
215
+ const result = await service.run({ value: "ok" }, { actor: createActor() });
216
+ expect(result.isOk()).toBe(true);
217
+ if (result.isOk()) {
218
+ expect(result.value).toBe("user-1:ok");
219
+ }
220
+ });
221
+ it("requireAuth accepts organization actors for organization scope", async () => {
222
+ class ProtectedService extends base_service_1.BaseService {
223
+ run = this.procedure("run")
224
+ .requireAuth("organization")
225
+ .handle(({ ctx }) => (0, neverthrow_1.ok)(ctx.actor.organizationId));
226
+ }
227
+ const service = new ProtectedService();
228
+ const result = await service.run(undefined, {
229
+ actor: createOrganizationActor(),
230
+ });
231
+ expect(result.isOk()).toBe(true);
232
+ if (result.isOk()) {
233
+ expect(result.value).toBe("org-1");
234
+ }
235
+ });
236
+ it("requireAuth rejects actors without the requested team scope", async () => {
237
+ class ProtectedService extends base_service_1.BaseService {
238
+ run = this.procedure("run")
239
+ .requireAuth("team")
240
+ .handle(({ ctx }) => (0, neverthrow_1.ok)(ctx.actor.teamId));
241
+ }
242
+ const service = new ProtectedService();
243
+ const result = await service.run(undefined, {
244
+ actor: createOrganizationActor(),
245
+ });
246
+ expect(result.isErr()).toBe(true);
247
+ if (result.isErr()) {
248
+ expect(result.error.code).toBe("FORBIDDEN");
249
+ }
250
+ });
251
+ it("normalizes thrown async errors through throwableAsync", async () => {
252
+ class ThrowingService extends base_service_1.BaseService {
253
+ run = this.procedure("run").handle(async () => {
254
+ throw new Error("boom");
255
+ });
256
+ }
257
+ const service = new ThrowingService();
258
+ const result = await service.run(undefined, {});
259
+ expect(result.isErr()).toBe(true);
260
+ if (result.isErr()) {
261
+ expect(result.error.code).toBe("INTERNAL_SERVER_ERROR");
262
+ expect(result.error.cause).toBeInstanceOf(Error);
263
+ }
264
+ });
265
+ it("logs metadata stages without input or context payloads", async () => {
266
+ class LoggedService extends base_service_1.BaseService {
267
+ run = this.procedure("run")
268
+ .requireAuth()
269
+ .handle(({ ctx }) => (0, neverthrow_1.ok)(ctx.actor.userId));
270
+ }
271
+ const service = new LoggedService();
272
+ const debugSpy = jest.fn();
273
+ service.logger.debug = debugSpy;
274
+ const result = await service.run({ secret: "top-secret" }, {
275
+ actor: createActor(),
276
+ token: "super-token",
277
+ });
278
+ expect(result.isOk()).toBe(true);
279
+ expect(debugSpy).toHaveBeenCalledTimes(3);
280
+ const payloads = debugSpy.mock.calls.map(([payload]) => payload);
281
+ expect(payloads.map((payload) => payload.stage)).toEqual(["start", "auth_passed", "success"]);
282
+ const serializedPayloads = JSON.stringify(payloads);
283
+ expect(serializedPayloads).not.toContain("top-secret");
284
+ expect(serializedPayloads).not.toContain("super-token");
285
+ expect(payloads.every((payload) => "hasActor" in payload)).toBe(true);
286
+ expect(payloads.every((payload) => !("input" in payload))).toBe(true);
287
+ expect(payloads.every((payload) => !("ctx" in payload))).toBe(true);
288
+ });
289
+ });
290
+ describe("BasePermissionService procedure builder", () => {
291
+ it("passes loaded entities into the handler when access is granted", async () => {
292
+ const grants = [
293
+ {
294
+ action: "read",
295
+ level: "user",
296
+ role: "member",
297
+ access: "own",
298
+ },
299
+ ];
300
+ class PermissionService extends base_service_1.BasePermissionService {
301
+ constructor() {
302
+ super({}, {}, grants);
303
+ }
304
+ run = this.procedure("run")
305
+ .access({
306
+ action: "read",
307
+ entities: ({ input }) => ({
308
+ userId: input.ownerId,
309
+ }),
310
+ })
311
+ .handle(({ state }) => (0, neverthrow_1.ok)(state.access?.userId ?? null));
312
+ }
313
+ const service = new PermissionService();
314
+ const result = await service.run({ ownerId: "user-1" }, { actor: createActor() });
315
+ expect(result.isOk()).toBe(true);
316
+ if (result.isOk()) {
317
+ expect(result.value).toBe("user-1");
318
+ }
319
+ });
320
+ it("reuses a typed state step directly when entityStep is provided", async () => {
321
+ const grants = [
322
+ {
323
+ action: "read",
324
+ level: "user",
325
+ role: "member",
326
+ access: "own",
327
+ },
328
+ ];
329
+ class PermissionService extends base_service_1.BasePermissionService {
330
+ constructor() {
331
+ super({}, {}, grants);
332
+ }
333
+ run = this.procedure("run")
334
+ .use("record", ({ input }) => (0, neverthrow_1.ok)({
335
+ id: "resource-1",
336
+ userId: input.ownerId,
337
+ teamId: null,
338
+ organizationId: null,
339
+ }))
340
+ .access({
341
+ action: "read",
342
+ entityStep: "record",
343
+ })
344
+ .handle(({ state }) => (0, neverthrow_1.ok)(state.access === state.record));
345
+ }
346
+ const service = new PermissionService();
347
+ const result = await service.run({ ownerId: "user-1" }, { actor: createActor() });
348
+ expect(result.isOk()).toBe(true);
349
+ if (result.isOk()) {
350
+ expect(result.value).toBe(true);
351
+ }
352
+ });
353
+ it("returns FORBIDDEN when access validation fails", async () => {
354
+ const grants = [
355
+ {
356
+ action: "read",
357
+ level: "user",
358
+ role: "member",
359
+ access: "own",
360
+ },
361
+ ];
362
+ class PermissionService extends base_service_1.BasePermissionService {
363
+ constructor() {
364
+ super({}, {}, grants);
365
+ }
366
+ run = this.procedure("run")
367
+ .access({
368
+ action: "read",
369
+ entities: ({ input }) => ({
370
+ userId: input.ownerId,
371
+ }),
372
+ })
373
+ .handle(() => (0, neverthrow_1.ok)("allowed"));
374
+ }
375
+ const service = new PermissionService();
376
+ const result = await service.run({ ownerId: "other-user" }, { actor: createActor() });
377
+ expect(result.isErr()).toBe(true);
378
+ if (result.isErr()) {
379
+ expect(result.error.code).toBe("FORBIDDEN");
380
+ }
381
+ });
382
+ it("propagates entity loader failures through access", async () => {
383
+ const grants = [
384
+ {
385
+ action: "read",
386
+ level: "user",
387
+ role: "member",
388
+ access: "own",
389
+ },
390
+ ];
391
+ class PermissionService extends base_service_1.BasePermissionService {
392
+ constructor() {
393
+ super({}, {}, grants);
394
+ }
395
+ run = this.procedure("run")
396
+ .access({
397
+ action: "read",
398
+ entities: async () => (0, neverthrow_1.err)(new errors_1.ServerError({
399
+ code: "NOT_FOUND",
400
+ layer: "service",
401
+ layerName: "PermissionService",
402
+ message: "Missing entity",
403
+ })),
404
+ })
405
+ .handle(() => (0, neverthrow_1.ok)("allowed"));
406
+ }
407
+ const service = new PermissionService();
408
+ const result = await service.run({ ownerId: "user-1" }, { actor: createActor() });
409
+ expect(result.isErr()).toBe(true);
410
+ if (result.isErr()) {
411
+ expect(result.error.code).toBe("INTERNAL_SERVER_ERROR");
412
+ }
413
+ });
414
+ it("skips entity loading when grants already allow all access", async () => {
415
+ const grants = [
416
+ {
417
+ action: "read",
418
+ level: "user",
419
+ role: "member",
420
+ access: "all",
421
+ },
422
+ ];
423
+ const resolveEntity = jest.fn(async () => ({ userId: "user-1" }));
424
+ class PermissionService extends base_service_1.BasePermissionService {
425
+ constructor() {
426
+ super({}, {}, grants);
427
+ }
428
+ run = this.procedure("run")
429
+ .access({
430
+ action: "read",
431
+ entities: resolveEntity,
432
+ })
433
+ .handle(() => (0, neverthrow_1.ok)("allowed"));
434
+ }
435
+ const service = new PermissionService();
436
+ const result = await service.run({ ownerId: "other-user" }, { actor: createActor() });
437
+ expect(result.isOk()).toBe(true);
438
+ if (result.isOk()) {
439
+ expect(result.value).toBe("allowed");
440
+ }
441
+ expect(resolveEntity).not.toHaveBeenCalled();
442
+ });
443
+ });
@@ -1,6 +1,8 @@
1
+ import type { BillingSchema } from "@m5kdev/commons/modules/billing/billing.schema";
1
2
  import type Stripe from "stripe";
2
3
  import type { User } from "../auth/auth.lib";
3
4
  import type { ServerResult, ServerResultAsync } from "../base/base.dto";
5
+ import type { Context } from "../../utils/trpc";
4
6
  import { BaseService } from "../base/base.service";
5
7
  import type { BillingRepository } from "./billing.repository";
6
8
  export declare class BillingService extends BaseService<{
@@ -20,31 +22,8 @@ export declare class BillingService extends BaseService<{
20
22
  name?: string;
21
23
  };
22
24
  }): ServerResultAsync<boolean>;
23
- getActiveSubscription({ user }: {
24
- user: User;
25
- }): Promise<ServerResult<{
26
- id: string;
27
- plan: string;
28
- referenceId: string;
29
- status: string;
30
- stripeCustomerId?: string | null | undefined;
31
- stripeSubscriptionId?: string | null | undefined;
32
- periodStart?: Date | null | undefined;
33
- periodEnd?: Date | null | undefined;
34
- cancelAtPeriodEnd?: boolean | null | undefined;
35
- cancelAt?: Date | null | undefined;
36
- canceledAt?: Date | null | undefined;
37
- seats?: number | null | undefined;
38
- trialStart?: Date | null | undefined;
39
- trialEnd?: Date | null | undefined;
40
- priceId?: string | null | undefined;
41
- interval?: string | null | undefined;
42
- unitAmount?: number | null | undefined;
43
- discounts?: string[] | null | undefined;
44
- } | null>>;
45
- listInvoices({ user }: {
46
- user: User;
47
- }): ServerResultAsync<Stripe.Invoice[]>;
25
+ getActiveSubscription(ctx: Context): ServerResultAsync<BillingSchema | null>;
26
+ listInvoices(ctx: Context): ServerResultAsync<Stripe.Invoice[]>;
48
27
  createCheckoutSession({ priceId }: {
49
28
  priceId: string;
50
29
  }, { user }: {
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BillingService = void 0;
4
4
  const neverthrow_1 = require("neverthrow");
5
- const base_service_1 = require("../base/base.service");
6
5
  const posthog_1 = require("../../utils/posthog");
6
+ const base_service_1 = require("../base/base.service");
7
7
  const allowedEvents = [
8
8
  "checkout.session.completed",
9
9
  "customer.subscription.created",
@@ -72,13 +72,13 @@ class BillingService extends base_service_1.BaseService {
72
72
  }
73
73
  return (0, neverthrow_1.ok)(true);
74
74
  }
75
- async getActiveSubscription({ user }) {
76
- return this.repository.billing.getActiveSubscription(user.id);
75
+ async getActiveSubscription(ctx) {
76
+ return this.repository.billing.getActiveSubscription(ctx.actor.userId);
77
77
  }
78
- async listInvoices({ user }) {
79
- if (!user.stripeCustomerId)
78
+ async listInvoices(ctx) {
79
+ if (!ctx.user.stripeCustomerId)
80
80
  return this.error("NOT_FOUND", "User has no stripe customer id");
81
- return this.repository.billing.listInvoices(user.stripeCustomerId);
81
+ return this.repository.billing.listInvoices(ctx.user.stripeCustomerId);
82
82
  }
83
83
  async createCheckoutSession({ priceId }, { user }) {
84
84
  let stripeCustomerId = user.stripeCustomerId;
@@ -1,7 +1,7 @@
1
- import type { BillingService } from "./billing.service";
2
1
  import { type TRPCMethods } from "../../utils/trpc";
2
+ import type { BillingService } from "./billing.service";
3
3
  export declare function createBillingTRPC({ router, privateProcedure: procedure }: TRPCMethods, billingService: BillingService): import("@trpc/server").TRPCBuiltRouter<{
4
- ctx: import("../auth/auth.lib").Context;
4
+ ctx: import("../../utils/trpc").Context;
5
5
  meta: any;
6
6
  errorShape: import("@trpc/server").TRPCDefaultErrorShape;
7
7
  transformer: true;
@@ -5,13 +5,11 @@ const billing_schema_1 = require("@m5kdev/commons/modules/billing/billing.schema
5
5
  const trpc_1 = require("../../utils/trpc");
6
6
  function createBillingTRPC({ router, privateProcedure: procedure }, billingService) {
7
7
  return router({
8
- getActiveSubscription: procedure
9
- .output(billing_schema_1.billingSchema.nullable())
10
- .query(async ({ ctx: { user } }) => {
11
- return (0, trpc_1.handleTRPCResult)(await billingService.getActiveSubscription({ user }));
8
+ getActiveSubscription: procedure.output(billing_schema_1.billingSchema.nullable()).query(async ({ ctx }) => {
9
+ return (0, trpc_1.handleTRPCResult)(await billingService.getActiveSubscription(ctx));
12
10
  }),
13
- listInvoices: procedure.query(async ({ ctx: { user } }) => {
14
- return (0, trpc_1.handleTRPCResult)(await billingService.listInvoices({ user }));
11
+ listInvoices: procedure.query(async ({ ctx }) => {
12
+ return (0, trpc_1.handleTRPCResult)(await billingService.listInvoices(ctx));
15
13
  }),
16
14
  });
17
15
  }
@@ -389,22 +389,22 @@ export declare class ConnectRepository extends BaseTableRepository<Orm, Schema,
389
389
  updatedAt: Date | null;
390
390
  }[]>>;
391
391
  upsert(data: ConnectInsert, tx?: Orm): Promise<import("../base/base.dto").ServerResult<{
392
- provider: string;
393
392
  id: string;
394
393
  createdAt: Date;
395
394
  updatedAt: Date | null;
396
- userId: string;
397
395
  expiresAt: Date | null;
396
+ userId: string;
397
+ parentId: string | null;
398
398
  accessToken: string;
399
399
  refreshToken: string | null;
400
400
  scope: string | null;
401
+ provider: string;
401
402
  accountType: string;
402
403
  providerAccountId: string;
403
404
  handle: string | null;
404
405
  displayName: string | null;
405
406
  avatarUrl: string | null;
406
407
  tokenType: string | null;
407
- parentId: string | null;
408
408
  metadataJson: unknown;
409
409
  revokedAt: Date | null;
410
410
  lastRefreshedAt: Date | null;
@@ -1,7 +1,6 @@
1
1
  import type { User } from "../auth/auth.lib";
2
2
  import type { ServerResultAsync } from "../base/base.dto";
3
3
  import { BaseService } from "../base/base.service";
4
- import type { ConnectDeleteInputSchema, ConnectListInputSchema } from "./connect.dto";
5
4
  import type { ConnectRepository } from "./connect.repository";
6
5
  import type { ConnectProvider } from "./connect.types";
7
6
  export declare class ConnectService extends BaseService<{
@@ -16,15 +15,15 @@ export declare class ConnectService extends BaseService<{
16
15
  url: string;
17
16
  }>;
18
17
  handleCallback(user: User, sessionId: string, providerId: string, code: string, state: string): Promise<import("../base/base.dto").ServerResult<{
19
- provider: string;
20
18
  id: string;
21
19
  createdAt: Date;
22
20
  updatedAt: Date | null;
23
- userId: string;
24
21
  expiresAt: Date | null;
22
+ userId: string;
25
23
  accessToken: string;
26
24
  refreshToken: string | null;
27
25
  scope: string | null;
26
+ provider: string;
28
27
  accountType: string;
29
28
  providerAccountId: string;
30
29
  handle: string | null;
@@ -37,15 +36,15 @@ export declare class ConnectService extends BaseService<{
37
36
  lastRefreshedAt: Date | null;
38
37
  }>>;
39
38
  refreshToken(connectionId: string): Promise<import("../base/base.dto").ServerResult<{
40
- provider: string;
41
39
  id: string;
42
40
  createdAt: Date;
43
41
  updatedAt: Date | null;
44
- userId: string;
45
42
  expiresAt: Date | null;
43
+ userId: string;
46
44
  accessToken: string;
47
45
  refreshToken: string | null;
48
46
  scope: string | null;
47
+ provider: string;
49
48
  accountType: string;
50
49
  providerAccountId: string;
51
50
  handle: string | null;
@@ -57,9 +56,14 @@ export declare class ConnectService extends BaseService<{
57
56
  revokedAt: Date | null;
58
57
  lastRefreshedAt: Date | null;
59
58
  }>>;
60
- list(input: ConnectListInputSchema, { user }: {
61
- user: User;
62
- }): Promise<import("../base/base.dto").ServerResult<{
59
+ readonly list: import("../base/base.procedure").ServiceProcedure<{
60
+ providers?: string[] | undefined;
61
+ inactive?: boolean | undefined;
62
+ }, {
63
+ actor?: import("../base/base.actor").AuthenticatedActor | null;
64
+ } & Record<string, unknown> & {
65
+ actor: import("../base/base.actor").UserActor;
66
+ }, {
63
67
  id: string;
64
68
  userId: string;
65
69
  provider: string;
@@ -79,10 +83,14 @@ export declare class ConnectService extends BaseService<{
79
83
  lastRefreshedAt: Date | null;
80
84
  createdAt: Date;
81
85
  updatedAt: Date | null;
82
- }[]>>;
83
- delete({ id }: ConnectDeleteInputSchema, { user }: {
84
- user: User;
85
- }): Promise<import("../base/base.dto").ServerResult<{
86
+ }[]>;
87
+ readonly delete: import("../base/base.procedure").ServiceProcedure<{
86
88
  id: string;
87
- }>>;
89
+ }, {
90
+ actor?: import("../base/base.actor").AuthenticatedActor | null;
91
+ } & Record<string, unknown> & {
92
+ actor: import("../base/base.actor").UserActor;
93
+ }, {
94
+ id: string;
95
+ }>;
88
96
  }
@@ -97,18 +97,20 @@ class ConnectService extends base_service_1.BaseService {
97
97
  return (0, neverthrow_1.ok)(updated.value);
98
98
  });
99
99
  }
100
- async list(input, { user }) {
101
- return this.repository.connect.list({ userId: user.id, ...input });
102
- }
103
- async delete({ id }, { user }) {
104
- const connection = await this.repository.connect.findById(id);
100
+ list = this.procedure("connectList")
101
+ .requireAuth()
102
+ .handle(({ input, ctx }) => this.repository.connect.list({ userId: ctx.actor.userId, ...input }));
103
+ delete = this.procedure("connectDelete")
104
+ .requireAuth()
105
+ .handle(async ({ input, ctx }) => {
106
+ const connection = await this.repository.connect.findById(input.id);
105
107
  if (connection.isOk()) {
106
- if (connection.value?.userId !== user.id) {
108
+ if (connection.value?.userId !== ctx.actor.userId) {
107
109
  return this.error("FORBIDDEN", "Not your connection");
108
110
  }
109
- return this.repository.connect.deleteById(id);
111
+ return this.repository.connect.deleteById(input.id);
110
112
  }
111
113
  return (0, neverthrow_1.err)(connection.error);
112
- }
114
+ });
113
115
  }
114
116
  exports.ConnectService = ConnectService;