@m5kdev/backend 0.6.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.
- package/dist/src/modules/ai/ai.service.d.ts +11 -13
- package/dist/src/modules/ai/ai.service.js +6 -6
- package/dist/src/modules/ai/ai.trpc.d.ts +1 -1
- package/dist/src/modules/auth/auth.lib.d.ts +4 -8
- package/dist/src/modules/auth/auth.lib.js +2 -2
- package/dist/src/modules/auth/auth.service.d.ts +17 -47
- package/dist/src/modules/auth/auth.service.js +79 -66
- package/dist/src/modules/auth/auth.trpc.d.ts +1 -1
- package/dist/src/modules/base/base.actor.d.ts +68 -0
- package/dist/src/modules/base/base.actor.js +99 -0
- package/dist/src/modules/base/base.actor.test.d.ts +1 -0
- package/dist/src/modules/base/base.actor.test.js +58 -0
- package/dist/src/modules/base/base.grants.d.ts +3 -7
- package/dist/src/modules/base/base.grants.js +22 -10
- package/dist/src/modules/base/base.grants.test.js +16 -45
- package/dist/src/modules/base/base.procedure.d.ts +17 -20
- package/dist/src/modules/base/base.procedure.js +36 -24
- package/dist/src/modules/base/base.service.d.ts +7 -19
- package/dist/src/modules/base/base.service.js +19 -12
- package/dist/src/modules/base/base.service.test.js +89 -61
- package/dist/src/modules/billing/billing.service.d.ts +4 -25
- package/dist/src/modules/billing/billing.service.js +6 -6
- package/dist/src/modules/billing/billing.trpc.d.ts +2 -2
- package/dist/src/modules/billing/billing.trpc.js +4 -6
- package/dist/src/modules/connect/connect.service.d.ts +19 -11
- package/dist/src/modules/connect/connect.service.js +10 -8
- package/dist/src/modules/connect/connect.trpc.d.ts +2 -2
- package/dist/src/modules/recurrence/recurrence.service.d.ts +36 -6
- package/dist/src/modules/recurrence/recurrence.service.js +13 -10
- package/dist/src/modules/recurrence/recurrence.trpc.d.ts +1 -1
- package/dist/src/modules/social/social.service.d.ts +3 -4
- package/dist/src/modules/social/social.service.js +3 -3
- package/dist/src/modules/tag/tag.service.d.ts +16 -12
- package/dist/src/modules/tag/tag.service.js +4 -4
- package/dist/src/modules/tag/tag.trpc.d.ts +1 -1
- package/dist/src/modules/workflow/workflow.service.d.ts +48 -8
- package/dist/src/modules/workflow/workflow.service.js +6 -6
- package/dist/src/modules/workflow/workflow.trpc.d.ts +2 -2
- package/dist/src/types.d.ts +4 -4
- package/dist/src/utils/trpc.d.ts +31 -41
- package/dist/src/utils/trpc.js +95 -0
- package/dist/src/utils/trpc.test.d.ts +1 -0
- package/dist/src/utils/trpc.test.js +154 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.BasePermissionService = exports.BaseService = void 0;
|
|
4
4
|
const neverthrow_1 = require("neverthrow");
|
|
5
5
|
const base_abstract_1 = require("./base.abstract");
|
|
6
|
+
const base_actor_1 = require("./base.actor");
|
|
6
7
|
const base_grants_1 = require("./base.grants");
|
|
7
8
|
const base_procedure_1 = require("./base.procedure");
|
|
8
9
|
class BaseService extends base_abstract_1.Base {
|
|
@@ -29,7 +30,7 @@ class BaseService extends base_abstract_1.Base {
|
|
|
29
30
|
procedure(name) {
|
|
30
31
|
return (0, base_procedure_1.createServiceProcedureBuilder)(this, { name, steps: [] });
|
|
31
32
|
}
|
|
32
|
-
addContextFilter(
|
|
33
|
+
addContextFilter(actor, include = {
|
|
33
34
|
user: true,
|
|
34
35
|
organization: false,
|
|
35
36
|
team: false,
|
|
@@ -53,23 +54,29 @@ class BaseService extends base_abstract_1.Base {
|
|
|
53
54
|
columnId: map.userId.columnId,
|
|
54
55
|
type: "string",
|
|
55
56
|
method: map.userId.method,
|
|
56
|
-
value:
|
|
57
|
+
value: actor.userId,
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
60
|
if (include.organization) {
|
|
61
|
+
if (!(0, base_actor_1.validateActor)(actor, "organization")) {
|
|
62
|
+
throw new Error("Organization-scoped context filter requires an organization actor");
|
|
63
|
+
}
|
|
60
64
|
filters.push({
|
|
61
65
|
columnId: map.organizationId.columnId,
|
|
62
66
|
type: "string",
|
|
63
67
|
method: map.organizationId.method,
|
|
64
|
-
value:
|
|
68
|
+
value: actor.organizationId,
|
|
65
69
|
});
|
|
66
70
|
}
|
|
67
71
|
if (include.team) {
|
|
72
|
+
if (!(0, base_actor_1.validateActor)(actor, "team")) {
|
|
73
|
+
throw new Error("Team-scoped context filter requires a team actor");
|
|
74
|
+
}
|
|
68
75
|
filters.push({
|
|
69
76
|
columnId: map.teamId.columnId,
|
|
70
77
|
type: "string",
|
|
71
78
|
method: map.teamId.method,
|
|
72
|
-
value:
|
|
79
|
+
value: actor.teamId,
|
|
73
80
|
});
|
|
74
81
|
}
|
|
75
82
|
return query ? { ...query, filters: [...(query?.filters ?? []), ...filters] } : { filters };
|
|
@@ -82,14 +89,14 @@ class BasePermissionService extends BaseService {
|
|
|
82
89
|
super(repository, service);
|
|
83
90
|
this.grants = grants;
|
|
84
91
|
}
|
|
85
|
-
accessGuard(
|
|
86
|
-
const hasPermission = this.checkPermission(
|
|
92
|
+
accessGuard(actor, action, entities, grants) {
|
|
93
|
+
const hasPermission = this.checkPermission(actor, action, entities, grants);
|
|
87
94
|
if (!hasPermission)
|
|
88
95
|
return this.error("FORBIDDEN");
|
|
89
96
|
return (0, neverthrow_1.ok)(true);
|
|
90
97
|
}
|
|
91
|
-
async accessGuardAsync(
|
|
92
|
-
const hasPermission = await this.checkPermissionAsync(
|
|
98
|
+
async accessGuardAsync(actor, action, getEntities, grants) {
|
|
99
|
+
const hasPermission = await this.checkPermissionAsync(actor, action, getEntities, grants);
|
|
93
100
|
if (hasPermission.isErr())
|
|
94
101
|
return (0, neverthrow_1.err)(hasPermission.error);
|
|
95
102
|
if (!hasPermission.value)
|
|
@@ -99,13 +106,13 @@ class BasePermissionService extends BaseService {
|
|
|
99
106
|
procedure(name) {
|
|
100
107
|
return (0, base_procedure_1.createPermissionServiceProcedureBuilder)(this, { name, steps: [] });
|
|
101
108
|
}
|
|
102
|
-
checkPermission(
|
|
109
|
+
checkPermission(actor, action, entities, grants) {
|
|
103
110
|
const actionGrants = grants ?? this.grants.filter((grant) => grant.action === action);
|
|
104
|
-
return (0, base_grants_1.checkPermissionSync)(
|
|
111
|
+
return (0, base_grants_1.checkPermissionSync)(actor, actionGrants, entities);
|
|
105
112
|
}
|
|
106
|
-
async checkPermissionAsync(
|
|
113
|
+
async checkPermissionAsync(actor, action, getEntities, grants) {
|
|
107
114
|
const actionGrants = grants ?? this.grants.filter((grant) => grant.action === action);
|
|
108
|
-
const permission = await (0, base_grants_1.checkPermissionAsync)(
|
|
115
|
+
const permission = await (0, base_grants_1.checkPermissionAsync)(actor, actionGrants, getEntities);
|
|
109
116
|
if (permission.isErr())
|
|
110
117
|
return this.error("INTERNAL_SERVER_ERROR", "Failed to check permission", {
|
|
111
118
|
cause: permission.error,
|
|
@@ -2,47 +2,38 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const neverthrow_1 = require("neverthrow");
|
|
4
4
|
const errors_1 = require("../../utils/errors");
|
|
5
|
+
const base_actor_1 = require("./base.actor");
|
|
5
6
|
const base_service_1 = require("./base.service");
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
banned: false,
|
|
15
|
-
banReason: null,
|
|
16
|
-
banExpires: null,
|
|
17
|
-
emailVerified: true,
|
|
18
|
-
image: null,
|
|
19
|
-
onboarding: null,
|
|
20
|
-
preferences: null,
|
|
21
|
-
flags: null,
|
|
22
|
-
stripeCustomerId: null,
|
|
23
|
-
paymentCustomerId: null,
|
|
24
|
-
paymentPlanTier: null,
|
|
25
|
-
paymentPlanExpiresAt: null,
|
|
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,
|
|
26
15
|
...overrides,
|
|
27
|
-
};
|
|
16
|
+
});
|
|
17
|
+
if (!actor) {
|
|
18
|
+
throw new Error("Expected actor");
|
|
19
|
+
}
|
|
20
|
+
return actor;
|
|
28
21
|
}
|
|
29
|
-
function
|
|
30
|
-
return {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
activeTeamRole: null,
|
|
43
|
-
impersonatedBy: null,
|
|
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",
|
|
44
35
|
...overrides,
|
|
45
|
-
};
|
|
36
|
+
});
|
|
46
37
|
}
|
|
47
38
|
describe("BaseService procedure builder", () => {
|
|
48
39
|
it("runs chained steps in order and exposes state by step name", async () => {
|
|
@@ -92,10 +83,7 @@ describe("BaseService procedure builder", () => {
|
|
|
92
83
|
expect(unauthorized.error.code).toBe("UNAUTHORIZED");
|
|
93
84
|
}
|
|
94
85
|
const authorized = await service.run({ search: "hello" }, {
|
|
95
|
-
|
|
96
|
-
session: createSession({
|
|
97
|
-
activeOrganizationId: "org-1",
|
|
98
|
-
}),
|
|
86
|
+
actor: createOrganizationActor(),
|
|
99
87
|
});
|
|
100
88
|
expect(authorized.isOk()).toBe(true);
|
|
101
89
|
if (authorized.isOk()) {
|
|
@@ -117,11 +105,26 @@ describe("BaseService procedure builder", () => {
|
|
|
117
105
|
]);
|
|
118
106
|
}
|
|
119
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
|
+
});
|
|
120
123
|
it("mapInput updates the input seen by later steps and the handler", async () => {
|
|
121
124
|
class QueryService extends base_service_1.BaseService {
|
|
122
125
|
run = this.procedure("run")
|
|
123
126
|
.requireAuth()
|
|
124
|
-
.mapInput("scopedQuery", ({ input, ctx }) => this.addContextFilter(ctx, { user: true, organization: true, team: true }, input, {
|
|
127
|
+
.mapInput("scopedQuery", ({ input, ctx }) => this.addContextFilter(ctx.actor, { user: true, organization: true, team: true }, input, {
|
|
125
128
|
userId: {
|
|
126
129
|
columnId: "authorUserId",
|
|
127
130
|
method: "equals",
|
|
@@ -144,11 +147,7 @@ describe("BaseService procedure builder", () => {
|
|
|
144
147
|
}
|
|
145
148
|
const service = new QueryService();
|
|
146
149
|
const result = await service.run({ search: "hello" }, {
|
|
147
|
-
|
|
148
|
-
session: createSession({
|
|
149
|
-
activeOrganizationId: "org-1",
|
|
150
|
-
activeTeamId: "team-1",
|
|
151
|
-
}),
|
|
150
|
+
actor: createTeamActor(),
|
|
152
151
|
});
|
|
153
152
|
expect(result.isOk()).toBe(true);
|
|
154
153
|
if (result.isOk()) {
|
|
@@ -181,13 +180,12 @@ describe("BaseService procedure builder", () => {
|
|
|
181
180
|
class ContextService extends base_service_1.BaseService {
|
|
182
181
|
run = this.procedure("run")
|
|
183
182
|
.requireAuth()
|
|
184
|
-
.handle(({ input, ctx }) => (0, neverthrow_1.ok)(`${ctx.requestId}:${ctx.
|
|
183
|
+
.handle(({ input, ctx }) => (0, neverthrow_1.ok)(`${ctx.requestId}:${ctx.actor.userId}:${input.value}`));
|
|
185
184
|
}
|
|
186
185
|
const service = new ContextService();
|
|
187
186
|
const result = await service.run({ value: "ok" }, {
|
|
188
187
|
requestId: "req-1",
|
|
189
|
-
|
|
190
|
-
session: createSession(),
|
|
188
|
+
actor: createActor(),
|
|
191
189
|
});
|
|
192
190
|
expect(result.isOk()).toBe(true);
|
|
193
191
|
if (result.isOk()) {
|
|
@@ -198,7 +196,7 @@ describe("BaseService procedure builder", () => {
|
|
|
198
196
|
class ProtectedService extends base_service_1.BaseService {
|
|
199
197
|
run = this.procedure("run")
|
|
200
198
|
.requireAuth()
|
|
201
|
-
.handle(({ input, ctx }) => (0, neverthrow_1.ok)(`${ctx.
|
|
199
|
+
.handle(({ input, ctx }) => (0, neverthrow_1.ok)(`${ctx.actor.userId}:${input.value}`));
|
|
202
200
|
}
|
|
203
201
|
const service = new ProtectedService();
|
|
204
202
|
const result = await service.run({ value: "x" }, {});
|
|
@@ -211,15 +209,45 @@ describe("BaseService procedure builder", () => {
|
|
|
211
209
|
class ProtectedService extends base_service_1.BaseService {
|
|
212
210
|
run = this.procedure("run")
|
|
213
211
|
.requireAuth()
|
|
214
|
-
.handle(({ input, ctx }) => (0, neverthrow_1.ok)(`${ctx.
|
|
212
|
+
.handle(({ input, ctx }) => (0, neverthrow_1.ok)(`${ctx.actor.userId}:${input.value}`));
|
|
215
213
|
}
|
|
216
214
|
const service = new ProtectedService();
|
|
217
|
-
const result = await service.run({ value: "ok" }, {
|
|
215
|
+
const result = await service.run({ value: "ok" }, { actor: createActor() });
|
|
218
216
|
expect(result.isOk()).toBe(true);
|
|
219
217
|
if (result.isOk()) {
|
|
220
218
|
expect(result.value).toBe("user-1:ok");
|
|
221
219
|
}
|
|
222
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
|
+
});
|
|
223
251
|
it("normalizes thrown async errors through throwableAsync", async () => {
|
|
224
252
|
class ThrowingService extends base_service_1.BaseService {
|
|
225
253
|
run = this.procedure("run").handle(async () => {
|
|
@@ -238,14 +266,13 @@ describe("BaseService procedure builder", () => {
|
|
|
238
266
|
class LoggedService extends base_service_1.BaseService {
|
|
239
267
|
run = this.procedure("run")
|
|
240
268
|
.requireAuth()
|
|
241
|
-
.handle(({ ctx }) => (0, neverthrow_1.ok)(ctx.
|
|
269
|
+
.handle(({ ctx }) => (0, neverthrow_1.ok)(ctx.actor.userId));
|
|
242
270
|
}
|
|
243
271
|
const service = new LoggedService();
|
|
244
272
|
const debugSpy = jest.fn();
|
|
245
273
|
service.logger.debug = debugSpy;
|
|
246
274
|
const result = await service.run({ secret: "top-secret" }, {
|
|
247
|
-
|
|
248
|
-
session: createSession(),
|
|
275
|
+
actor: createActor(),
|
|
249
276
|
token: "super-token",
|
|
250
277
|
});
|
|
251
278
|
expect(result.isOk()).toBe(true);
|
|
@@ -255,6 +282,7 @@ describe("BaseService procedure builder", () => {
|
|
|
255
282
|
const serializedPayloads = JSON.stringify(payloads);
|
|
256
283
|
expect(serializedPayloads).not.toContain("top-secret");
|
|
257
284
|
expect(serializedPayloads).not.toContain("super-token");
|
|
285
|
+
expect(payloads.every((payload) => "hasActor" in payload)).toBe(true);
|
|
258
286
|
expect(payloads.every((payload) => !("input" in payload))).toBe(true);
|
|
259
287
|
expect(payloads.every((payload) => !("ctx" in payload))).toBe(true);
|
|
260
288
|
});
|
|
@@ -283,7 +311,7 @@ describe("BasePermissionService procedure builder", () => {
|
|
|
283
311
|
.handle(({ state }) => (0, neverthrow_1.ok)(state.access?.userId ?? null));
|
|
284
312
|
}
|
|
285
313
|
const service = new PermissionService();
|
|
286
|
-
const result = await service.run({ ownerId: "user-1" }, {
|
|
314
|
+
const result = await service.run({ ownerId: "user-1" }, { actor: createActor() });
|
|
287
315
|
expect(result.isOk()).toBe(true);
|
|
288
316
|
if (result.isOk()) {
|
|
289
317
|
expect(result.value).toBe("user-1");
|
|
@@ -316,7 +344,7 @@ describe("BasePermissionService procedure builder", () => {
|
|
|
316
344
|
.handle(({ state }) => (0, neverthrow_1.ok)(state.access === state.record));
|
|
317
345
|
}
|
|
318
346
|
const service = new PermissionService();
|
|
319
|
-
const result = await service.run({ ownerId: "user-1" }, {
|
|
347
|
+
const result = await service.run({ ownerId: "user-1" }, { actor: createActor() });
|
|
320
348
|
expect(result.isOk()).toBe(true);
|
|
321
349
|
if (result.isOk()) {
|
|
322
350
|
expect(result.value).toBe(true);
|
|
@@ -345,7 +373,7 @@ describe("BasePermissionService procedure builder", () => {
|
|
|
345
373
|
.handle(() => (0, neverthrow_1.ok)("allowed"));
|
|
346
374
|
}
|
|
347
375
|
const service = new PermissionService();
|
|
348
|
-
const result = await service.run({ ownerId: "other-user" }, {
|
|
376
|
+
const result = await service.run({ ownerId: "other-user" }, { actor: createActor() });
|
|
349
377
|
expect(result.isErr()).toBe(true);
|
|
350
378
|
if (result.isErr()) {
|
|
351
379
|
expect(result.error.code).toBe("FORBIDDEN");
|
|
@@ -377,7 +405,7 @@ describe("BasePermissionService procedure builder", () => {
|
|
|
377
405
|
.handle(() => (0, neverthrow_1.ok)("allowed"));
|
|
378
406
|
}
|
|
379
407
|
const service = new PermissionService();
|
|
380
|
-
const result = await service.run({ ownerId: "user-1" }, {
|
|
408
|
+
const result = await service.run({ ownerId: "user-1" }, { actor: createActor() });
|
|
381
409
|
expect(result.isErr()).toBe(true);
|
|
382
410
|
if (result.isErr()) {
|
|
383
411
|
expect(result.error.code).toBe("INTERNAL_SERVER_ERROR");
|
|
@@ -405,7 +433,7 @@ describe("BasePermissionService procedure builder", () => {
|
|
|
405
433
|
.handle(() => (0, neverthrow_1.ok)("allowed"));
|
|
406
434
|
}
|
|
407
435
|
const service = new PermissionService();
|
|
408
|
-
const result = await service.run({ ownerId: "other-user" }, {
|
|
436
|
+
const result = await service.run({ ownerId: "other-user" }, { actor: createActor() });
|
|
409
437
|
expect(result.isOk()).toBe(true);
|
|
410
438
|
if (result.isOk()) {
|
|
411
439
|
expect(result.value).toBe("allowed");
|
|
@@ -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(
|
|
24
|
-
|
|
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(
|
|
76
|
-
return this.repository.billing.getActiveSubscription(
|
|
75
|
+
async getActiveSubscription(ctx) {
|
|
76
|
+
return this.repository.billing.getActiveSubscription(ctx.actor.userId);
|
|
77
77
|
}
|
|
78
|
-
async listInvoices(
|
|
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("
|
|
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
|
-
.
|
|
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
|
|
14
|
-
return (0, trpc_1.handleTRPCResult)(await billingService.listInvoices(
|
|
11
|
+
listInvoices: procedure.query(async ({ ctx }) => {
|
|
12
|
+
return (0, trpc_1.handleTRPCResult)(await billingService.listInvoices(ctx));
|
|
15
13
|
}),
|
|
16
14
|
});
|
|
17
15
|
}
|
|
@@ -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<{
|
|
@@ -21,7 +20,6 @@ export declare class ConnectService extends BaseService<{
|
|
|
21
20
|
updatedAt: Date | null;
|
|
22
21
|
expiresAt: Date | null;
|
|
23
22
|
userId: string;
|
|
24
|
-
parentId: string | null;
|
|
25
23
|
accessToken: string;
|
|
26
24
|
refreshToken: string | null;
|
|
27
25
|
scope: string | null;
|
|
@@ -32,6 +30,7 @@ export declare class ConnectService extends BaseService<{
|
|
|
32
30
|
displayName: string | null;
|
|
33
31
|
avatarUrl: string | null;
|
|
34
32
|
tokenType: string | null;
|
|
33
|
+
parentId: string | null;
|
|
35
34
|
metadataJson: unknown;
|
|
36
35
|
revokedAt: Date | null;
|
|
37
36
|
lastRefreshedAt: Date | null;
|
|
@@ -42,7 +41,6 @@ export declare class ConnectService extends BaseService<{
|
|
|
42
41
|
updatedAt: Date | null;
|
|
43
42
|
expiresAt: Date | null;
|
|
44
43
|
userId: string;
|
|
45
|
-
parentId: string | null;
|
|
46
44
|
accessToken: string;
|
|
47
45
|
refreshToken: string | null;
|
|
48
46
|
scope: string | null;
|
|
@@ -53,13 +51,19 @@ export declare class ConnectService extends BaseService<{
|
|
|
53
51
|
displayName: string | null;
|
|
54
52
|
avatarUrl: string | null;
|
|
55
53
|
tokenType: string | null;
|
|
54
|
+
parentId: string | null;
|
|
56
55
|
metadataJson: unknown;
|
|
57
56
|
revokedAt: Date | null;
|
|
58
57
|
lastRefreshedAt: Date | null;
|
|
59
58
|
}>>;
|
|
60
|
-
list
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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 !==
|
|
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;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type TRPCMethods } from "../../utils/trpc";
|
|
2
2
|
import type { ConnectService } from "./connect.service";
|
|
3
3
|
export declare function createConnectTRPC({ router, privateProcedure: procedure }: TRPCMethods, connectService: ConnectService): import("@trpc/server").TRPCBuiltRouter<{
|
|
4
|
-
ctx: import("
|
|
4
|
+
ctx: import("../../utils/trpc").Context;
|
|
5
5
|
meta: any;
|
|
6
6
|
errorShape: import("@trpc/server").TRPCDefaultErrorShape;
|
|
7
7
|
transformer: true;
|
|
@@ -20,12 +20,12 @@ export declare function createConnectTRPC({ router, privateProcedure: procedure
|
|
|
20
20
|
providerAccountId: string;
|
|
21
21
|
updatedAt?: Date | null | undefined;
|
|
22
22
|
expiresAt?: Date | null | undefined;
|
|
23
|
-
parentId?: string | null | undefined;
|
|
24
23
|
scope?: string | null | undefined;
|
|
25
24
|
handle?: string | null | undefined;
|
|
26
25
|
displayName?: string | null | undefined;
|
|
27
26
|
avatarUrl?: string | null | undefined;
|
|
28
27
|
tokenType?: string | null | undefined;
|
|
28
|
+
parentId?: string | null | undefined;
|
|
29
29
|
metadataJson?: unknown;
|
|
30
30
|
revokedAt?: Date | null | undefined;
|
|
31
31
|
lastRefreshedAt?: Date | null | undefined;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { Context } from "../auth/auth.lib";
|
|
1
|
+
import type { DeleteRecurrenceRulesSchema, DeleteRecurrenceSchema, UpdateRecurrenceRulesSchema, UpdateRecurrenceSchema } from "@m5kdev/commons/modules/recurrence/recurrence.schema";
|
|
3
2
|
import type { ServerResultAsync } from "../base/base.dto";
|
|
4
3
|
import { BaseService } from "../base/base.service";
|
|
5
4
|
import type { CreateWithRulesResult, RecurrenceRepository, RecurrenceRulesRepository } from "./recurrence.repository";
|
|
6
5
|
export declare class RecurrenceService extends BaseService<{
|
|
7
6
|
recurrence: RecurrenceRepository;
|
|
8
7
|
recurrenceRules: RecurrenceRulesRepository;
|
|
9
|
-
}, Record<string, never
|
|
8
|
+
}, Record<string, never>> {
|
|
10
9
|
readonly list: import("../base/base.procedure").ServiceProcedure<{
|
|
11
10
|
page?: number | undefined;
|
|
12
11
|
limit?: number | undefined;
|
|
@@ -20,7 +19,11 @@ export declare class RecurrenceService extends BaseService<{
|
|
|
20
19
|
valueTo?: string | undefined;
|
|
21
20
|
endColumnId?: string | undefined;
|
|
22
21
|
}[] | undefined;
|
|
23
|
-
},
|
|
22
|
+
}, {
|
|
23
|
+
actor?: import("../base/base.actor").AuthenticatedActor | null;
|
|
24
|
+
} & Record<string, unknown> & {
|
|
25
|
+
actor: import("../base/base.actor").UserActor;
|
|
26
|
+
}, {
|
|
24
27
|
rows: {
|
|
25
28
|
id: string;
|
|
26
29
|
name: string | null;
|
|
@@ -28,14 +31,41 @@ export declare class RecurrenceService extends BaseService<{
|
|
|
28
31
|
updatedAt: Date;
|
|
29
32
|
metadata: Record<string, any> | null;
|
|
30
33
|
userId: string | null;
|
|
31
|
-
teamId: string | null;
|
|
32
34
|
organizationId: string | null;
|
|
35
|
+
teamId: string | null;
|
|
33
36
|
enabled: boolean;
|
|
34
37
|
kind: string | null;
|
|
35
38
|
}[];
|
|
36
39
|
total: number;
|
|
37
40
|
}>;
|
|
38
|
-
create
|
|
41
|
+
readonly create: import("../base/base.procedure").ServiceProcedure<{
|
|
42
|
+
name: string;
|
|
43
|
+
kind: string;
|
|
44
|
+
enabled: boolean;
|
|
45
|
+
recurrenceRules: {
|
|
46
|
+
interval: number;
|
|
47
|
+
freq: number;
|
|
48
|
+
bysetpos?: number | number[] | null | undefined;
|
|
49
|
+
bymonth?: number | number[] | null | undefined;
|
|
50
|
+
bymonthday?: number | number[] | null | undefined;
|
|
51
|
+
byyearday?: number | number[] | null | undefined;
|
|
52
|
+
byweekno?: number | number[] | null | undefined;
|
|
53
|
+
byweekday?: number | number[] | null | undefined;
|
|
54
|
+
byhour?: number | number[] | null | undefined;
|
|
55
|
+
byminute?: number | number[] | null | undefined;
|
|
56
|
+
bysecond?: number | number[] | null | undefined;
|
|
57
|
+
dtstart?: Date | null | undefined;
|
|
58
|
+
wkst?: number | null | undefined;
|
|
59
|
+
count?: number | null | undefined;
|
|
60
|
+
until?: Date | null | undefined;
|
|
61
|
+
tzid?: string | null | undefined;
|
|
62
|
+
}[];
|
|
63
|
+
metadata?: Record<string, unknown> | null | undefined;
|
|
64
|
+
}, {
|
|
65
|
+
actor?: import("../base/base.actor").AuthenticatedActor | null;
|
|
66
|
+
} & Record<string, unknown> & {
|
|
67
|
+
actor: import("../base/base.actor").UserActor;
|
|
68
|
+
}, CreateWithRulesResult>;
|
|
39
69
|
findById(id: string): ServerResultAsync<CreateWithRulesResult["recurrence"] | null>;
|
|
40
70
|
update(data: UpdateRecurrenceSchema & {
|
|
41
71
|
id: string;
|