@managemint-solutions/sdk 0.21.1 → 0.22.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/auth.d.ts +12 -0
- package/dist/auth.js +18 -2
- package/dist/auth.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/organization-payment-methods/index.d.ts +50 -0
- package/dist/organization-payment-methods/index.js +88 -0
- package/dist/organization-payment-methods/index.js.map +1 -0
- package/dist/service-client/index.d.ts +11 -5
- package/dist/service-client/index.js +24 -6
- package/dist/service-client/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/organization-paystack-credentials/index.d.ts +0 -33
- package/dist/organization-paystack-credentials/index.js +0 -71
- package/dist/organization-paystack-credentials/index.js.map +0 -1
package/dist/auth.d.ts
CHANGED
|
@@ -10,11 +10,23 @@ export type AuthContext = {
|
|
|
10
10
|
mms_id: string;
|
|
11
11
|
organization_id: string;
|
|
12
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* The billing state of the caller's organization, read in the same query as their tenancy so the
|
|
15
|
+
* api's payment and module gates cost no extra round trip. `billing_status` is a
|
|
16
|
+
* `BillingStatus` value; `modules` holds the module keys the organization owns.
|
|
17
|
+
*/
|
|
18
|
+
export type VerifiedOrganization = {
|
|
19
|
+
billing_status: string;
|
|
20
|
+
payment_override: boolean;
|
|
21
|
+
access_expires_at: string | null;
|
|
22
|
+
modules: string[];
|
|
23
|
+
};
|
|
13
24
|
/** What a verified bearer token resolves to: the GoTrue subject plus the caller's `users` row. */
|
|
14
25
|
export type VerifiedAuth = AuthContext & {
|
|
15
26
|
email: string | null;
|
|
16
27
|
name: string | null;
|
|
17
28
|
surname: string | null;
|
|
29
|
+
organization: VerifiedOrganization;
|
|
18
30
|
};
|
|
19
31
|
export type VerifyAccessTokenConfig = {
|
|
20
32
|
url: string;
|
package/dist/auth.js
CHANGED
|
@@ -13,6 +13,10 @@ const createRawClient = (url, key, accessToken) => (0, supabase_js_1.createClien
|
|
|
13
13
|
auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false },
|
|
14
14
|
});
|
|
15
15
|
exports.createRawClient = createRawClient;
|
|
16
|
+
// Named explicitly: users and organizations reference each other (organization_id one way,
|
|
17
|
+
// last_updated_by the other), so a bare embed would be ambiguous.
|
|
18
|
+
const PROFILE_SELECT = 'organization_id, active, email, name, surname, '
|
|
19
|
+
+ 'organization:organizations!users_organization_id_fkey(billing_status, payment_override, access_expires_at, modules)';
|
|
16
20
|
const authError = (message) => new errors_1.SupabaseClientError({ status: 401, error: 'Authentication Error', message });
|
|
17
21
|
/**
|
|
18
22
|
* Establishes who the caller is, from a token whose signature is actually checked.
|
|
@@ -32,13 +36,14 @@ const verifyAccessToken = async ({ url, key, accessToken, client = (0, exports.c
|
|
|
32
36
|
if (error || typeof mms_id !== 'string' || mms_id === '') {
|
|
33
37
|
throw authError('Invalid or expired token');
|
|
34
38
|
}
|
|
35
|
-
const { data:
|
|
39
|
+
const { data: profileData, error: profileError } = await client
|
|
36
40
|
.from('users')
|
|
37
|
-
.select(
|
|
41
|
+
.select(PROFILE_SELECT)
|
|
38
42
|
.eq('mms_id', mms_id)
|
|
39
43
|
.maybeSingle();
|
|
40
44
|
if (profileError)
|
|
41
45
|
throw (0, errors_1.mapPostgrestError)(profileError);
|
|
46
|
+
const profile = profileData;
|
|
42
47
|
if (!profile)
|
|
43
48
|
throw authError('No user profile exists for this account');
|
|
44
49
|
if (profile.active === false) {
|
|
@@ -48,12 +53,23 @@ const verifyAccessToken = async ({ url, key, accessToken, client = (0, exports.c
|
|
|
48
53
|
message: 'Your account has been deactivated',
|
|
49
54
|
});
|
|
50
55
|
}
|
|
56
|
+
// The FK is not null, so this only fails if the organization row is unreadable - which is
|
|
57
|
+
// the same "no tenancy" situation as a missing users row.
|
|
58
|
+
const organization = profile.organization;
|
|
59
|
+
if (!organization)
|
|
60
|
+
throw authError('No organization exists for this account');
|
|
51
61
|
return {
|
|
52
62
|
mms_id,
|
|
53
63
|
organization_id: profile.organization_id,
|
|
54
64
|
email: profile.email ?? null,
|
|
55
65
|
name: profile.name ?? null,
|
|
56
66
|
surname: profile.surname ?? null,
|
|
67
|
+
organization: {
|
|
68
|
+
billing_status: organization.billing_status,
|
|
69
|
+
payment_override: organization.payment_override === true,
|
|
70
|
+
access_expires_at: organization.access_expires_at ?? null,
|
|
71
|
+
modules: organization.modules ?? [],
|
|
72
|
+
},
|
|
57
73
|
};
|
|
58
74
|
};
|
|
59
75
|
exports.verifyAccessToken = verifyAccessToken;
|
package/dist/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":";;;AAAA,uDAA8F;AAC9F,qCAAkE;AAElE;;;;GAIG;AACI,MAAM,eAAe,GAAG,CAC7B,GAAW,EACX,GAAW,EACX,WAAoB,EACF,EAAE,CACpB,IAAA,0BAAY,EAAC,GAAG,EAAE,GAAG,EAAE;IACrB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,WAAW,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3F,IAAI,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE;CACpF,CAAC,CAAC;AARQ,QAAA,eAAe,mBAQvB;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":";;;AAAA,uDAA8F;AAC9F,qCAAkE;AAElE;;;;GAIG;AACI,MAAM,eAAe,GAAG,CAC7B,GAAW,EACX,GAAW,EACX,WAAoB,EACF,EAAE,CACpB,IAAA,0BAAY,EAAC,GAAG,EAAE,GAAG,EAAE;IACrB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,WAAW,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3F,IAAI,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE;CACpF,CAAC,CAAC;AARQ,QAAA,eAAe,mBAQvB;AAyBL,2FAA2F;AAC3F,kEAAkE;AAClE,MAAM,cAAc,GAClB,iDAAiD;MAC/C,qHAAqH,CAAC;AAuB1H,MAAM,SAAS,GAAG,CAAC,OAAe,EAAuB,EAAE,CACzD,IAAI,4BAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,CAAC,CAAC;AAEnF;;;;;;;;;GASG;AACI,MAAM,iBAAiB,GAAG,KAAK,EAAE,EACtC,GAAG,EACH,GAAG,EACH,WAAW,EACX,MAAM,GAAG,IAAA,uBAAe,EAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,GACvB,EAAyB,EAAE;IACnD,6FAA6F;IAC7F,2FAA2F;IAC3F,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC;IACjC,IAAI,KAAK,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;QACzD,MAAM,SAAS,CAAC,0BAA0B,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM;SAC5D,IAAI,CAAC,OAAO,CAAC;SACb,MAAM,CAAC,cAAc,CAAC;SACtB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;SACpB,WAAW,EAAE,CAAC;IACjB,IAAI,YAAY;QAAE,MAAM,IAAA,0BAAiB,EAAC,YAAY,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,WAA2C,CAAC;IAC5D,IAAI,CAAC,OAAO;QAAE,MAAM,SAAS,CAAC,yCAAyC,CAAC,CAAC;IACzE,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC7B,MAAM,IAAI,4BAAmB,CAAC;YAC5B,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,sBAAsB;YAC7B,OAAO,EAAE,mCAAmC;SAC7C,CAAC,CAAC;IACL,CAAC;IAED,0FAA0F;IAC1F,0DAA0D;IAC1D,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAC1C,IAAI,CAAC,YAAY;QAAE,MAAM,SAAS,CAAC,yCAAyC,CAAC,CAAC;IAE9E,OAAO;QACL,MAAM;QACN,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,IAAI;QAC5B,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI;QAC1B,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;QAChC,YAAY,EAAE;YACZ,cAAc,EAAE,YAAY,CAAC,cAAwB;YACrD,gBAAgB,EAAE,YAAY,CAAC,gBAAgB,KAAK,IAAI;YACxD,iBAAiB,EAAE,YAAY,CAAC,iBAAiB,IAAI,IAAI;YACzD,OAAO,EAAE,YAAY,CAAC,OAAO,IAAI,EAAE;SACpC;KACF,CAAC;AACJ,CAAC,CAAC;AAhDW,QAAA,iBAAiB,qBAgD5B"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { SupabaseClient, createSupabaseClient } from './client';
|
|
2
2
|
export type { SupabaseClientConfig, TypedSupabaseClient } from './client';
|
|
3
3
|
export { verifyAccessToken } from './auth';
|
|
4
|
-
export type { AuthContext, VerifiedAuth, VerifyAccessTokenConfig } from './auth';
|
|
4
|
+
export type { AuthContext, VerifiedAuth, VerifiedOrganization, VerifyAccessTokenConfig, } from './auth';
|
|
5
5
|
export { SupabaseAuthClient, createSupabaseAuthClient } from './auth-client';
|
|
6
6
|
export type { SupabaseAuthClientConfig } from './auth-client';
|
|
7
7
|
export { ExchangeRefreshTokenDto, ExchangeTokenHashDto, ResetPasswordDto, SendPasswordResetEmailDto, SignInDto, } from './auth-client';
|
|
@@ -28,8 +28,8 @@ export type { CreateNotificationInput, CreatedNotification, NotificationContentR
|
|
|
28
28
|
export { GetNotificationsDto, NotificationIdDto } from './notifications';
|
|
29
29
|
export { OrganizationInvitesResource } from './organization-invites';
|
|
30
30
|
export type { OrganizationInvite } from './organization-invites';
|
|
31
|
-
export {
|
|
32
|
-
export type {
|
|
31
|
+
export { OrganizationPaymentMethodsResource } from './organization-payment-methods';
|
|
32
|
+
export type { OrganizationPaymentMethod, PaymentMethodLookupColumn, } from './organization-payment-methods';
|
|
33
33
|
export { OrganizationsResource, OrganizationSignupResource } from './organizations';
|
|
34
34
|
export type { CreateOrganizationRow, OrganizationRow } from './organizations';
|
|
35
35
|
export { CreateOrganizationDto, UpdateOrganizationDto } from './organizations';
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// the audit diff, the row helpers, the select-string fragments, the error mappers — and stays
|
|
4
4
|
// reachable only from inside. The `./nest` entrypoint is listed separately, in src/nest/index.ts.
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.OrganizationSignupResource = exports.OrganizationsResource = exports.
|
|
6
|
+
exports.OrganizationSignupResource = exports.OrganizationsResource = exports.OrganizationPaymentMethodsResource = exports.OrganizationInvitesResource = exports.NotificationIdDto = exports.GetNotificationsDto = exports.NotificationsOutboxResource = exports.NotificationsResource = exports.NoteIdDto = exports.GetNotesDto = exports.AddNoteDto = exports.NotesResource = exports.UpdateAdditionalDetailsDto = exports.IsAdditionalDetailsValueByType = exports.GetAdditionalDetailsDto = exports.AdditionalDetailsIdDto = exports.AddAdditionalDetailsDto = exports.AdditionalDetailsResource = exports.UpdateStatusDto = exports.StatusIdDto = exports.GetStatusesDto = exports.AddStatusDto = exports.StatusesResource = exports.InvoiceIdDto = exports.GetInvoicesQueryDto = exports.InvoicesResource = exports.InvoicesReadsResource = exports.ReinstateSubscriptionDto = exports.PurchaseModuleDto = exports.InitialPaymentDto = exports.CancelSubscriptionDto = exports.BillingResource = exports.BillingReadsResource = exports.GetAuditTrailDto = exports.AuditResource = exports.IsNullable = exports.SupabaseClientError = exports.createSupabaseServiceClient = exports.SupabaseOrganizationScope = exports.SupabaseServiceClient = exports.SignInDto = exports.SendPasswordResetEmailDto = exports.ResetPasswordDto = exports.ExchangeTokenHashDto = exports.ExchangeRefreshTokenDto = exports.createSupabaseAuthClient = exports.SupabaseAuthClient = exports.verifyAccessToken = exports.createSupabaseClient = exports.SupabaseClient = void 0;
|
|
7
7
|
exports.monthlyTotalMinor = exports.PricebooksResource = exports.UpdateTaskDto = exports.TaskIdDto = exports.GetTasksDto = exports.CreateTaskDto = exports.TasksResource = exports.UpdateProjectDto = exports.ProjectIdDto = exports.GetProjectsDto = exports.CreateProjectDto = exports.ProjectsResource = exports.UpdateClientDto = exports.GetClientsDto = exports.CreateClientDto = exports.ClientIdDto = exports.ClientsResource = exports.SupportTicketIdDto = exports.SupportAttachmentDto = exports.ReplySupportTicketDto = exports.GetSupportTicketsDto = exports.CreateSupportTicketDto = exports.AssignSupportTicketDto = exports.SupportTicketsAdminResource = exports.SupportTicketsResource = exports.SupportingFileIdDto = exports.GetSupportingFilesDto = exports.SupportingFilesResource = exports.WebhookEventsResource = exports.UserIdDto = exports.UpdateUserDto = exports.UpdateMyProfileDto = exports.GetUsersQueryDto = exports.AddUserDto = exports.UsersResource = exports.UpdatePermissionsDto = exports.PermissionsResource = exports.UpdateOrganizationDto = exports.CreateOrganizationDto = void 0;
|
|
8
8
|
var client_1 = require("./client");
|
|
9
9
|
Object.defineProperty(exports, "SupabaseClient", { enumerable: true, get: function () { return client_1.SupabaseClient; } });
|
|
@@ -74,8 +74,8 @@ Object.defineProperty(exports, "GetNotificationsDto", { enumerable: true, get: f
|
|
|
74
74
|
Object.defineProperty(exports, "NotificationIdDto", { enumerable: true, get: function () { return notifications_2.NotificationIdDto; } });
|
|
75
75
|
var organization_invites_1 = require("./organization-invites");
|
|
76
76
|
Object.defineProperty(exports, "OrganizationInvitesResource", { enumerable: true, get: function () { return organization_invites_1.OrganizationInvitesResource; } });
|
|
77
|
-
var
|
|
78
|
-
Object.defineProperty(exports, "
|
|
77
|
+
var organization_payment_methods_1 = require("./organization-payment-methods");
|
|
78
|
+
Object.defineProperty(exports, "OrganizationPaymentMethodsResource", { enumerable: true, get: function () { return organization_payment_methods_1.OrganizationPaymentMethodsResource; } });
|
|
79
79
|
var organizations_1 = require("./organizations");
|
|
80
80
|
Object.defineProperty(exports, "OrganizationsResource", { enumerable: true, get: function () { return organizations_1.OrganizationsResource; } });
|
|
81
81
|
Object.defineProperty(exports, "OrganizationSignupResource", { enumerable: true, get: function () { return organizations_1.OrganizationSignupResource; } });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,kGAAkG;AAClG,8FAA8F;AAC9F,kGAAkG;;;;AAElG,mCAAgE;AAAvD,wGAAA,cAAc,OAAA;AAAE,8GAAA,oBAAoB,OAAA;AAG7C,+BAA2C;AAAlC,yGAAA,iBAAiB,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type AuditActor, type AuditResource } from '../audit';
|
|
2
|
+
import type { TypedSupabaseClient } from '../client';
|
|
3
|
+
/**
|
|
4
|
+
* Everything Paystack knows an organization by, plus the two secrets the billing service acts
|
|
5
|
+
* with. One row per organization; every column is null until the step that creates it runs.
|
|
6
|
+
*/
|
|
7
|
+
export type OrganizationPaymentMethod = {
|
|
8
|
+
/** The Paystack customer representing the organization. */
|
|
9
|
+
paystack_customer_code: string | null;
|
|
10
|
+
paystack_customer_created_at: string | null;
|
|
11
|
+
/** The plan priced for the organization's modules and seats. */
|
|
12
|
+
paystack_plan_code: string | null;
|
|
13
|
+
paystack_plan_created_at: string | null;
|
|
14
|
+
/** The current recurring subscription; cleared when it is cancelled so a dead code is never reused. */
|
|
15
|
+
paystack_subscription_code: string | null;
|
|
16
|
+
paystack_subscription_created_at: string | null;
|
|
17
|
+
/** Paired with the subscription code to disable or enable the subscription. */
|
|
18
|
+
paystack_subscription_email_token: string | null;
|
|
19
|
+
/** The saved card authorization every off-session charge is made against. */
|
|
20
|
+
paystack_customer_authorization_code: string | null;
|
|
21
|
+
};
|
|
22
|
+
export declare const PAYMENT_METHOD_COLUMNS: readonly ["paystack_customer_code", "paystack_customer_created_at", "paystack_plan_code", "paystack_plan_created_at", "paystack_subscription_code", "paystack_subscription_created_at", "paystack_subscription_email_token", "paystack_customer_authorization_code"];
|
|
23
|
+
/** The payment-method columns a webhook may look an organization up by. */
|
|
24
|
+
export type PaymentMethodLookupColumn = 'paystack_customer_code' | 'paystack_subscription_code';
|
|
25
|
+
/**
|
|
26
|
+
* The `organization_payment_methods` table: the organization's Paystack identity in one row
|
|
27
|
+
* beside the `organizations` row, rather than as columns on it. The organizations READ policy
|
|
28
|
+
* hands the whole row to every member of the tenant, and nothing here is a member's business —
|
|
29
|
+
* the customer, plan and subscription codes are the provider's identifiers and the authorization
|
|
30
|
+
* code and email token are credentials — so the table carries no `authenticated` grant and no
|
|
31
|
+
* policy. Only the service role can reach it.
|
|
32
|
+
*
|
|
33
|
+
* Service-role only, like the invites — this lives on the organization scope of the service
|
|
34
|
+
* client and never on a caller's client. Writes are audited against the organization (the row
|
|
35
|
+
* has no identity of its own), and the audit diff redacts every `paystack_*` column, so the trail
|
|
36
|
+
* records that a value changed and never what it changed to.
|
|
37
|
+
*/
|
|
38
|
+
export declare class OrganizationPaymentMethodsResource {
|
|
39
|
+
private readonly supabase;
|
|
40
|
+
private readonly actor;
|
|
41
|
+
private readonly audit;
|
|
42
|
+
constructor(supabase: TypedSupabaseClient, actor: AuditActor, audit: AuditResource);
|
|
43
|
+
/** The actor organization's payment method; every column null when nothing has been stored yet. */
|
|
44
|
+
get(): Promise<OrganizationPaymentMethod>;
|
|
45
|
+
/**
|
|
46
|
+
* Stores the given columns, leaving the others untouched. Creates the row on first use;
|
|
47
|
+
* `null` clears a value (a cancelled subscription's code and token must never be reused).
|
|
48
|
+
*/
|
|
49
|
+
set(patch: Partial<OrganizationPaymentMethod>): Promise<void>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OrganizationPaymentMethodsResource = exports.PAYMENT_METHOD_COLUMNS = void 0;
|
|
4
|
+
const enum_1 = require("@managemint-solutions/entities/audit-trail/enum");
|
|
5
|
+
const audit_1 = require("../audit");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
exports.PAYMENT_METHOD_COLUMNS = [
|
|
8
|
+
'paystack_customer_code',
|
|
9
|
+
'paystack_customer_created_at',
|
|
10
|
+
'paystack_plan_code',
|
|
11
|
+
'paystack_plan_created_at',
|
|
12
|
+
'paystack_subscription_code',
|
|
13
|
+
'paystack_subscription_created_at',
|
|
14
|
+
'paystack_subscription_email_token',
|
|
15
|
+
'paystack_customer_authorization_code',
|
|
16
|
+
];
|
|
17
|
+
const EMPTY = {
|
|
18
|
+
paystack_customer_code: null,
|
|
19
|
+
paystack_customer_created_at: null,
|
|
20
|
+
paystack_plan_code: null,
|
|
21
|
+
paystack_plan_created_at: null,
|
|
22
|
+
paystack_subscription_code: null,
|
|
23
|
+
paystack_subscription_created_at: null,
|
|
24
|
+
paystack_subscription_email_token: null,
|
|
25
|
+
paystack_customer_authorization_code: null,
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* The `organization_payment_methods` table: the organization's Paystack identity in one row
|
|
29
|
+
* beside the `organizations` row, rather than as columns on it. The organizations READ policy
|
|
30
|
+
* hands the whole row to every member of the tenant, and nothing here is a member's business —
|
|
31
|
+
* the customer, plan and subscription codes are the provider's identifiers and the authorization
|
|
32
|
+
* code and email token are credentials — so the table carries no `authenticated` grant and no
|
|
33
|
+
* policy. Only the service role can reach it.
|
|
34
|
+
*
|
|
35
|
+
* Service-role only, like the invites — this lives on the organization scope of the service
|
|
36
|
+
* client and never on a caller's client. Writes are audited against the organization (the row
|
|
37
|
+
* has no identity of its own), and the audit diff redacts every `paystack_*` column, so the trail
|
|
38
|
+
* records that a value changed and never what it changed to.
|
|
39
|
+
*/
|
|
40
|
+
class OrganizationPaymentMethodsResource {
|
|
41
|
+
supabase;
|
|
42
|
+
actor;
|
|
43
|
+
audit;
|
|
44
|
+
constructor(supabase, actor, audit) {
|
|
45
|
+
this.supabase = supabase;
|
|
46
|
+
this.actor = actor;
|
|
47
|
+
this.audit = audit;
|
|
48
|
+
}
|
|
49
|
+
/** The actor organization's payment method; every column null when nothing has been stored yet. */
|
|
50
|
+
async get() {
|
|
51
|
+
const { data, error } = await this.supabase
|
|
52
|
+
.from('organization_payment_methods')
|
|
53
|
+
.select(exports.PAYMENT_METHOD_COLUMNS.join(', '))
|
|
54
|
+
.eq('organization_id', this.actor.organization_id)
|
|
55
|
+
.maybeSingle();
|
|
56
|
+
if (error)
|
|
57
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
58
|
+
return { ...EMPTY, ...(data ?? {}) };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Stores the given columns, leaving the others untouched. Creates the row on first use;
|
|
62
|
+
* `null` clears a value (a cancelled subscription's code and token must never be reused).
|
|
63
|
+
*/
|
|
64
|
+
async set(patch) {
|
|
65
|
+
const before = await this.get();
|
|
66
|
+
const after = { ...before, ...patch };
|
|
67
|
+
const { error } = await this.supabase
|
|
68
|
+
.from('organization_payment_methods')
|
|
69
|
+
.upsert({
|
|
70
|
+
organization_id: this.actor.organization_id,
|
|
71
|
+
...after,
|
|
72
|
+
updated_at: new Date().toISOString(),
|
|
73
|
+
}, { onConflict: 'organization_id' });
|
|
74
|
+
if (error)
|
|
75
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
76
|
+
const changes = (0, audit_1.diffChanges)(before, after);
|
|
77
|
+
if (Object.keys(changes).length === 0)
|
|
78
|
+
return;
|
|
79
|
+
await this.audit.record({
|
|
80
|
+
action: enum_1.AuditTrailAction.UPDATE,
|
|
81
|
+
entityType: enum_1.AuditTrailEntityType.ORGANIZATION,
|
|
82
|
+
entityId: this.actor.organization_id,
|
|
83
|
+
changes,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.OrganizationPaymentMethodsResource = OrganizationPaymentMethodsResource;
|
|
88
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/organization-payment-methods/index.ts"],"names":[],"mappings":";;;AAAA,0EAAyG;AACzG,oCAA2F;AAE3F,sCAA8C;AAsBjC,QAAA,sBAAsB,GAAG;IACpC,wBAAwB;IACxB,8BAA8B;IAC9B,oBAAoB;IACpB,0BAA0B;IAC1B,4BAA4B;IAC5B,kCAAkC;IAClC,mCAAmC;IACnC,sCAAsC;CACyB,CAAC;AAKlE,MAAM,KAAK,GAA8B;IACvC,sBAAsB,EAAE,IAAI;IAC5B,4BAA4B,EAAE,IAAI;IAClC,kBAAkB,EAAE,IAAI;IACxB,wBAAwB,EAAE,IAAI;IAC9B,0BAA0B,EAAE,IAAI;IAChC,gCAAgC,EAAE,IAAI;IACtC,iCAAiC,EAAE,IAAI;IACvC,oCAAoC,EAAE,IAAI;CAC3C,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAa,kCAAkC;IAE1B;IACA;IACA;IAHnB,YACmB,QAA6B,EAC7B,KAAiB,EACjB,KAAoB;QAFpB,aAAQ,GAAR,QAAQ,CAAqB;QAC7B,UAAK,GAAL,KAAK,CAAY;QACjB,UAAK,GAAL,KAAK,CAAe;IACpC,CAAC;IAEJ,mGAAmG;IACnG,KAAK,CAAC,GAAG;QACP,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aACxC,IAAI,CAAC,8BAA8B,CAAC;aACpC,MAAM,CAAC,8BAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aACzC,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC;aACjD,WAAW,EAAE,CAAC;QACjB,IAAI,KAAK;YAAE,MAAM,IAAA,0BAAiB,EAAC,KAAK,CAAC,CAAC;QAE1C,OAAO,EAAE,GAAG,KAAK,EAAE,GAAI,CAAC,IAAI,IAAI,EAAE,CAAwC,EAAE,CAAC;IAC/E,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,KAAyC;QACjD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,KAAK,GAA8B,EAAE,GAAG,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QAEjE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aAClC,IAAI,CAAC,8BAA8B,CAAC;aACpC,MAAM,CACL;YACE,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe;YAC3C,GAAG,KAAK;YACR,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACrC,EACD,EAAE,UAAU,EAAE,iBAAiB,EAAE,CAClC,CAAC;QACJ,IAAI,KAAK;YAAE,MAAM,IAAA,0BAAiB,EAAC,KAAK,CAAC,CAAC;QAE1C,MAAM,OAAO,GAAG,IAAA,mBAAW,EAAC,MAAkB,EAAE,KAAiB,CAAC,CAAC;QACnE,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE9C,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YACtB,MAAM,EAAE,uBAAgB,CAAC,MAAM;YAC/B,UAAU,EAAE,2BAAoB,CAAC,YAAY;YAC7C,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe;YACpC,OAAO;SACR,CAAC,CAAC;IACL,CAAC;CACF;AAjDD,gFAiDC"}
|
|
@@ -4,7 +4,7 @@ import { BillingResource } from '../billing';
|
|
|
4
4
|
import { InvoicesResource } from '../billing/invoices';
|
|
5
5
|
import { NotificationsOutboxResource } from '../notifications';
|
|
6
6
|
import { OrganizationInvitesResource } from '../organization-invites';
|
|
7
|
-
import {
|
|
7
|
+
import { OrganizationPaymentMethodsResource, type PaymentMethodLookupColumn } from '../organization-payment-methods';
|
|
8
8
|
import { OrganizationsResource, OrganizationSignupResource } from '../organizations';
|
|
9
9
|
import { PermissionsResource } from '../permissions';
|
|
10
10
|
import { SupportTicketsAdminResource } from '../support/tickets';
|
|
@@ -30,7 +30,7 @@ export declare class SupabaseOrganizationScope {
|
|
|
30
30
|
readonly invoices: InvoicesResource;
|
|
31
31
|
readonly invites: OrganizationInvitesResource;
|
|
32
32
|
readonly organizations: OrganizationsResource;
|
|
33
|
-
readonly
|
|
33
|
+
readonly paymentMethod: OrganizationPaymentMethodsResource;
|
|
34
34
|
readonly permissions: PermissionsResource;
|
|
35
35
|
readonly users: UsersResource;
|
|
36
36
|
constructor(supabase: TypedSupabaseClient, actor: AuditActor, onAuditError?: AuditErrorHandler);
|
|
@@ -66,11 +66,17 @@ export declare class SupabaseServiceClient {
|
|
|
66
66
|
*/
|
|
67
67
|
forOrganization(organizationId: string, actorMmsId?: string | null): SupabaseOrganizationScope;
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* it belongs to is exactly what this answers.
|
|
69
|
+
* An organization row by one of its own columns. Deliberately unscoped: the webhook paths
|
|
70
|
+
* know only what the provider sent, and which tenant it belongs to is exactly what this answers.
|
|
72
71
|
*/
|
|
73
72
|
findOrganizationBy(column: string, value: string): Promise<Record<string, unknown> | null>;
|
|
73
|
+
/**
|
|
74
|
+
* The organization behind a Paystack customer or subscription code. The codes live on
|
|
75
|
+
* `organization_payment_methods`, so the lookup goes through that row and embeds the
|
|
76
|
+
* organization it belongs to; a webhook then scopes to it with `forOrganization` for the
|
|
77
|
+
* payment method itself.
|
|
78
|
+
*/
|
|
79
|
+
findOrganizationByPaymentMethod(column: PaymentMethodLookupColumn, value: string): Promise<Record<string, unknown> | null>;
|
|
74
80
|
/**
|
|
75
81
|
* A ledger row by id alone. Also unscoped by necessity: a `charge.success` carries the
|
|
76
82
|
* transaction id in its metadata, and the row is what says which tenant it belongs to.
|
|
@@ -9,7 +9,7 @@ const invoices_1 = require("../billing/invoices");
|
|
|
9
9
|
const notifications_1 = require("../notifications");
|
|
10
10
|
const errors_1 = require("../errors");
|
|
11
11
|
const organization_invites_1 = require("../organization-invites");
|
|
12
|
-
const
|
|
12
|
+
const organization_payment_methods_1 = require("../organization-payment-methods");
|
|
13
13
|
const organizations_1 = require("../organizations");
|
|
14
14
|
const permissions_1 = require("../permissions");
|
|
15
15
|
const tickets_1 = require("../support/tickets");
|
|
@@ -28,7 +28,7 @@ class SupabaseOrganizationScope {
|
|
|
28
28
|
invoices;
|
|
29
29
|
invites;
|
|
30
30
|
organizations;
|
|
31
|
-
|
|
31
|
+
paymentMethod;
|
|
32
32
|
permissions;
|
|
33
33
|
users;
|
|
34
34
|
constructor(supabase, actor, onAuditError) {
|
|
@@ -39,7 +39,7 @@ class SupabaseOrganizationScope {
|
|
|
39
39
|
this.invoices = new invoices_1.InvoicesResource(supabase, actor, this.audit);
|
|
40
40
|
this.invites = new organization_invites_1.OrganizationInvitesResource(supabase, actor);
|
|
41
41
|
this.organizations = new organizations_1.OrganizationsResource(supabase, actor, this.audit);
|
|
42
|
-
this.
|
|
42
|
+
this.paymentMethod = new organization_payment_methods_1.OrganizationPaymentMethodsResource(supabase, actor, this.audit);
|
|
43
43
|
this.permissions = new permissions_1.PermissionsResource(supabase, actor, this.audit);
|
|
44
44
|
this.users = new users_1.UsersResource(supabase, actor, this.audit);
|
|
45
45
|
}
|
|
@@ -97,9 +97,8 @@ class SupabaseServiceClient {
|
|
|
97
97
|
return new SupabaseOrganizationScope(this.supabase, { mms_id: actorMmsId, organization_id: organizationId }, this.config.onAuditError);
|
|
98
98
|
}
|
|
99
99
|
/**
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* it belongs to is exactly what this answers.
|
|
100
|
+
* An organization row by one of its own columns. Deliberately unscoped: the webhook paths
|
|
101
|
+
* know only what the provider sent, and which tenant it belongs to is exactly what this answers.
|
|
103
102
|
*/
|
|
104
103
|
async findOrganizationBy(column, value) {
|
|
105
104
|
const { data, error } = await this.supabase
|
|
@@ -112,6 +111,25 @@ class SupabaseServiceClient {
|
|
|
112
111
|
throw (0, errors_1.mapPostgrestError)(error);
|
|
113
112
|
return data ? (0, audit_1.withoutInternalId)(data) : null;
|
|
114
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* The organization behind a Paystack customer or subscription code. The codes live on
|
|
116
|
+
* `organization_payment_methods`, so the lookup goes through that row and embeds the
|
|
117
|
+
* organization it belongs to; a webhook then scopes to it with `forOrganization` for the
|
|
118
|
+
* payment method itself.
|
|
119
|
+
*/
|
|
120
|
+
async findOrganizationByPaymentMethod(column, value) {
|
|
121
|
+
const { data, error } = await this.supabase
|
|
122
|
+
.from('organization_payment_methods')
|
|
123
|
+
.select('organization:organizations(*)')
|
|
124
|
+
.eq(column, value)
|
|
125
|
+
.limit(1)
|
|
126
|
+
.maybeSingle();
|
|
127
|
+
if (error)
|
|
128
|
+
throw (0, errors_1.mapPostgrestError)(error);
|
|
129
|
+
const organization = data
|
|
130
|
+
?.organization;
|
|
131
|
+
return organization ? (0, audit_1.withoutInternalId)(organization) : null;
|
|
132
|
+
}
|
|
115
133
|
/**
|
|
116
134
|
* A ledger row by id alone. Also unscoped by necessity: a `charge.success` carries the
|
|
117
135
|
* transaction id in its metadata, and the row is what says which tenant it belongs to.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service-client/index.ts"],"names":[],"mappings":";;;AAAA,kCAA0C;AAC1C,oCAQkB;AAClB,0EAAuF;AAEvF,wCAA6C;AAC7C,kDAAuD;AACvD,oDAA+D;AAC/D,sCAA8C;AAC9C,kEAAsE;AACtE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service-client/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { type AuditActor, type AuditResource } from '../audit';
|
|
2
|
-
import type { TypedSupabaseClient } from '../client';
|
|
3
|
-
/** The two Paystack secrets an organization holds. Both null until the first successful charge. */
|
|
4
|
-
export type OrganizationPaystackCredentials = {
|
|
5
|
-
/** The saved card authorization every off-session charge is made against. */
|
|
6
|
-
paystack_customer_authorization_code: string | null;
|
|
7
|
-
/** Paired with the subscription code to disable or enable the subscription. */
|
|
8
|
-
paystack_subscription_email_token: string | null;
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* The `organization_paystack_credentials` table: the one row per organization that holds the
|
|
12
|
-
* card authorization code and the subscription email token. They used to be columns on
|
|
13
|
-
* `organizations`, where the tenant-scoped READ policy handed them to every member; here the
|
|
14
|
-
* table carries no `authenticated` grant and no policy, so only the service role can reach it.
|
|
15
|
-
*
|
|
16
|
-
* Service-role only, like the invites — this lives on the organization scope of the service
|
|
17
|
-
* client and never on a caller's client. Writes are audited against the organization (the row
|
|
18
|
-
* has no identity of its own), and the audit diff redacts every `paystack_*` column, so the trail
|
|
19
|
-
* records that a credential changed and never what it changed to.
|
|
20
|
-
*/
|
|
21
|
-
export declare class OrganizationPaystackCredentialsResource {
|
|
22
|
-
private readonly supabase;
|
|
23
|
-
private readonly actor;
|
|
24
|
-
private readonly audit;
|
|
25
|
-
constructor(supabase: TypedSupabaseClient, actor: AuditActor, audit: AuditResource);
|
|
26
|
-
/** The actor organization's credentials; both null when nothing has been stored yet. */
|
|
27
|
-
get(): Promise<OrganizationPaystackCredentials>;
|
|
28
|
-
/**
|
|
29
|
-
* Stores the given credentials, leaving the other untouched. Creates the row on first use;
|
|
30
|
-
* `null` clears a credential (a cancelled subscription's dead token must never be reused).
|
|
31
|
-
*/
|
|
32
|
-
set(patch: Partial<OrganizationPaystackCredentials>): Promise<void>;
|
|
33
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OrganizationPaystackCredentialsResource = void 0;
|
|
4
|
-
const enum_1 = require("@managemint-solutions/entities/audit-trail/enum");
|
|
5
|
-
const audit_1 = require("../audit");
|
|
6
|
-
const errors_1 = require("../errors");
|
|
7
|
-
const CREDENTIAL_COLUMNS = 'paystack_customer_authorization_code, paystack_subscription_email_token';
|
|
8
|
-
/**
|
|
9
|
-
* The `organization_paystack_credentials` table: the one row per organization that holds the
|
|
10
|
-
* card authorization code and the subscription email token. They used to be columns on
|
|
11
|
-
* `organizations`, where the tenant-scoped READ policy handed them to every member; here the
|
|
12
|
-
* table carries no `authenticated` grant and no policy, so only the service role can reach it.
|
|
13
|
-
*
|
|
14
|
-
* Service-role only, like the invites — this lives on the organization scope of the service
|
|
15
|
-
* client and never on a caller's client. Writes are audited against the organization (the row
|
|
16
|
-
* has no identity of its own), and the audit diff redacts every `paystack_*` column, so the trail
|
|
17
|
-
* records that a credential changed and never what it changed to.
|
|
18
|
-
*/
|
|
19
|
-
class OrganizationPaystackCredentialsResource {
|
|
20
|
-
supabase;
|
|
21
|
-
actor;
|
|
22
|
-
audit;
|
|
23
|
-
constructor(supabase, actor, audit) {
|
|
24
|
-
this.supabase = supabase;
|
|
25
|
-
this.actor = actor;
|
|
26
|
-
this.audit = audit;
|
|
27
|
-
}
|
|
28
|
-
/** The actor organization's credentials; both null when nothing has been stored yet. */
|
|
29
|
-
async get() {
|
|
30
|
-
const { data, error } = await this.supabase
|
|
31
|
-
.from('organization_paystack_credentials')
|
|
32
|
-
.select(CREDENTIAL_COLUMNS)
|
|
33
|
-
.eq('organization_id', this.actor.organization_id)
|
|
34
|
-
.maybeSingle();
|
|
35
|
-
if (error)
|
|
36
|
-
throw (0, errors_1.mapPostgrestError)(error);
|
|
37
|
-
const row = (data ?? {});
|
|
38
|
-
return {
|
|
39
|
-
paystack_customer_authorization_code: row.paystack_customer_authorization_code ?? null,
|
|
40
|
-
paystack_subscription_email_token: row.paystack_subscription_email_token ?? null,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Stores the given credentials, leaving the other untouched. Creates the row on first use;
|
|
45
|
-
* `null` clears a credential (a cancelled subscription's dead token must never be reused).
|
|
46
|
-
*/
|
|
47
|
-
async set(patch) {
|
|
48
|
-
const before = await this.get();
|
|
49
|
-
const after = { ...before, ...patch };
|
|
50
|
-
const { error } = await this.supabase
|
|
51
|
-
.from('organization_paystack_credentials')
|
|
52
|
-
.upsert({
|
|
53
|
-
organization_id: this.actor.organization_id,
|
|
54
|
-
...after,
|
|
55
|
-
updated_at: new Date().toISOString(),
|
|
56
|
-
}, { onConflict: 'organization_id' });
|
|
57
|
-
if (error)
|
|
58
|
-
throw (0, errors_1.mapPostgrestError)(error);
|
|
59
|
-
const changes = (0, audit_1.diffChanges)(before, after);
|
|
60
|
-
if (Object.keys(changes).length === 0)
|
|
61
|
-
return;
|
|
62
|
-
await this.audit.record({
|
|
63
|
-
action: enum_1.AuditTrailAction.UPDATE,
|
|
64
|
-
entityType: enum_1.AuditTrailEntityType.ORGANIZATION,
|
|
65
|
-
entityId: this.actor.organization_id,
|
|
66
|
-
changes,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
exports.OrganizationPaystackCredentialsResource = OrganizationPaystackCredentialsResource;
|
|
71
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/organization-paystack-credentials/index.ts"],"names":[],"mappings":";;;AAAA,0EAAyG;AACzG,oCAA2F;AAE3F,sCAA8C;AAU9C,MAAM,kBAAkB,GAAG,yEAAyE,CAAC;AAErG;;;;;;;;;;GAUG;AACH,MAAa,uCAAuC;IAE/B;IACA;IACA;IAHnB,YACmB,QAA6B,EAC7B,KAAiB,EACjB,KAAoB;QAFpB,aAAQ,GAAR,QAAQ,CAAqB;QAC7B,UAAK,GAAL,KAAK,CAAY;QACjB,UAAK,GAAL,KAAK,CAAe;IACpC,CAAC;IAEJ,wFAAwF;IACxF,KAAK,CAAC,GAAG;QACP,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aACxC,IAAI,CAAC,mCAAmC,CAAC;aACzC,MAAM,CAAC,kBAAkB,CAAC;aAC1B,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC;aACjD,WAAW,EAAE,CAAC;QACjB,IAAI,KAAK;YAAE,MAAM,IAAA,0BAAiB,EAAC,KAAK,CAAC,CAAC;QAE1C,MAAM,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAA6C,CAAC;QAErE,OAAO;YACL,oCAAoC,EAAE,GAAG,CAAC,oCAAoC,IAAI,IAAI;YACtF,iCAAiC,EAAE,GAAG,CAAC,iCAAiC,IAAI,IAAI;SACjF,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,KAA+C;QACvD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,KAAK,GAAoC,EAAE,GAAG,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QAEvE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aAClC,IAAI,CAAC,mCAAmC,CAAC;aACzC,MAAM,CACL;YACE,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe;YAC3C,GAAG,KAAK;YACR,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACrC,EACD,EAAE,UAAU,EAAE,iBAAiB,EAAE,CAClC,CAAC;QACJ,IAAI,KAAK;YAAE,MAAM,IAAA,0BAAiB,EAAC,KAAK,CAAC,CAAC;QAE1C,MAAM,OAAO,GAAG,IAAA,mBAAW,EAAC,MAAkB,EAAE,KAAiB,CAAC,CAAC;QACnE,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAE9C,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YACtB,MAAM,EAAE,uBAAgB,CAAC,MAAM;YAC/B,UAAU,EAAE,2BAAoB,CAAC,YAAY;YAC7C,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe;YACpC,OAAO;SACR,CAAC,CAAC;IACL,CAAC;CACF;AAtDD,0FAsDC"}
|