shutro-erp 0.3.1 → 0.3.3
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/account_portal/.kosh/bindings.js +1 -1
- package/dist/account_portal/.kosh/schema.d.ts +29 -1
- package/dist/account_portal/index.js +3 -2
- package/dist/accounting/.kosh/bindings.js +1 -1
- package/dist/accounting/.kosh/schema.d.ts +29 -1
- package/dist/accounting/index.js +4 -0
- package/dist/assistant/index.js +1 -1
- package/dist/cli/init.js +2 -0
- package/dist/cli/launch.js +8 -5
- package/dist/cli/templates.js +4 -1
- package/dist/cli/ui.js +19 -1
- package/dist/contacts/.kosh/bindings.js +1 -1
- package/dist/contacts/.kosh/schema.d.ts +29 -1
- package/dist/integrations/inbound.d.ts +36 -0
- package/dist/integrations/inbound.js +171 -0
- package/dist/integrations/index.d.ts +18 -0
- package/dist/integrations/index.js +400 -0
- package/dist/integrations/models.d.ts +6 -0
- package/dist/integrations/models.js +119 -0
- package/dist/integrations/web/DeliveryTools.d.ts +4 -0
- package/dist/integrations/web/DeliveryTools.js +15 -0
- package/dist/integrations/web/EndpointTools.d.ts +7 -0
- package/dist/integrations/web/EndpointTools.js +25 -0
- package/dist/integrations/web/InboundTools.d.ts +4 -0
- package/dist/integrations/web/InboundTools.js +15 -0
- package/dist/integrations/web/WebhookTools.d.ts +7 -0
- package/dist/integrations/web/WebhookTools.js +25 -0
- package/dist/integrations/web/index.d.ts +16 -0
- package/dist/integrations/web/index.js +27 -0
- package/dist/integrations/web/messages.d.ts +2 -0
- package/dist/integrations/web/messages.js +53 -0
- package/dist/integrations/webhooks.d.ts +63 -0
- package/dist/integrations/webhooks.js +217 -0
- package/dist/l10n_bd/.kosh/bindings.js +1 -1
- package/dist/l10n_bd/.kosh/schema.d.ts +29 -1
- package/dist/l10n_in/.kosh/bindings.js +1 -1
- package/dist/l10n_in/.kosh/schema.d.ts +29 -4
- package/dist/l10n_in/module.d.ts +0 -62
- package/dist/l10n_in/module.js +2 -4
- package/dist/modules-sdk/index.d.ts +1 -1
- package/dist/modules-sdk/manifest.d.ts +48 -0
- package/dist/payment/.kosh/bindings.d.ts +22 -0
- package/dist/payment/.kosh/bindings.js +15 -0
- package/dist/payment/.kosh/schema.d.ts +1581 -0
- package/dist/payment/bkash.d.ts +28 -0
- package/dist/payment/bkash.js +169 -0
- package/dist/payment/index.d.ts +38 -0
- package/dist/payment/index.js +431 -0
- package/dist/payment/module.d.ts +6856 -0
- package/dist/payment/module.js +77 -0
- package/dist/payment/money.d.ts +7 -0
- package/dist/payment/money.js +37 -0
- package/dist/payment/providers.d.ts +75 -0
- package/dist/payment/providers.js +77 -0
- package/dist/payment/razorpay.d.ts +12 -0
- package/dist/payment/razorpay.js +149 -0
- package/dist/payment/settle.d.ts +11 -0
- package/dist/payment/settle.js +59 -0
- package/dist/payment/sslcommerz.d.ts +12 -0
- package/dist/payment/sslcommerz.js +185 -0
- package/dist/payment/stripe.d.ts +15 -0
- package/dist/payment/stripe.js +182 -0
- package/dist/permissions/admin.d.ts +3 -0
- package/dist/permissions/admin.js +108 -10
- package/dist/permissions/index.d.ts +1 -0
- package/dist/permissions/index.js +3 -0
- package/dist/permissions/roles.d.ts +2 -0
- package/dist/permissions/roles.js +236 -0
- package/dist/portal/.kosh/bindings.js +1 -1
- package/dist/portal/.kosh/schema.d.ts +29 -1
- package/dist/portal/routes-documents.js +5 -0
- package/dist/product/.kosh/bindings.js +1 -1
- package/dist/product/.kosh/schema.d.ts +29 -1
- package/dist/project/.kosh/bindings.js +1 -1
- package/dist/project/.kosh/schema.d.ts +29 -1
- package/dist/project_portal/.kosh/bindings.js +1 -1
- package/dist/project_portal/.kosh/schema.d.ts +29 -1
- package/dist/purchase/.kosh/bindings.js +1 -1
- package/dist/purchase/.kosh/schema.d.ts +29 -1
- package/dist/purchase_account/.kosh/bindings.js +1 -1
- package/dist/purchase_account/.kosh/schema.d.ts +29 -1
- package/dist/purchase_portal/.kosh/bindings.js +1 -1
- package/dist/purchase_portal/.kosh/schema.d.ts +29 -1
- package/dist/sale_account/.kosh/bindings.js +1 -1
- package/dist/sale_account/.kosh/schema.d.ts +29 -1
- package/dist/sale_portal/.kosh/bindings.js +1 -1
- package/dist/sale_portal/.kosh/schema.d.ts +29 -1
- package/dist/sale_project/.kosh/bindings.js +1 -1
- package/dist/sale_project/.kosh/schema.d.ts +29 -1
- package/dist/sales/.kosh/bindings.js +1 -1
- package/dist/sales/.kosh/schema.d.ts +29 -1
- package/dist/sales/index.js +2 -0
- package/dist/server/api/rest.d.ts +6 -1
- package/dist/server/api/rest.js +11 -0
- package/dist/server/auth/base.js +22 -0
- package/dist/server/auth/routes.d.ts +3 -0
- package/dist/server/auth/routes.js +29 -0
- package/dist/server/auth/service.d.ts +52 -0
- package/dist/server/auth/service.js +168 -3
- package/dist/server/identity.d.ts +2 -0
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +1 -1
- package/dist/server/server.js +11 -3
- package/dist/settings/company.d.ts +34 -0
- package/dist/settings/company.js +187 -0
- package/dist/settings/index.d.ts +10 -10
- package/dist/settings/index.js +159 -30
- package/dist/settings/people.d.ts +16 -0
- package/dist/settings/people.js +505 -0
- package/dist/settings/security.d.ts +13 -0
- package/dist/settings/security.js +158 -0
- package/dist/settings/web/AuditPage.d.ts +8 -0
- package/dist/settings/web/AuditPage.js +74 -0
- package/dist/settings/web/CompaniesPage.d.ts +8 -0
- package/dist/settings/web/CompaniesPage.js +52 -0
- package/dist/settings/web/CompanyPage.d.ts +9 -0
- package/dist/settings/web/CompanyPage.js +94 -0
- package/dist/settings/web/OverviewPage.d.ts +9 -0
- package/dist/settings/web/OverviewPage.js +66 -0
- package/dist/settings/web/PeoplePage.d.ts +9 -0
- package/dist/settings/web/PeoplePage.js +163 -0
- package/dist/settings/web/ProfilePage.d.ts +14 -0
- package/dist/settings/web/ProfilePage.js +194 -0
- package/dist/settings/web/RolesEditor.d.ts +35 -0
- package/dist/settings/web/RolesEditor.js +49 -0
- package/dist/settings/web/RolesPage.d.ts +9 -0
- package/dist/settings/web/RolesPage.js +296 -0
- package/dist/settings/web/SecurityPage.d.ts +8 -0
- package/dist/settings/web/SecurityPage.js +81 -0
- package/dist/settings/web/index.d.ts +9 -0
- package/dist/settings/web/index.js +26 -1
- package/dist/settings/web/messages.js +566 -0
- package/dist/ui/api.d.ts +4 -0
- package/dist/ui/app.d.ts +5 -0
- package/dist/ui/app.js +108 -31
- package/dist/ui/components/primitives.d.ts +9 -1
- package/dist/ui/components/primitives.js +12 -4
- package/dist/ui/context.d.ts +10 -1
- package/dist/ui/context.js +60 -2
- package/dist/ui/i18n/messages.d.ts +46 -0
- package/dist/ui/i18n/messages.js +92 -0
- package/dist/ui/index.d.ts +2 -1
- package/dist/ui/index.js +2 -1
- package/dist/ui/lib/accent.d.ts +13 -0
- package/dist/ui/lib/accent.js +36 -0
- package/dist/ui/shell/Activate.d.ts +6 -0
- package/dist/ui/shell/Activate.js +39 -0
- package/dist/ui/shell/CommandPalette.d.ts +7 -1
- package/dist/ui/shell/CommandPalette.js +16 -2
- package/dist/ui/shell/Sidebar.d.ts +27 -0
- package/dist/ui/shell/Sidebar.js +84 -0
- package/dist/ui/shell/TwoFactorSetup.d.ts +5 -0
- package/dist/ui/shell/TwoFactorSetup.js +32 -0
- package/dist/ui/shell/shortcuts.d.ts +3 -0
- package/dist/ui/shell/shortcuts.js +13 -4
- package/dist/ui/styles.css +70 -28
- package/dist/ui/views/DateField.d.ts +10 -0
- package/dist/ui/views/DateField.js +129 -0
- package/dist/ui/views/FormView.js +161 -21
- package/dist/ui/views/ListView.d.ts +2 -0
- package/dist/ui/views/ListView.js +8 -3
- package/dist/ui/views/StatusChip.d.ts +10 -0
- package/dist/ui/views/StatusChip.js +22 -0
- package/dist/ui/views/widgets.d.ts +3 -0
- package/dist/ui/views/widgets.js +26 -8
- package/dist/views/types.d.ts +7 -0
- package/dist/views/validate.js +4 -0
- package/package.json +14 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash:
|
|
1
|
+
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 2bbbe12acf870fd9
|
|
2
2
|
// Schema view of module `purchase_portal` (RFC 0002 §7.7): the models it owns or depends on, with the extensions it can see.
|
|
3
3
|
import type { F } from '../../server/orm.js';
|
|
4
4
|
|
|
@@ -11,6 +11,7 @@ export interface SchemaView {
|
|
|
11
11
|
readonly 'audit.event': AuditEvent;
|
|
12
12
|
readonly 'auth.api_key': AuthApiKey;
|
|
13
13
|
readonly 'auth.credential': AuthCredential;
|
|
14
|
+
readonly 'auth.policy': AuthPolicy;
|
|
14
15
|
readonly 'auth.session': AuthSession;
|
|
15
16
|
readonly 'auth.user_grant': AuthUserGrant;
|
|
16
17
|
readonly 'auth.user_group': AuthUserGroup;
|
|
@@ -222,6 +223,26 @@ export interface AuthCredential {
|
|
|
222
223
|
export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
|
|
223
224
|
}
|
|
224
225
|
|
|
226
|
+
/** `auth.policy` (owner: base). */
|
|
227
|
+
export interface AuthPolicy {
|
|
228
|
+
readonly name: 'auth.policy';
|
|
229
|
+
readonly fields: {
|
|
230
|
+
readonly id: F.Id<'auth.policy'>;
|
|
231
|
+
readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
232
|
+
readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
233
|
+
readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
234
|
+
readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
235
|
+
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
236
|
+
readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
|
|
237
|
+
readonly sessionDays: F.Integer;
|
|
238
|
+
};
|
|
239
|
+
readonly methods: AuthPolicyMethods;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Methods of `auth.policy`: declared ones and transitions. */
|
|
243
|
+
export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
|
|
244
|
+
}
|
|
245
|
+
|
|
225
246
|
/** `auth.session` (owner: base). */
|
|
226
247
|
export interface AuthSession {
|
|
227
248
|
readonly name: 'auth.session';
|
|
@@ -706,6 +727,13 @@ export interface ResCompany {
|
|
|
706
727
|
readonly name: F.Char<{ readonly required: true }>;
|
|
707
728
|
readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
|
|
708
729
|
readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
|
|
730
|
+
readonly accentColor: F.Char;
|
|
731
|
+
readonly street: F.Char;
|
|
732
|
+
readonly city: F.Char;
|
|
733
|
+
readonly zip: F.Char;
|
|
734
|
+
readonly email: F.Char;
|
|
735
|
+
readonly phone: F.Char;
|
|
736
|
+
readonly website: F.Char;
|
|
709
737
|
};
|
|
710
738
|
readonly methods: ResCompanyMethods;
|
|
711
739
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash:
|
|
1
|
+
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: b268ad86cd210c36
|
|
2
2
|
// Bindings of module `sale_account`: import the definition API from here to get types scoped to what it can see.
|
|
3
3
|
export { defineModel, defineModule, extendModel, f, replace } from '../../server/orm.js';
|
|
4
4
|
import { definitions } from '../../server/orm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash:
|
|
1
|
+
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: b268ad86cd210c36
|
|
2
2
|
// Schema view of module `sale_account` (RFC 0002 §7.7): the models it owns or depends on, with the extensions it can see.
|
|
3
3
|
import type { F } from '../../server/orm.js';
|
|
4
4
|
|
|
@@ -24,6 +24,7 @@ export interface SchemaView {
|
|
|
24
24
|
readonly 'audit.event': AuditEvent;
|
|
25
25
|
readonly 'auth.api_key': AuthApiKey;
|
|
26
26
|
readonly 'auth.credential': AuthCredential;
|
|
27
|
+
readonly 'auth.policy': AuthPolicy;
|
|
27
28
|
readonly 'auth.session': AuthSession;
|
|
28
29
|
readonly 'auth.user_grant': AuthUserGrant;
|
|
29
30
|
readonly 'auth.user_group': AuthUserGroup;
|
|
@@ -634,6 +635,26 @@ export interface AuthCredential {
|
|
|
634
635
|
export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
|
|
635
636
|
}
|
|
636
637
|
|
|
638
|
+
/** `auth.policy` (owner: base). */
|
|
639
|
+
export interface AuthPolicy {
|
|
640
|
+
readonly name: 'auth.policy';
|
|
641
|
+
readonly fields: {
|
|
642
|
+
readonly id: F.Id<'auth.policy'>;
|
|
643
|
+
readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
644
|
+
readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
645
|
+
readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
646
|
+
readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
647
|
+
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
648
|
+
readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
|
|
649
|
+
readonly sessionDays: F.Integer;
|
|
650
|
+
};
|
|
651
|
+
readonly methods: AuthPolicyMethods;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/** Methods of `auth.policy`: declared ones and transitions. */
|
|
655
|
+
export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
|
|
656
|
+
}
|
|
657
|
+
|
|
637
658
|
/** `auth.session` (owner: base). */
|
|
638
659
|
export interface AuthSession {
|
|
639
660
|
readonly name: 'auth.session';
|
|
@@ -1128,6 +1149,13 @@ export interface ResCompany {
|
|
|
1128
1149
|
readonly name: F.Char<{ readonly required: true }>;
|
|
1129
1150
|
readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
|
|
1130
1151
|
readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
|
|
1152
|
+
readonly accentColor: F.Char;
|
|
1153
|
+
readonly street: F.Char;
|
|
1154
|
+
readonly city: F.Char;
|
|
1155
|
+
readonly zip: F.Char;
|
|
1156
|
+
readonly email: F.Char;
|
|
1157
|
+
readonly phone: F.Char;
|
|
1158
|
+
readonly website: F.Char;
|
|
1131
1159
|
readonly fiscalYearStart: F.Integer<{ readonly required: true; readonly default: true }>; // accounting
|
|
1132
1160
|
readonly chartTemplate: F.Char; // accounting
|
|
1133
1161
|
readonly country: F.Char; // accounting
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash:
|
|
1
|
+
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 2377e830cd00a651
|
|
2
2
|
// Bindings of module `sale_portal`: import the definition API from here to get types scoped to what it can see.
|
|
3
3
|
export { defineModel, defineModule, extendModel, f, replace } from '../../server/orm.js';
|
|
4
4
|
import { definitions } from '../../server/orm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash:
|
|
1
|
+
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 2377e830cd00a651
|
|
2
2
|
// Schema view of module `sale_portal` (RFC 0002 §7.7): the models it owns or depends on, with the extensions it can see.
|
|
3
3
|
import type { F } from '../../server/orm.js';
|
|
4
4
|
|
|
@@ -8,6 +8,7 @@ export interface SchemaView {
|
|
|
8
8
|
readonly 'audit.event': AuditEvent;
|
|
9
9
|
readonly 'auth.api_key': AuthApiKey;
|
|
10
10
|
readonly 'auth.credential': AuthCredential;
|
|
11
|
+
readonly 'auth.policy': AuthPolicy;
|
|
11
12
|
readonly 'auth.session': AuthSession;
|
|
12
13
|
readonly 'auth.user_grant': AuthUserGrant;
|
|
13
14
|
readonly 'auth.user_group': AuthUserGroup;
|
|
@@ -139,6 +140,26 @@ export interface AuthCredential {
|
|
|
139
140
|
export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
|
|
140
141
|
}
|
|
141
142
|
|
|
143
|
+
/** `auth.policy` (owner: base). */
|
|
144
|
+
export interface AuthPolicy {
|
|
145
|
+
readonly name: 'auth.policy';
|
|
146
|
+
readonly fields: {
|
|
147
|
+
readonly id: F.Id<'auth.policy'>;
|
|
148
|
+
readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
149
|
+
readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
150
|
+
readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
151
|
+
readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
152
|
+
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
153
|
+
readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
|
|
154
|
+
readonly sessionDays: F.Integer;
|
|
155
|
+
};
|
|
156
|
+
readonly methods: AuthPolicyMethods;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Methods of `auth.policy`: declared ones and transitions. */
|
|
160
|
+
export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
|
|
161
|
+
}
|
|
162
|
+
|
|
142
163
|
/** `auth.session` (owner: base). */
|
|
143
164
|
export interface AuthSession {
|
|
144
165
|
readonly name: 'auth.session';
|
|
@@ -552,6 +573,13 @@ export interface ResCompany {
|
|
|
552
573
|
readonly name: F.Char<{ readonly required: true }>;
|
|
553
574
|
readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
|
|
554
575
|
readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
|
|
576
|
+
readonly accentColor: F.Char;
|
|
577
|
+
readonly street: F.Char;
|
|
578
|
+
readonly city: F.Char;
|
|
579
|
+
readonly zip: F.Char;
|
|
580
|
+
readonly email: F.Char;
|
|
581
|
+
readonly phone: F.Char;
|
|
582
|
+
readonly website: F.Char;
|
|
555
583
|
};
|
|
556
584
|
readonly methods: ResCompanyMethods;
|
|
557
585
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash:
|
|
1
|
+
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: b044bca835096ac0
|
|
2
2
|
// Bindings of module `sale_project`: import the definition API from here to get types scoped to what it can see.
|
|
3
3
|
export { defineModel, defineModule, extendModel, f, replace } from '../../server/orm.js';
|
|
4
4
|
import { definitions } from '../../server/orm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash:
|
|
1
|
+
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: b044bca835096ac0
|
|
2
2
|
// Schema view of module `sale_project` (RFC 0002 §7.7): the models it owns or depends on, with the extensions it can see.
|
|
3
3
|
import type { F } from '../../server/orm.js';
|
|
4
4
|
|
|
@@ -8,6 +8,7 @@ export interface SchemaView {
|
|
|
8
8
|
readonly 'audit.event': AuditEvent;
|
|
9
9
|
readonly 'auth.api_key': AuthApiKey;
|
|
10
10
|
readonly 'auth.credential': AuthCredential;
|
|
11
|
+
readonly 'auth.policy': AuthPolicy;
|
|
11
12
|
readonly 'auth.session': AuthSession;
|
|
12
13
|
readonly 'auth.user_grant': AuthUserGrant;
|
|
13
14
|
readonly 'auth.user_group': AuthUserGroup;
|
|
@@ -140,6 +141,26 @@ export interface AuthCredential {
|
|
|
140
141
|
export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
|
|
141
142
|
}
|
|
142
143
|
|
|
144
|
+
/** `auth.policy` (owner: base). */
|
|
145
|
+
export interface AuthPolicy {
|
|
146
|
+
readonly name: 'auth.policy';
|
|
147
|
+
readonly fields: {
|
|
148
|
+
readonly id: F.Id<'auth.policy'>;
|
|
149
|
+
readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
150
|
+
readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
151
|
+
readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
152
|
+
readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
153
|
+
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
154
|
+
readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
|
|
155
|
+
readonly sessionDays: F.Integer;
|
|
156
|
+
};
|
|
157
|
+
readonly methods: AuthPolicyMethods;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Methods of `auth.policy`: declared ones and transitions. */
|
|
161
|
+
export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
|
|
162
|
+
}
|
|
163
|
+
|
|
143
164
|
/** `auth.session` (owner: base). */
|
|
144
165
|
export interface AuthSession {
|
|
145
166
|
readonly name: 'auth.session';
|
|
@@ -596,6 +617,13 @@ export interface ResCompany {
|
|
|
596
617
|
readonly name: F.Char<{ readonly required: true }>;
|
|
597
618
|
readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
|
|
598
619
|
readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
|
|
620
|
+
readonly accentColor: F.Char;
|
|
621
|
+
readonly street: F.Char;
|
|
622
|
+
readonly city: F.Char;
|
|
623
|
+
readonly zip: F.Char;
|
|
624
|
+
readonly email: F.Char;
|
|
625
|
+
readonly phone: F.Char;
|
|
626
|
+
readonly website: F.Char;
|
|
599
627
|
};
|
|
600
628
|
readonly methods: ResCompanyMethods;
|
|
601
629
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash:
|
|
1
|
+
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 2d9d91e59673d178
|
|
2
2
|
// Bindings of module `sales`: import the definition API from here to get types scoped to what it can see.
|
|
3
3
|
export { defineModel, defineModule, extendModel, f, replace } from '../../server/orm.js';
|
|
4
4
|
import { definitions } from '../../server/orm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash:
|
|
1
|
+
// GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 2d9d91e59673d178
|
|
2
2
|
// Schema view of module `sales` (RFC 0002 §7.7): the models it owns or depends on, with the extensions it can see.
|
|
3
3
|
import type { F } from '../../server/orm.js';
|
|
4
4
|
|
|
@@ -8,6 +8,7 @@ export interface SchemaView {
|
|
|
8
8
|
readonly 'audit.event': AuditEvent;
|
|
9
9
|
readonly 'auth.api_key': AuthApiKey;
|
|
10
10
|
readonly 'auth.credential': AuthCredential;
|
|
11
|
+
readonly 'auth.policy': AuthPolicy;
|
|
11
12
|
readonly 'auth.session': AuthSession;
|
|
12
13
|
readonly 'auth.user_grant': AuthUserGrant;
|
|
13
14
|
readonly 'auth.user_group': AuthUserGroup;
|
|
@@ -136,6 +137,26 @@ export interface AuthCredential {
|
|
|
136
137
|
export interface AuthCredentialMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.credential'> {
|
|
137
138
|
}
|
|
138
139
|
|
|
140
|
+
/** `auth.policy` (owner: base). */
|
|
141
|
+
export interface AuthPolicy {
|
|
142
|
+
readonly name: 'auth.policy';
|
|
143
|
+
readonly fields: {
|
|
144
|
+
readonly id: F.Id<'auth.policy'>;
|
|
145
|
+
readonly createdAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
146
|
+
readonly updatedAt: F.Datetime<{ readonly required: true; readonly readonly: true }>;
|
|
147
|
+
readonly createdBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
148
|
+
readonly updatedBy: F.Many2one<'res.users', { readonly readonly: true }>;
|
|
149
|
+
readonly displayName: F.Char<{ readonly required: true; readonly readonly: true; readonly compute: true }>;
|
|
150
|
+
readonly twoFactor: F.Selection<'administrators' | 'everyone', { readonly required: true; readonly default: true }>;
|
|
151
|
+
readonly sessionDays: F.Integer;
|
|
152
|
+
};
|
|
153
|
+
readonly methods: AuthPolicyMethods;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Methods of `auth.policy`: declared ones and transitions. */
|
|
157
|
+
export interface AuthPolicyMethods extends F.Methods<typeof import('../../server/index.js').baseShutro, 'auth.policy'> {
|
|
158
|
+
}
|
|
159
|
+
|
|
139
160
|
/** `auth.session` (owner: base). */
|
|
140
161
|
export interface AuthSession {
|
|
141
162
|
readonly name: 'auth.session';
|
|
@@ -477,6 +498,13 @@ export interface ResCompany {
|
|
|
477
498
|
readonly name: F.Char<{ readonly required: true }>;
|
|
478
499
|
readonly currency: F.Many2one<'res.currency', { readonly required: true }>;
|
|
479
500
|
readonly numberGrouping: F.Selection<'international' | 'lakh', { readonly required: true; readonly default: true }>;
|
|
501
|
+
readonly accentColor: F.Char;
|
|
502
|
+
readonly street: F.Char;
|
|
503
|
+
readonly city: F.Char;
|
|
504
|
+
readonly zip: F.Char;
|
|
505
|
+
readonly email: F.Char;
|
|
506
|
+
readonly phone: F.Char;
|
|
507
|
+
readonly website: F.Char;
|
|
480
508
|
};
|
|
481
509
|
readonly methods: ResCompanyMethods;
|
|
482
510
|
}
|
package/dist/sales/index.js
CHANGED
|
@@ -17,6 +17,8 @@ export const sales = defineModule({
|
|
|
17
17
|
kosh: '^0.1.0',
|
|
18
18
|
hooks: { demo: salesDemo },
|
|
19
19
|
depends: [contacts, product, messaging],
|
|
20
|
+
// What webhooks may subscribe to besides record changes (RFC 0017 §5.3).
|
|
21
|
+
events: [{ topic: 'sale.order.confirmed', model: 'sale.order', label: 'Sales order confirmed' }],
|
|
20
22
|
app: {
|
|
21
23
|
code: 'sales',
|
|
22
24
|
label: 'Sales',
|
|
@@ -17,8 +17,13 @@
|
|
|
17
17
|
* - `GET /api/v1/openapi.json` the OpenAPI 3.1 document
|
|
18
18
|
*/
|
|
19
19
|
import type { FastifyInstance } from 'fastify';
|
|
20
|
-
import type { Driver } from '../orm.js';
|
|
20
|
+
import type { Driver, Env } from '../orm.js';
|
|
21
21
|
import { type ApiModel } from './metadata.js';
|
|
22
|
+
/**
|
|
23
|
+
* A record as `GET /api/v1/models/<model>/<id>` returns it to `env`'s user (their readable default fields), or null
|
|
24
|
+
* when they cannot see it: what webhooks send (RFC 0017 §5.3).
|
|
25
|
+
*/
|
|
26
|
+
export declare function readApiRecord(env: Env, model: ApiModel, id: number): Promise<Record<string, unknown> | null>;
|
|
22
27
|
/** Registers the generated routes for `models`. */
|
|
23
28
|
export declare function registerRestApi(app: FastifyInstance, options: {
|
|
24
29
|
readonly models: ReadonlyMap<string, ApiModel>;
|
package/dist/server/api/rest.js
CHANGED
|
@@ -102,6 +102,17 @@ function ifMatch(request) {
|
|
|
102
102
|
throw problem(400, 'invalid-if-match', 'Invalid If-Match', 'If-Match must be an ETag returned by this API.');
|
|
103
103
|
return new Date(Number(m[1]));
|
|
104
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* A record as `GET /api/v1/models/<model>/<id>` returns it to `env`'s user (their readable default fields), or null
|
|
107
|
+
* when they cannot see it: what webhooks send (RFC 0017 §5.3).
|
|
108
|
+
*/
|
|
109
|
+
export async function readApiRecord(env, model, id) {
|
|
110
|
+
const set = await ref(env, model.name).search({ where: { id }, limit: 1 });
|
|
111
|
+
if (set.length === 0)
|
|
112
|
+
return null;
|
|
113
|
+
const [row] = await rows(set, fieldsOf(model, env, undefined));
|
|
114
|
+
return row ?? null;
|
|
115
|
+
}
|
|
105
116
|
async function record(env, model, id, fields) {
|
|
106
117
|
const set = await ref(env, model.name).browse([id]).load(['id', 'updatedAt']);
|
|
107
118
|
const [row] = await rows(set, fields ?? fieldsOf(model, env, undefined));
|
package/dist/server/auth/base.js
CHANGED
|
@@ -22,6 +22,15 @@ const ResCompany = defineModel('res.company', {
|
|
|
22
22
|
currency: f.many2one('res.currency', { required: true }),
|
|
23
23
|
/** How numbers are grouped on screen and in documents (RFC 0016): 1,234,567 or 12,34,567 (lakh and crore). */
|
|
24
24
|
numberGrouping: f.selection({ international: 'International (1,234,567)', lakh: 'Lakh and crore (12,34,567)' }, { required: true, default: 'international', label: 'Number grouping' }),
|
|
25
|
+
/** The company's brand colour (`#4f46e5`), the back-office's accent (RFC 0018); the default when empty. */
|
|
26
|
+
accentColor: f.char({ size: 7, label: 'Brand colour' }),
|
|
27
|
+
/** Its address and how to reach it (RFC 0019 §3.4): on documents, e-invoices and the portal. */
|
|
28
|
+
street: f.char({ label: 'Address' }),
|
|
29
|
+
city: f.char({ label: 'City' }),
|
|
30
|
+
zip: f.char({ size: 12, label: 'Postal code' }),
|
|
31
|
+
email: f.char({ label: 'Email' }),
|
|
32
|
+
phone: f.char({ label: 'Phone' }),
|
|
33
|
+
website: f.char({ label: 'Website' }),
|
|
25
34
|
},
|
|
26
35
|
});
|
|
27
36
|
const readRows = async (env, model, ids, keys) => env.asSuperuser({ reason: 'check administrators' }, async (su) => {
|
|
@@ -127,6 +136,17 @@ const AuthUserGrant = defineModel('auth.user_grant', {
|
|
|
127
136
|
reason: f.char({ required: true }),
|
|
128
137
|
},
|
|
129
138
|
});
|
|
139
|
+
/**
|
|
140
|
+
* The installation's security policy (RFC 0019 §3.5): one row, read by the auth service, changed in Settings ›
|
|
141
|
+
* Security. Without a row: two-factor sign-in for administrators only, sessions as the server is configured.
|
|
142
|
+
*/
|
|
143
|
+
const AuthPolicy = defineModel('auth.policy', {
|
|
144
|
+
fields: {
|
|
145
|
+
twoFactor: f.selection({ administrators: 'Administrators', everyone: 'Everyone' }, { required: true, default: 'administrators', label: 'Two-factor sign-in required for' }),
|
|
146
|
+
/** Days a sign-in lasts at most; empty: the server's setting. */
|
|
147
|
+
sessionDays: f.integer({ label: 'Session lifetime (days)' }),
|
|
148
|
+
},
|
|
149
|
+
});
|
|
130
150
|
/**
|
|
131
151
|
* The security audit log (CLAUDE.md: logins, permission changes, exports, sensitive actions). Append-only: no one
|
|
132
152
|
* may change or delete events (administrators included: the REST API never serves it, and the admin API only reads).
|
|
@@ -196,6 +216,7 @@ export const baseShutro = defineModule({
|
|
|
196
216
|
AuthApiKey,
|
|
197
217
|
AuthUserGroup,
|
|
198
218
|
AuthUserGrant,
|
|
219
|
+
AuthPolicy,
|
|
199
220
|
AuditEvent,
|
|
200
221
|
SavedView,
|
|
201
222
|
],
|
|
@@ -214,6 +235,7 @@ export const base = defineKoshModule({
|
|
|
214
235
|
'auth.api_key',
|
|
215
236
|
'auth.user_group',
|
|
216
237
|
'auth.user_grant',
|
|
238
|
+
'auth.policy',
|
|
217
239
|
'audit.event',
|
|
218
240
|
],
|
|
219
241
|
});
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
* - `POST /api/v1/auth/2fa/verify` `{ code }` (TOTP or recovery code) completes a pending sign-in
|
|
11
11
|
* - `POST /api/v1/auth/2fa/disable` `{ password, code }`
|
|
12
12
|
* - `POST /api/v1/auth/password` `{ current, next }`; other sessions are revoked
|
|
13
|
+
* - `GET /api/v1/auth/profile` your details (RFC 0019); `PATCH` `{ name?, email?, phone?, lang?, tz?, company? }`
|
|
14
|
+
* - `GET /api/v1/auth/sessions` your signed-in devices; `DELETE …/sessions/:id` signs one out
|
|
15
|
+
* - `POST /api/v1/auth/sessions/sign-out-others`
|
|
13
16
|
*/
|
|
14
17
|
import type { FastifyInstance } from 'fastify';
|
|
15
18
|
import type { AuthService } from './service.js';
|
|
@@ -52,4 +52,33 @@ export function registerAuthRoutes(app, auth, options = {}) {
|
|
|
52
52
|
await auth.changePassword(await auth.requireSession(request), text(request, 'current'), text(request, 'next'));
|
|
53
53
|
return { ok: true };
|
|
54
54
|
});
|
|
55
|
+
// Your own profile and sessions (RFC 0019 §3.6): a session's, never an API key's.
|
|
56
|
+
app.get('/api/v1/auth/profile', { config: { auth: false } }, async (request) => auth.profile(await auth.requireSession(request)));
|
|
57
|
+
app.patch('/api/v1/auth/profile', { config: { auth: false } }, async (request) => {
|
|
58
|
+
const body = (request.body ?? {});
|
|
59
|
+
const values = {};
|
|
60
|
+
for (const key of ['name', 'email', 'phone', 'lang', 'tz'])
|
|
61
|
+
if (body[key] !== undefined) {
|
|
62
|
+
if (body[key] !== null &&
|
|
63
|
+
(typeof body[key] !== 'string' || body[key].length > 200))
|
|
64
|
+
throw new HttpProblem(400, 'invalid-body', 'Invalid body', `'${key}' is a short text.`);
|
|
65
|
+
values[key] = body[key];
|
|
66
|
+
}
|
|
67
|
+
if (body['company'] !== undefined) {
|
|
68
|
+
if (!Number.isSafeInteger(body['company']))
|
|
69
|
+
throw new HttpProblem(400, 'invalid-body', 'Invalid body', "'company' is a company id.");
|
|
70
|
+
values['company'] = body['company'];
|
|
71
|
+
}
|
|
72
|
+
return auth.updateProfile(await auth.requireSession(request), values);
|
|
73
|
+
});
|
|
74
|
+
app.get('/api/v1/auth/sessions', { config: { auth: false } }, async (request) => ({
|
|
75
|
+
sessions: await auth.sessions(await auth.requireSession(request)),
|
|
76
|
+
}));
|
|
77
|
+
app.delete('/api/v1/auth/sessions/:id', { config: { auth: false } }, async (request) => {
|
|
78
|
+
const id = Number(request.params.id);
|
|
79
|
+
if (!Number.isSafeInteger(id) || id <= 0)
|
|
80
|
+
throw new HttpProblem(400, 'invalid-id', 'Invalid id', 'The id is a positive integer.');
|
|
81
|
+
return auth.revokeSessions(await auth.requireSession(request), id);
|
|
82
|
+
});
|
|
83
|
+
app.post('/api/v1/auth/sessions/sign-out-others', { config: { auth: false } }, async (request) => auth.revokeSessions(await auth.requireSession(request), 'others'));
|
|
55
84
|
}
|
|
@@ -39,11 +39,22 @@ export interface UserInfo {
|
|
|
39
39
|
readonly companies: readonly number[];
|
|
40
40
|
/** The number grouping of each of the user's companies (RFC 0016): `lakh` or `international`. */
|
|
41
41
|
readonly groupings: Readonly<Record<string, 'international' | 'lakh'>>;
|
|
42
|
+
/** The brand colour of each of the user's companies that has one (RFC 0018): `#rrggbb`. */
|
|
43
|
+
readonly accents: Readonly<Record<string, string>>;
|
|
42
44
|
readonly twoFactorEnabled: boolean;
|
|
43
45
|
/** Holds an administrator role (in some company). */
|
|
44
46
|
readonly administrator: boolean;
|
|
45
47
|
/** Administrator rights are withheld until this session has a second factor (enable or verify 2FA). */
|
|
46
48
|
readonly administratorNeedsSecondFactor: boolean;
|
|
49
|
+
/** The policy requires two-factor sign-in of everyone and it is not on: nothing but setting it up is allowed. */
|
|
50
|
+
readonly twoFactorSetupRequired: boolean;
|
|
51
|
+
}
|
|
52
|
+
/** The installation's security policy (RFC 0019 §3.5). */
|
|
53
|
+
export interface SecurityPolicy {
|
|
54
|
+
/** Who must sign in with a second factor: administrators only (the default), or everyone. */
|
|
55
|
+
readonly twoFactor: 'administrators' | 'everyone';
|
|
56
|
+
/** Days a sign-in lasts at most; null: the server's `lifetimeMs`. */
|
|
57
|
+
readonly sessionDays: number | null;
|
|
47
58
|
}
|
|
48
59
|
/** An API key as listed (never its secret). */
|
|
49
60
|
export interface ApiKeyInfo {
|
|
@@ -162,4 +173,45 @@ export declare class AuthService {
|
|
|
162
173
|
disableTwoFactor(session: SessionInfo, password: string, code: string): Promise<void>;
|
|
163
174
|
/** Changes the password; every other session of the user is revoked. */
|
|
164
175
|
changePassword(session: SessionInfo, current: string, next: string): Promise<void>;
|
|
176
|
+
/** The security policy (cached like sessions; {@link forgetPolicy} after changing it). */
|
|
177
|
+
policy(): Promise<SecurityPolicy>;
|
|
178
|
+
/** Forgets the cached policy: after Settings › Security changed it. */
|
|
179
|
+
forgetPolicy(): void;
|
|
180
|
+
/** Forgets what is cached about `user` (their identity and sessions): after their roles or account changed. */
|
|
181
|
+
forget(user: number): void;
|
|
182
|
+
/** The signed-in user's own details (RFC 0019 §3.6). */
|
|
183
|
+
profile(session: SessionInfo): Promise<Profile>;
|
|
184
|
+
/**
|
|
185
|
+
* Changes the user's own details: name, email, phone, language, time zone, and the default company (one of
|
|
186
|
+
* theirs). Audited.
|
|
187
|
+
*/
|
|
188
|
+
updateProfile(session: SessionInfo, values: Partial<Omit<Profile, 'login'>>): Promise<Profile>;
|
|
189
|
+
/** The user's active sessions, newest use first; the current one marked. */
|
|
190
|
+
sessions(session: SessionInfo): Promise<SessionEntry[]>;
|
|
191
|
+
/** Signs out one of the user's own sessions (or all but this one with `'others'`). Audited. */
|
|
192
|
+
revokeSessions(session: SessionInfo, which: number | 'others'): Promise<{
|
|
193
|
+
revoked: number;
|
|
194
|
+
}>;
|
|
195
|
+
}
|
|
196
|
+
/** The user's own details (RFC 0019 §3.6). */
|
|
197
|
+
export interface Profile {
|
|
198
|
+
readonly login: string;
|
|
199
|
+
readonly name: string;
|
|
200
|
+
readonly email: string | null;
|
|
201
|
+
readonly phone: string | null;
|
|
202
|
+
readonly lang: string;
|
|
203
|
+
readonly tz: string;
|
|
204
|
+
/** The default company. */
|
|
205
|
+
readonly company: number | null;
|
|
206
|
+
}
|
|
207
|
+
/** One of the user's sessions (a signed-in device). */
|
|
208
|
+
export interface SessionEntry {
|
|
209
|
+
readonly id: number;
|
|
210
|
+
readonly ip: string | null;
|
|
211
|
+
readonly userAgent: string | null;
|
|
212
|
+
readonly lastSeenAt: string;
|
|
213
|
+
readonly createdAt: string | null;
|
|
214
|
+
readonly secondFactor: boolean;
|
|
215
|
+
/** This browser. */
|
|
216
|
+
readonly current: boolean;
|
|
165
217
|
}
|