@7365admin1/core 3.64.5 → 3.65.1
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/CHANGELOG.md +52 -0
- package/dist/index.d.ts +1055 -677
- package/dist/index.js +7948 -6996
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6087 -5149
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/test/console-permission.test.mjs +4 -3
- package/test/e2e/member-direct-role-org.e2e.test.mjs +255 -0
- package/test/e2e/member-direct-self-enrol-role.e2e.test.mjs +204 -0
- package/test/e2e/org-anon-lookup-projection.e2e.test.mjs +11 -1
- package/test/e2e/organization-read-scope.e2e.test.mjs +4 -1
- package/test/e2e/organization-record-reach.e2e.test.mjs +241 -0
- package/test/e2e/user-field-self-allowlist.e2e.test.mjs +172 -0
- package/test/member-direct-role-org.test.mjs +33 -0
- package/test/member-self-enrol-role.test.mjs +43 -0
- package/test/module-access.test.mjs +128 -0
- package/test/module-gate.fixtures.mjs +108 -0
- package/test/module-gate.test.mjs +64 -0
- package/test/modules-endpoint.test.mjs +525 -0
- package/test/notification-access.test.mjs +197 -0
- package/test/org-record-reach.test.mjs +45 -0
- package/test/resident-app-modules.test.mjs +45 -1
- package/test/role-member-org-scope.test.mjs +2 -1
- package/test/site-modules.test.mjs +22 -0
- package/test/staff-console-authz.test.mjs +9 -0
- package/test/user-field-self-allowlist.test.mjs +39 -0
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { ObjectId, ClientSession, Db, Collection, Document, AggregateOptions } f
|
|
|
3
3
|
import Joi from 'joi';
|
|
4
4
|
import { Request, Response, NextFunction } from 'express';
|
|
5
5
|
import * as bson from 'bson';
|
|
6
|
+
import * as qs from 'qs';
|
|
7
|
+
import * as express_serve_static_core from 'express-serve-static-core';
|
|
6
8
|
import { z } from 'zod';
|
|
7
9
|
import * as urllib from 'urllib';
|
|
8
10
|
import { Server } from 'socket.io';
|
|
@@ -490,10 +492,474 @@ declare function useMemberRepo(): {
|
|
|
490
492
|
}) => Promise<string[]>;
|
|
491
493
|
};
|
|
492
494
|
|
|
495
|
+
/**
|
|
496
|
+
* THE SEVEN365 STAFF CONSOLE CATALOGUE, ON THE SERVER.
|
|
497
|
+
*
|
|
498
|
+
* `console-authz.util.ts` `requirePlatformStaff` answers ONE question — is this
|
|
499
|
+
* session a Seven365 staff membership — and twelve controllers ask it before
|
|
500
|
+
* every console write. It has never read which modules the staff role holds, so
|
|
501
|
+
* a staff account onboarded onto a role ticked for Promo Codes alone could still
|
|
502
|
+
* suspend a client, publish platform Terms, mint a subscription and read every
|
|
503
|
+
* user on the platform. The console's own guard
|
|
504
|
+
* (`web-app-org middleware/console-tier.global.ts` + `composables/useConsoleGate.ts`,
|
|
505
|
+
* shipped in org #186) hides those screens from that role, but hiding a screen
|
|
506
|
+
* is drawing, not securing: the endpoint behind it answered anybody with a staff
|
|
507
|
+
* session. This file is the server half.
|
|
508
|
+
*
|
|
509
|
+
* ## The catalogue is a MIRROR, and it is pinned as one
|
|
510
|
+
*
|
|
511
|
+
* The strings below are `web-app-org composables/useAdminPermission.ts` — the
|
|
512
|
+
* tick-boxes a `type: "admin"` role is actually built from — plus the two
|
|
513
|
+
* families that composable pulls out of layer-common's `useCommonPermissions`
|
|
514
|
+
* (`members`, `roles-and-permissions`). It is copied rather than imported
|
|
515
|
+
* because `core` is a backend package and cannot depend on a Nuxt layer; a
|
|
516
|
+
* server that invented its own vocabulary would be the
|
|
517
|
+
* `visitor:create`/`visitor-mgmt:add-visitor` split all over again — a string
|
|
518
|
+
* the server enforces that no role editor can grant.
|
|
519
|
+
*
|
|
520
|
+
* ## THE EMPTY-LIST RULE — why switching this on locks nobody out
|
|
521
|
+
*
|
|
522
|
+
* `user.service.ts createDefaultUser()` seeds the platform-staff role with
|
|
523
|
+
* `permissions: []`, NOT `["*"]`. A plain membership test over this catalogue
|
|
524
|
+
* would therefore refuse the Seven365 owner's own account on the day it shipped.
|
|
525
|
+
*
|
|
526
|
+
* So an EMPTY list means "everything", exactly as it does today, and `"*"` keeps
|
|
527
|
+
* the short-circuit it has everywhere else in the estate. Both spellings the
|
|
528
|
+
* staging owner role and the seeder can produce (`["*"]` and `[]`) allow all, so
|
|
529
|
+
* **no role, member or user document has to be written for this to ship** —
|
|
530
|
+
* which matters, because nothing in a repo may write one.
|
|
531
|
+
*
|
|
532
|
+
* The moment somebody ticks a module on a staff role, that role becomes
|
|
533
|
+
* governed at BOTH ends. That is the intended behaviour, and it is the one case
|
|
534
|
+
* to check before granting: a staff role that already holds a partial list is
|
|
535
|
+
* enforced immediately.
|
|
536
|
+
*
|
|
537
|
+
* ## WIDENING ONLY
|
|
538
|
+
*
|
|
539
|
+
* Every check here is layered ON TOP of the staff identity test, never in place
|
|
540
|
+
* of it — nobody who was refused before is admitted now. And the match accepts
|
|
541
|
+
* ANY shipped spelling of a grant, the rule
|
|
542
|
+
* `layer-common utils/permission-spellings.ts` already applies on the client:
|
|
543
|
+
* `-admin`'s role editor writes `roles-and-permissions:add-role` while eight
|
|
544
|
+
* apps write `roles:add-role`, and a role holding either must pass. Accepting
|
|
545
|
+
* both costs nothing and needs no role migration; picking one would silently
|
|
546
|
+
* un-grant every role holding the other.
|
|
547
|
+
*/
|
|
548
|
+
/** Console resource -> the actions a staff role can be granted on it. */
|
|
549
|
+
declare const CONSOLE_PERMISSIONS: Readonly<Record<string, readonly string[]>>;
|
|
550
|
+
/** Every shipped spelling of `resource:action`. */
|
|
551
|
+
declare function consoleSpellings(resource: string, action: string): readonly string[];
|
|
552
|
+
/** True when this staff role is ungoverned and reaches the whole console. */
|
|
553
|
+
declare function consoleRoleAllowsAll(held?: readonly string[] | null): boolean;
|
|
554
|
+
/**
|
|
555
|
+
* May a staff role holding `held` take `action` on `resource`?
|
|
556
|
+
*
|
|
557
|
+
* Omit `action` to ask the SCREEN question — "does this role reach the resource
|
|
558
|
+
* at all" — which is `consoleCanSee` on the client: any single action on the
|
|
559
|
+
* resource is enough. Used where the catalogue has no string for the operation
|
|
560
|
+
* (creating a client organisation, writing a platform role/member row), because
|
|
561
|
+
* inventing a `create-organization` string here would be a grant no role editor
|
|
562
|
+
* anywhere can tick.
|
|
563
|
+
*
|
|
564
|
+
* An unknown resource, or an action the catalogue does not carry, is REFUSED for
|
|
565
|
+
* a governed role — the same answer `hasPermission` gives on the client, and the
|
|
566
|
+
* control the tests assert.
|
|
567
|
+
*/
|
|
568
|
+
declare function consoleRoleAllows(held: readonly string[] | null | undefined, resource: string, action?: string): boolean;
|
|
569
|
+
/**
|
|
570
|
+
* THE CROSS-CLIENT GRANT — the one string that lets Seven365 staff out of
|
|
571
|
+
* tenant scoping.
|
|
572
|
+
*
|
|
573
|
+
* Every tenant-scoping helper in this package (`requireSiteReach`,
|
|
574
|
+
* `siteReachOf`, `entitledSites`, `requireOwnUnit`, `requireOrgReach`) opened
|
|
575
|
+
* with `if (actor.isSuperAdmin) return`. That is an IDENTITY test: it asks who
|
|
576
|
+
* the caller is and never asks what their staff role is ticked for. So a staff
|
|
577
|
+
* account onboarded onto a role holding Promo Codes alone still read and wrote
|
|
578
|
+
* every client's sites, people, files, documents, forms and facilities — the
|
|
579
|
+
* console gate shipped at revision 35 governs the console's OWN endpoints, and
|
|
580
|
+
* these are the tenant ones behind it.
|
|
581
|
+
*
|
|
582
|
+
* `organizations` is the catalogue string that already means "this staff role
|
|
583
|
+
* reaches across clients" (`CONSOLE_PERMISSIONS.organizations` =
|
|
584
|
+
* `see-all-organizations` / `see-organization-details`), and it is a tick-box
|
|
585
|
+
* the admin role editor can actually grant. No new vocabulary is invented — a
|
|
586
|
+
* string the server enforces that no editor can grant is the
|
|
587
|
+
* `visitor:create` mistake, and this deliberately avoids it. The SCREEN
|
|
588
|
+
* question is asked (no `action`), so either tick is enough.
|
|
589
|
+
*/
|
|
590
|
+
declare const CROSS_CLIENT_GRANT: {
|
|
591
|
+
resource: string;
|
|
592
|
+
action?: string;
|
|
593
|
+
};
|
|
594
|
+
/**
|
|
595
|
+
* May this staff caller skip tenant scoping?
|
|
596
|
+
*
|
|
597
|
+
* **This never refuses anybody by itself.** It answers one question, and the
|
|
598
|
+
* caller falls through to the ORDINARY tenant scoping when the answer is no —
|
|
599
|
+
* so a staff member who is also a member of the target organisation, or who
|
|
600
|
+
* reaches the site through a live `customer.sites` engagement, is served
|
|
601
|
+
* exactly as they are today. The change is that platform identity alone stops
|
|
602
|
+
* being a skeleton key.
|
|
603
|
+
*
|
|
604
|
+
* ## ZERO LOCKOUT
|
|
605
|
+
*
|
|
606
|
+
* The rule is `consoleRoleAllows`, unchanged and already shipped: an EMPTY
|
|
607
|
+
* permission list means everything (that is what `createDefaultUser` seeds) and
|
|
608
|
+
* `"*"` means everything (that is what the live staff account holds). Both
|
|
609
|
+
* spellings a real staff role can carry today allow all, so no role, member or
|
|
610
|
+
* user document has to be written for this to ship and nobody loses access on
|
|
611
|
+
* deploy.
|
|
612
|
+
*
|
|
613
|
+
* The one population this governs is a staff role holding a NON-EMPTY PARTIAL
|
|
614
|
+
* list — which is the intended behaviour, and the same population revision 35
|
|
615
|
+
* already began governing on the console endpoints. Such a role keeps every
|
|
616
|
+
* client it holds a membership or engagement in; it loses only the reach it was
|
|
617
|
+
* never ticked for.
|
|
618
|
+
*/
|
|
619
|
+
declare function staffMayBypass(actor: {
|
|
620
|
+
isSuperAdmin: boolean;
|
|
621
|
+
staffPermissions?: string[];
|
|
622
|
+
}, grant?: {
|
|
623
|
+
resource: string;
|
|
624
|
+
action?: string;
|
|
625
|
+
}): boolean;
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* ONE console module, optionally ONE action on it.
|
|
629
|
+
*
|
|
630
|
+
* `{ resource }` alone is the SCREEN question — "does this role reach the module
|
|
631
|
+
* at all" — which is `consoleCanSee` on the client. Used where the catalogue
|
|
632
|
+
* carries no string for the operation; see `console-permission.util.ts`.
|
|
633
|
+
*/
|
|
634
|
+
type ConsoleGrant = {
|
|
635
|
+
resource: string;
|
|
636
|
+
action?: string;
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Seven365 staff only, and — when a grant is named — staff whose role holds it.
|
|
641
|
+
*
|
|
642
|
+
* Returns the caller's id so a handler can attribute the write to them rather
|
|
643
|
+
* than to whatever the request body claimed.
|
|
644
|
+
*
|
|
645
|
+
* The `grant` argument is the whole of the console-permission change. Omitting
|
|
646
|
+
* it is exactly the behaviour this function has always had, so every call site
|
|
647
|
+
* that has not been mapped to a module is untouched rather than guessed at. A
|
|
648
|
+
* role with an EMPTY permission list — which is what `createDefaultUser` seeds —
|
|
649
|
+
* passes every grant, so naming one locks nobody out. See
|
|
650
|
+
* `console-permission.util.ts` for why that rule is what makes this shippable
|
|
651
|
+
* with no write to any role document.
|
|
652
|
+
*/
|
|
653
|
+
declare function requirePlatformStaff(req: Request, grant?: ConsoleGrant): Promise<string>;
|
|
654
|
+
/**
|
|
655
|
+
* Seven365 staff who hold this console module.
|
|
656
|
+
*
|
|
657
|
+
* The name the controllers use. `requirePlatformStaff` still decides staff
|
|
658
|
+
* identity, unchanged — this is a layer ON TOP of it, never a replacement, so
|
|
659
|
+
* nobody who was refused before is admitted now.
|
|
660
|
+
*/
|
|
661
|
+
declare function requireConsolePermission(req: Request, resource: string, action?: string): Promise<string>;
|
|
662
|
+
/**
|
|
663
|
+
* The person themselves, or Seven365 staff.
|
|
664
|
+
*
|
|
665
|
+
* A user record belongs to one person, so the id in the URL must be the
|
|
666
|
+
* caller's own — unless the caller is Seven365 staff, who run the client
|
|
667
|
+
* console. Used by both `/api/users` and its twin `/api/users/v2`, whose
|
|
668
|
+
* handlers are separate files with the same routes.
|
|
669
|
+
*
|
|
670
|
+
* `PATCH /api/users/field/:id` is why this exists: its allow-list includes
|
|
671
|
+
* `email`, `nric`, `status` and `defaultOrg`, so pointing it at somebody else's
|
|
672
|
+
* id rewrote their sign-in address — and the forgot-password flow then delivers
|
|
673
|
+
* to the new one.
|
|
674
|
+
*/
|
|
675
|
+
declare function requireSelfOrPlatformStaff(req: Request, userId?: string | null, grant?: ConsoleGrant): Promise<string>;
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* What the Seven365 staff console records, as pure functions.
|
|
679
|
+
*
|
|
680
|
+
* Everything here is decidable without a database, a network or an Express
|
|
681
|
+
* request, which is the point: the rules that decide **what is allowed into an
|
|
682
|
+
* audit row** must be testable on their own. The row is written by
|
|
683
|
+
* `console-audit.repo.ts`; this file decides its shape and its contents.
|
|
684
|
+
*
|
|
685
|
+
* The one rule that governs the whole file: an audit row holds **who, what,
|
|
686
|
+
* which object, when, and enough of the values to make sense of the change**.
|
|
687
|
+
* It is not a copy of the document. Fields are admitted by an **allow-list per
|
|
688
|
+
* action** — anything not named there is dropped, so a handler that later
|
|
689
|
+
* passes a whole record cannot leak an email address, a phone number, a
|
|
690
|
+
* password hash or a token into the audit collection by accident.
|
|
691
|
+
*/
|
|
692
|
+
/** The staff actions worth keeping a record of. */
|
|
693
|
+
declare enum ConsoleAuditAction {
|
|
694
|
+
SUBSCRIPTION_CREATED = "subscription.created",
|
|
695
|
+
SUBSCRIPTION_UPDATED = "subscription.updated",
|
|
696
|
+
CLIENT_CREATED = "client.created",
|
|
697
|
+
CLIENT_SUSPENDED = "client.suspended",
|
|
698
|
+
CLIENT_REACTIVATED = "client.reactivated",
|
|
699
|
+
/**
|
|
700
|
+
* Seven365 staff changing which catalogue modules a client is offered.
|
|
701
|
+
*
|
|
702
|
+
* Recorded because it is a commercial decision about a paying client that
|
|
703
|
+
* somebody has to be able to answer for later, even though it grants and
|
|
704
|
+
* revokes nothing by itself (`org-modules.util.ts` - it narrows what a role
|
|
705
|
+
* editor OFFERS, and the server re-decides every request regardless).
|
|
706
|
+
*/
|
|
707
|
+
CLIENT_MODULES_CHANGED = "client.modules-changed",
|
|
708
|
+
/**
|
|
709
|
+
* A site's own module list changed (`PATCH /api/sites/:id/modules`).
|
|
710
|
+
*
|
|
711
|
+
* Like the camera rows below, this is a TENANT action: the organisation sets
|
|
712
|
+
* its site's list, not Seven365. It is here because the row is also the
|
|
713
|
+
* module gate's acknowledged-save marker (`gateListHash`, see
|
|
714
|
+
* `module-gate.util.ts enforcedModuleList`): a site list is enforced only
|
|
715
|
+
* once a save through the preview-and-acknowledge path has recorded it.
|
|
716
|
+
*/
|
|
717
|
+
SITE_MODULES_CHANGED = "site.modules-changed",
|
|
718
|
+
PROMO_CODE_CREATED = "promo-code.created",
|
|
719
|
+
PROMO_CODE_UPDATED = "promo-code.updated",
|
|
720
|
+
PROMO_CODE_STATUS_CHANGED = "promo-code.status-changed",
|
|
721
|
+
PROMO_CODE_REMOVED = "promo-code.removed",
|
|
722
|
+
PLAN_CREATED = "plan.created",
|
|
723
|
+
PLAN_UPDATED = "plan.updated",
|
|
724
|
+
PLAN_STATUS_CHANGED = "plan.status-changed",
|
|
725
|
+
TERMS_PUBLISHED = "terms.published",
|
|
726
|
+
/**
|
|
727
|
+
* Seven365 staff switching a client's camera on or off.
|
|
728
|
+
*
|
|
729
|
+
* The only tenant-owned object on this list, and it is here because it is the
|
|
730
|
+
* only one staff may touch: a faulty camera at a client's site has to be
|
|
731
|
+
* switchable off by us. See `updateById` in `site-camera.controller.ts` for
|
|
732
|
+
* the boundary that allows it and nothing else.
|
|
733
|
+
*/
|
|
734
|
+
CAMERA_STATUS_CHANGED = "camera.status-changed",
|
|
735
|
+
/**
|
|
736
|
+
* A camera being added, edited or removed BY THE SITE'S OWN PEOPLE.
|
|
737
|
+
*
|
|
738
|
+
* The three below are the answer to "who changed this camera's address, and
|
|
739
|
+
* when" - a question that had no answer anywhere in the system. A camera
|
|
740
|
+
* record carries `createdAt`/`updatedAt` and no actor, and a write overwrites
|
|
741
|
+
* the previous `host` in place, so a wrong port number could only be traced by
|
|
742
|
+
* asking people what they remembered doing. At Seventh Condominium that turned
|
|
743
|
+
* a one-line correction into nine days.
|
|
744
|
+
*
|
|
745
|
+
* This is a widening of what the collection holds: `CAMERA_STATUS_CHANGED` is
|
|
746
|
+
* a Seven365 STAFF action, and these are tenant actions. That is deliberate.
|
|
747
|
+
* The console is where an operator goes to answer exactly this question, the
|
|
748
|
+
* row already carries `actor`, `target` and `createdAt`, and the alternative -
|
|
749
|
+
* a second audit collection with its own repository, model and indexes - is
|
|
750
|
+
* more moving parts for the same row. Nothing existing changes: the collection
|
|
751
|
+
* is append-only and every reader filters by `action`.
|
|
752
|
+
*/
|
|
753
|
+
CAMERA_ADDED = "camera.added",
|
|
754
|
+
CAMERA_UPDATED = "camera.updated",
|
|
755
|
+
CAMERA_REMOVED = "camera.removed"
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* The three actions that live in `organization.controller.ts`.
|
|
759
|
+
*
|
|
760
|
+
* They are defined, labelled and tested here, but **nothing calls them yet**.
|
|
761
|
+
* `organization.controller.ts` is being edited by open PR #1884 (suspend), and
|
|
762
|
+
* editing the same handlers here would hand a reviewer a merge conflict for no
|
|
763
|
+
* gain. Each needs exactly one `recordConsoleAction(...)` call once #1884
|
|
764
|
+
* lands; the action names and labels are already in place for it.
|
|
765
|
+
*/
|
|
766
|
+
declare const CLIENT_ACTIONS: ConsoleAuditAction[];
|
|
767
|
+
/** What a person reads on the screen. The row carries it so the screen need not map it. */
|
|
768
|
+
declare const CONSOLE_AUDIT_LABELS: Record<ConsoleAuditAction, string>;
|
|
769
|
+
/** What kind of thing the action was done to. */
|
|
770
|
+
declare enum ConsoleAuditTarget {
|
|
771
|
+
ORGANIZATION = "organization",
|
|
772
|
+
SUBSCRIPTION = "subscription",
|
|
773
|
+
PROMO_CODE = "promo-code",
|
|
774
|
+
PLAN = "plan",
|
|
775
|
+
TERMS = "terms",
|
|
776
|
+
CAMERA = "camera",
|
|
777
|
+
SITE = "site"
|
|
778
|
+
}
|
|
779
|
+
/** A stored value is a primitive or it is not stored. */
|
|
780
|
+
declare const AUDIT_VALUE_MAX_LENGTH = 120;
|
|
781
|
+
/**
|
|
782
|
+
* The part of a change that may be stored, for this action.
|
|
783
|
+
*
|
|
784
|
+
* Returns `undefined` rather than `{}` when nothing survives, so an empty
|
|
785
|
+
* object never occupies a row and a reader can tell "nothing recorded" from
|
|
786
|
+
* "recorded as empty".
|
|
787
|
+
*/
|
|
788
|
+
declare function pickAuditFields(action: ConsoleAuditAction, value?: Record<string, unknown> | null): Record<string, string | number | boolean> | undefined;
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Every module key a list can deny: the keys the Seven365 console's module card
|
|
792
|
+
* can offer, minus `ALWAYS_ALLOWED`, plus the alias spellings in
|
|
793
|
+
* `SPELLING_GROUPS`.
|
|
794
|
+
*
|
|
795
|
+
* GENERATED 2026-09-11 from layer-common `origin/main` 5a96f95, not
|
|
796
|
+
* hand-written: bundled with esbuild, then
|
|
797
|
+
* union(Object.keys(PERMISSIONS) constants/permissions.ts,
|
|
798
|
+
* applicationModules().flatMap(a => a.modules) utils/module-applications.ts)
|
|
799
|
+
* which is `MODULE_KEYS` in web-app-org `pages/super-admin/client-details.vue`.
|
|
800
|
+
* Then added the alias resources of `LEGACY_PERMISSION_ALIASES` that are not
|
|
801
|
+
* already keys (`facility-booking`, `service-provider`, `work-orders`), and
|
|
802
|
+
* removed `ALWAYS_ALLOWED`.
|
|
803
|
+
*
|
|
804
|
+
* Deliberately NOT included: resource keys of catalogues the card cannot offer
|
|
805
|
+
* (`useAdminPermission`: `organizations`, `users`, `promo-codes`, …;
|
|
806
|
+
* `useRecapPermission`: `request`). A governed key the card cannot tick could
|
|
807
|
+
* never be allowed again once a client had a list.
|
|
808
|
+
*
|
|
809
|
+
* Regenerate when a composable gains a module; until then the new module is
|
|
810
|
+
* simply ungoverned, so it stays visible.
|
|
811
|
+
*/
|
|
812
|
+
declare const GOVERNED_MODULES: readonly string[];
|
|
813
|
+
/** A list, cleaned and widened so every spelling of a listed module is in it. */
|
|
814
|
+
declare function expandModules(list: readonly unknown[] | null | undefined): string[];
|
|
815
|
+
/**
|
|
816
|
+
* The modules this caller's apps must hide, given the organisation's list and
|
|
817
|
+
* the site's list. `[]` means hide nothing.
|
|
818
|
+
*
|
|
819
|
+
* Both tiers are widened through the spelling groups BEFORE the existing
|
|
820
|
+
* `effectiveSiteModules` intersects them, so `workOrder` at one tier and
|
|
821
|
+
* `work_orders` at the other still meet.
|
|
822
|
+
*/
|
|
823
|
+
declare function deniedModules(orgList: readonly unknown[] | null | undefined, siteList: readonly unknown[] | null | undefined): string[];
|
|
824
|
+
type TImpactMember = {
|
|
825
|
+
_id?: unknown;
|
|
826
|
+
name?: string;
|
|
827
|
+
type?: string;
|
|
828
|
+
role?: unknown;
|
|
829
|
+
};
|
|
830
|
+
type TImpactRole = {
|
|
831
|
+
_id?: unknown;
|
|
832
|
+
name?: string;
|
|
833
|
+
permissions?: unknown;
|
|
834
|
+
};
|
|
835
|
+
type TModuleImpactEntry = {
|
|
836
|
+
/** The module's first spelling in `SPELLING_GROUPS`, or the key itself. */
|
|
837
|
+
module: string;
|
|
838
|
+
/** Every newly denied spelling of it. */
|
|
839
|
+
spellings: string[];
|
|
840
|
+
memberCount: number;
|
|
841
|
+
members: Array<{
|
|
842
|
+
_id: string;
|
|
843
|
+
name: string;
|
|
844
|
+
}>;
|
|
845
|
+
roleCount: number;
|
|
846
|
+
roles: Array<{
|
|
847
|
+
_id: string;
|
|
848
|
+
name: string;
|
|
849
|
+
}>;
|
|
850
|
+
};
|
|
851
|
+
type TModuleImpact = {
|
|
852
|
+
/** Distinct members who lose at least one module. */
|
|
853
|
+
memberCount: number;
|
|
854
|
+
modules: TModuleImpactEntry[];
|
|
855
|
+
};
|
|
856
|
+
/**
|
|
857
|
+
* Who would lose what if the denied list went from `currentDenied` to
|
|
858
|
+
* `proposedDenied`: the preview that must come before any narrowing save.
|
|
859
|
+
*
|
|
860
|
+
* - A role holding `"*"` holds every module. So does an EMPTY role, which is the
|
|
861
|
+
* estate rule (`createDefaultUser` seeds `permissions: []`), so a preview
|
|
862
|
+
* over-counts rather than under-counts.
|
|
863
|
+
* - An enumerated role holds the resource half of each string, under any
|
|
864
|
+
* spelling. A string for an ungoverned resource never loses anything.
|
|
865
|
+
* - Residents are excluded: they hold no staff role. A member whose role is not
|
|
866
|
+
* in `rolesById` is skipped. Filter out inactive members before calling.
|
|
867
|
+
*/
|
|
868
|
+
declare function moduleImpact({ currentDenied, proposedDenied, members, rolesById, }: {
|
|
869
|
+
currentDenied: readonly unknown[] | null | undefined;
|
|
870
|
+
proposedDenied: readonly unknown[] | null | undefined;
|
|
871
|
+
members: readonly TImpactMember[] | null | undefined;
|
|
872
|
+
rolesById: Record<string, TImpactRole | null | undefined> | null | undefined;
|
|
873
|
+
}): TModuleImpact;
|
|
874
|
+
/**
|
|
875
|
+
* THE ONE SWITCH (master plan rule 2). `MODULE_LIST_GATE=off` turns the whole
|
|
876
|
+
* gate off everywhere at once, with no app build: the `/modules` deny list that
|
|
877
|
+
* every web and mobile app ANDs, the Q7 notification filter and the Q3 server
|
|
878
|
+
* refusal all check this before computing anything, and answer "nothing
|
|
879
|
+
* denied".
|
|
880
|
+
*
|
|
881
|
+
* Read on every call rather than once at load, so a lead's emergency env
|
|
882
|
+
* override takes effect on restart. OUR flips change the code default below,
|
|
883
|
+
* by PR, staging first: setting an env on DigitalOcean is the leads' job.
|
|
884
|
+
*/
|
|
885
|
+
declare const MODULE_LIST_GATE_DEFAULT = "on";
|
|
886
|
+
declare function moduleListGateOn(env?: Record<string, string | undefined>): boolean;
|
|
887
|
+
/** The latest console-audit row that saved a list: its `after` and `createdAt`. */
|
|
888
|
+
type TModuleListSave = {
|
|
889
|
+
after?: Record<string, unknown> | null;
|
|
890
|
+
createdAt?: string | null;
|
|
891
|
+
} | null | undefined;
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* THE MODULE GATE, READ FROM THE DATABASE.
|
|
895
|
+
*
|
|
896
|
+
* The pure rules live in `utils/module-gate.util.ts`. This file only fetches
|
|
897
|
+
* what they need: memberships, the organisation and the site, the latest
|
|
898
|
+
* console-audit save row (the acknowledged-save marker) and roles. Every read
|
|
899
|
+
* is a plain `find`/`findOne` or a cached repository getter. Nothing here
|
|
900
|
+
* writes, and roles are never read through `GET /api/roles`, whose heal path
|
|
901
|
+
* writes.
|
|
902
|
+
*
|
|
903
|
+
* Every lookup is injectable (`TModuleGateData`), so the rules are tested
|
|
904
|
+
* against the shipped code with no database.
|
|
905
|
+
*/
|
|
906
|
+
type TRow = {
|
|
907
|
+
_id?: unknown;
|
|
908
|
+
user?: unknown;
|
|
909
|
+
org?: unknown;
|
|
910
|
+
siteId?: unknown;
|
|
911
|
+
type?: string;
|
|
912
|
+
status?: string;
|
|
913
|
+
deletedAt?: unknown;
|
|
914
|
+
role?: unknown;
|
|
915
|
+
name?: string;
|
|
916
|
+
};
|
|
917
|
+
type TOrgDoc = {
|
|
918
|
+
_id?: unknown;
|
|
919
|
+
modules?: unknown;
|
|
920
|
+
} | null;
|
|
921
|
+
type TSiteDoc = {
|
|
922
|
+
_id?: unknown;
|
|
923
|
+
orgId?: unknown;
|
|
924
|
+
metadata?: {
|
|
925
|
+
modules?: unknown;
|
|
926
|
+
} | null;
|
|
927
|
+
} | null;
|
|
928
|
+
type TRoleDoc = {
|
|
929
|
+
_id?: unknown;
|
|
930
|
+
name?: string;
|
|
931
|
+
permissions?: unknown;
|
|
932
|
+
};
|
|
933
|
+
type TModuleGateData = {
|
|
934
|
+
/** Every membership row of these users, any status. */
|
|
935
|
+
membershipsOf(userIds: string[]): Promise<TRow[]>;
|
|
936
|
+
org(id: string): Promise<TOrgDoc>;
|
|
937
|
+
site(id: string): Promise<TSiteDoc>;
|
|
938
|
+
/** The latest console-audit row saving this list. */
|
|
939
|
+
latestSave(action: ConsoleAuditAction, org: string, target: string): Promise<TModuleListSave>;
|
|
940
|
+
/** Seven365 staff whose console role may skip tenant scoping. */
|
|
941
|
+
isPlatformStaff(userId: string): Promise<boolean>;
|
|
942
|
+
/** Non-resident memberships in `org`; with `site`, those pinned there or org-wide. */
|
|
943
|
+
staffMembers(query: {
|
|
944
|
+
org: string;
|
|
945
|
+
site?: string;
|
|
946
|
+
}): Promise<TRow[]>;
|
|
947
|
+
roles(ids: string[]): Promise<Record<string, TRoleDoc>>;
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
/** Injected so a unit test runs the handler with no database. */
|
|
951
|
+
type TMemberModulesDeps = {
|
|
952
|
+
requireSelfOrPlatformStaff: typeof requireSelfOrPlatformStaff;
|
|
953
|
+
gateData?: TModuleGateData;
|
|
954
|
+
};
|
|
955
|
+
declare function memberModulesHandlers({ requireSelfOrPlatformStaff, gateData, }: TMemberModulesDeps): {
|
|
956
|
+
getModulesByUserIdType: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
957
|
+
};
|
|
493
958
|
declare function useMemberController(): {
|
|
494
959
|
createMember: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
495
960
|
getByUserId: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
496
961
|
getByUserIdType: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
962
|
+
getModulesByUserIdType: (req: Request<express_serve_static_core.ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction) => Promise<void>;
|
|
497
963
|
getAll: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
498
964
|
getAllByUser: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
499
965
|
getOrgsByMembership: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
@@ -949,6 +1415,94 @@ declare function useOrgRepo(): {
|
|
|
949
1415
|
completeOnboardingById: (_id: string | ObjectId, session?: ClientSession) => Promise<string>;
|
|
950
1416
|
};
|
|
951
1417
|
|
|
1418
|
+
/**
|
|
1419
|
+
* One staff action in the Seven365 console.
|
|
1420
|
+
*
|
|
1421
|
+
* A new collection. Nothing existing is changed, no field is added to any live
|
|
1422
|
+
* document, and there is no migration — a client, a subscription, a promo code
|
|
1423
|
+
* and a plan are all exactly as they were.
|
|
1424
|
+
*
|
|
1425
|
+
* `actor` is a `users._id` and it comes from the SESSION, never from the
|
|
1426
|
+
* request body. The body-attribution defect fixed on `POST /api/terms` earlier
|
|
1427
|
+
* today is the reason that is written down rather than assumed.
|
|
1428
|
+
*/
|
|
1429
|
+
type TConsoleAudit = {
|
|
1430
|
+
_id?: ObjectId;
|
|
1431
|
+
action: ConsoleAuditAction;
|
|
1432
|
+
/** Who. A `users._id`, resolved from the session. */
|
|
1433
|
+
actor: string | ObjectId;
|
|
1434
|
+
/** Which client it affected, when the action is about one. */
|
|
1435
|
+
org?: string | ObjectId | null;
|
|
1436
|
+
/** Which object changed, and of what kind. */
|
|
1437
|
+
target?: string | ObjectId | null;
|
|
1438
|
+
targetType?: ConsoleAuditTarget | null;
|
|
1439
|
+
/** Enough of the change to make sense of it — never a whole document. */
|
|
1440
|
+
before?: Record<string, unknown> | null;
|
|
1441
|
+
after?: Record<string, unknown> | null;
|
|
1442
|
+
/** ISO-8601 UTC, so a lexicographic range filter is also a date range filter. */
|
|
1443
|
+
createdAt?: string;
|
|
1444
|
+
};
|
|
1445
|
+
declare const schemaConsoleAudit: Joi.ObjectSchema<any>;
|
|
1446
|
+
declare function MConsoleAudit(value: TConsoleAudit): TConsoleAudit;
|
|
1447
|
+
|
|
1448
|
+
declare const console_audit_namespace_collection = "console-audit";
|
|
1449
|
+
type TConsoleAuditQuery = {
|
|
1450
|
+
org?: string;
|
|
1451
|
+
action?: string;
|
|
1452
|
+
/** ISO-8601. Inclusive at both ends of the day the caller names. */
|
|
1453
|
+
from?: string;
|
|
1454
|
+
to?: string;
|
|
1455
|
+
page?: number;
|
|
1456
|
+
limit?: number;
|
|
1457
|
+
};
|
|
1458
|
+
declare function useConsoleAuditRepo(): {
|
|
1459
|
+
createIndexes: () => Promise<void>;
|
|
1460
|
+
add: (value: TConsoleAudit) => Promise<{
|
|
1461
|
+
_id: ObjectId;
|
|
1462
|
+
action: ConsoleAuditAction;
|
|
1463
|
+
actor: string | ObjectId;
|
|
1464
|
+
org?: string | ObjectId | null | undefined;
|
|
1465
|
+
target?: string | ObjectId | null | undefined;
|
|
1466
|
+
targetType?: ConsoleAuditTarget | null | undefined;
|
|
1467
|
+
before?: Record<string, unknown> | null | undefined;
|
|
1468
|
+
after?: Record<string, unknown> | null | undefined;
|
|
1469
|
+
createdAt?: string | undefined;
|
|
1470
|
+
}>;
|
|
1471
|
+
list: (query: TConsoleAuditQuery) => Promise<{
|
|
1472
|
+
items: any[];
|
|
1473
|
+
pages: number;
|
|
1474
|
+
pageRange: string;
|
|
1475
|
+
}>;
|
|
1476
|
+
};
|
|
1477
|
+
/**
|
|
1478
|
+
* Record a staff action — and never, under any circumstance, break the action
|
|
1479
|
+
* it describes.
|
|
1480
|
+
*
|
|
1481
|
+
* Everything is inside the catch: resolving the database, validating the row
|
|
1482
|
+
* and the insert itself. The returned promise **cannot reject**, so a caller
|
|
1483
|
+
* that `await`s it cannot be thrown out of its own success path, and a caller
|
|
1484
|
+
* that forgets to `await` it cannot crash the process with an unhandled
|
|
1485
|
+
* rejection either. A failure is logged and the operation stands.
|
|
1486
|
+
*
|
|
1487
|
+
* Called only AFTER the operation it records has succeeded, so a row can never
|
|
1488
|
+
* describe something that did not happen. The other direction is possible and
|
|
1489
|
+
* accepted: an action can happen and its row fail to be written, in which case
|
|
1490
|
+
* the log carries it.
|
|
1491
|
+
*/
|
|
1492
|
+
declare function recordConsoleAction(entry: TConsoleAudit): Promise<void>;
|
|
1493
|
+
|
|
1494
|
+
/** What the client module-list handlers read and write; injected so a unit test runs them with no database. */
|
|
1495
|
+
type TOrgModulesDeps = {
|
|
1496
|
+
requireConsolePermission: (req: Request, resource: string) => Promise<string>;
|
|
1497
|
+
_getById: (id: string) => Promise<any>;
|
|
1498
|
+
_update: (id: string, value: any) => Promise<unknown>;
|
|
1499
|
+
recordConsoleAction: (entry: Parameters<typeof recordConsoleAction>[0]) => Promise<unknown>;
|
|
1500
|
+
gateData?: TModuleGateData;
|
|
1501
|
+
};
|
|
1502
|
+
declare function orgModulesHandlers({ requireConsolePermission, _getById, _update, recordConsoleAction, gateData, }: TOrgModulesDeps): {
|
|
1503
|
+
updateModules: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
1504
|
+
previewOrgModules: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
1505
|
+
};
|
|
952
1506
|
declare function useOrgController(): {
|
|
953
1507
|
add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
954
1508
|
addOnboardingOrg: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
@@ -961,7 +1515,8 @@ declare function useOrgController(): {
|
|
|
961
1515
|
getOrgsByEmail: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
962
1516
|
getAdminOrgForResident: (_req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
963
1517
|
updateStatus: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
964
|
-
updateModules: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
1518
|
+
updateModules: (req: Request<express_serve_static_core.ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction) => Promise<void>;
|
|
1519
|
+
previewOrgModules: (req: Request<express_serve_static_core.ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction) => Promise<void>;
|
|
965
1520
|
};
|
|
966
1521
|
|
|
967
1522
|
/**
|
|
@@ -2241,85 +2796,315 @@ declare function useCustomerController(): {
|
|
|
2241
2796
|
deleteCustomer: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
2242
2797
|
};
|
|
2243
2798
|
|
|
2244
|
-
declare function useSiteRepo(): {
|
|
2245
|
-
createIndexes: () => Promise<void>;
|
|
2246
|
-
createSite: (value: TSite, session?: ClientSession) => Promise<ObjectId>;
|
|
2247
|
-
getSites: ({ page, limit, search, sort, org, }: {
|
|
2248
|
-
page?: number | undefined;
|
|
2249
|
-
limit?: number | undefined;
|
|
2250
|
-
search?: string | undefined;
|
|
2251
|
-
sort?: Record<string, any> | undefined;
|
|
2252
|
-
org: string | ObjectId;
|
|
2253
|
-
}) => Promise<{}>;
|
|
2254
|
-
getAllSites: ({ page, limit, }: {
|
|
2255
|
-
page: number;
|
|
2256
|
-
limit: number;
|
|
2257
|
-
}) => Promise<{
|
|
2258
|
-
items: {
|
|
2259
|
-
_id: ObjectId;
|
|
2260
|
-
name: string;
|
|
2261
|
-
}[];
|
|
2262
|
-
pages: number;
|
|
2263
|
-
pageRange: string;
|
|
2264
|
-
}>;
|
|
2265
|
-
getSiteById: (_id: string | ObjectId) => Promise<TSite>;
|
|
2266
|
-
updateSiteBlock: (_id: string | ObjectId, block: TSiteUpdateBlock) => Promise<number>;
|
|
2267
|
-
deleteSite: (_id: string | ObjectId, session?: ClientSession) => Promise<number>;
|
|
2268
|
-
updateById: ({ _id, field, value, type }?: {
|
|
2269
|
-
_id: string | ObjectId;
|
|
2270
|
-
field: string;
|
|
2271
|
-
value: string | number | ObjectId;
|
|
2272
|
-
type?: string | undefined;
|
|
2273
|
-
}, session?: ClientSession) => Promise<string>;
|
|
2274
|
-
getByName: (name?: string) => Promise<TSite[]>;
|
|
2275
|
-
getByExactName: (name: string, orgId: string | ObjectId) => Promise<TSite[]>;
|
|
2276
|
-
updateSiteIncidentCounter: (_id: string | ObjectId, incidentCounter: number, session?: ClientSession) => Promise<number>;
|
|
2277
|
-
updateSiteById: (id: string | ObjectId, payload: TSite, session?: ClientSession) => Promise<number>;
|
|
2278
|
-
getAllSitesUnpaginated: () => Promise<bson.Document[]>;
|
|
2279
|
-
siteInformation: ({ id, payload, }: {
|
|
2280
|
-
id: string;
|
|
2281
|
-
payload: TSiteInformation;
|
|
2282
|
-
}) => Promise<number>;
|
|
2283
|
-
getAllSitesForResidentCreation: ({ search, page, limit, }: {
|
|
2284
|
-
search: string;
|
|
2285
|
-
page: number;
|
|
2286
|
-
limit: number;
|
|
2287
|
-
}) => Promise<{
|
|
2288
|
-
items: {
|
|
2289
|
-
_id: ObjectId;
|
|
2290
|
-
name: string;
|
|
2291
|
-
}[];
|
|
2292
|
-
pages: number;
|
|
2293
|
-
pageRange: string;
|
|
2294
|
-
}>;
|
|
2799
|
+
declare function useSiteRepo(): {
|
|
2800
|
+
createIndexes: () => Promise<void>;
|
|
2801
|
+
createSite: (value: TSite, session?: ClientSession) => Promise<ObjectId>;
|
|
2802
|
+
getSites: ({ page, limit, search, sort, org, }: {
|
|
2803
|
+
page?: number | undefined;
|
|
2804
|
+
limit?: number | undefined;
|
|
2805
|
+
search?: string | undefined;
|
|
2806
|
+
sort?: Record<string, any> | undefined;
|
|
2807
|
+
org: string | ObjectId;
|
|
2808
|
+
}) => Promise<{}>;
|
|
2809
|
+
getAllSites: ({ page, limit, }: {
|
|
2810
|
+
page: number;
|
|
2811
|
+
limit: number;
|
|
2812
|
+
}) => Promise<{
|
|
2813
|
+
items: {
|
|
2814
|
+
_id: ObjectId;
|
|
2815
|
+
name: string;
|
|
2816
|
+
}[];
|
|
2817
|
+
pages: number;
|
|
2818
|
+
pageRange: string;
|
|
2819
|
+
}>;
|
|
2820
|
+
getSiteById: (_id: string | ObjectId) => Promise<TSite>;
|
|
2821
|
+
updateSiteBlock: (_id: string | ObjectId, block: TSiteUpdateBlock) => Promise<number>;
|
|
2822
|
+
deleteSite: (_id: string | ObjectId, session?: ClientSession) => Promise<number>;
|
|
2823
|
+
updateById: ({ _id, field, value, type }?: {
|
|
2824
|
+
_id: string | ObjectId;
|
|
2825
|
+
field: string;
|
|
2826
|
+
value: string | number | ObjectId;
|
|
2827
|
+
type?: string | undefined;
|
|
2828
|
+
}, session?: ClientSession) => Promise<string>;
|
|
2829
|
+
getByName: (name?: string) => Promise<TSite[]>;
|
|
2830
|
+
getByExactName: (name: string, orgId: string | ObjectId) => Promise<TSite[]>;
|
|
2831
|
+
updateSiteIncidentCounter: (_id: string | ObjectId, incidentCounter: number, session?: ClientSession) => Promise<number>;
|
|
2832
|
+
updateSiteById: (id: string | ObjectId, payload: TSite, session?: ClientSession) => Promise<number>;
|
|
2833
|
+
getAllSitesUnpaginated: () => Promise<bson.Document[]>;
|
|
2834
|
+
siteInformation: ({ id, payload, }: {
|
|
2835
|
+
id: string;
|
|
2836
|
+
payload: TSiteInformation;
|
|
2837
|
+
}) => Promise<number>;
|
|
2838
|
+
getAllSitesForResidentCreation: ({ search, page, limit, }: {
|
|
2839
|
+
search: string;
|
|
2840
|
+
page: number;
|
|
2841
|
+
limit: number;
|
|
2842
|
+
}) => Promise<{
|
|
2843
|
+
items: {
|
|
2844
|
+
_id: ObjectId;
|
|
2845
|
+
name: string;
|
|
2846
|
+
}[];
|
|
2847
|
+
pages: number;
|
|
2848
|
+
pageRange: string;
|
|
2849
|
+
}>;
|
|
2850
|
+
};
|
|
2851
|
+
|
|
2852
|
+
declare function useSiteService(): {
|
|
2853
|
+
createSite: (value: {
|
|
2854
|
+
orgId: string;
|
|
2855
|
+
name: string;
|
|
2856
|
+
description?: string | undefined;
|
|
2857
|
+
customerId: string;
|
|
2858
|
+
category: SiteCategories;
|
|
2859
|
+
address: {
|
|
2860
|
+
line1: string;
|
|
2861
|
+
line2?: string;
|
|
2862
|
+
city: string;
|
|
2863
|
+
state?: string;
|
|
2864
|
+
postalCode: string;
|
|
2865
|
+
country: string;
|
|
2866
|
+
};
|
|
2867
|
+
}) => Promise<{
|
|
2868
|
+
site: bson.ObjectId;
|
|
2869
|
+
}>;
|
|
2870
|
+
updateGuardPostById: (site: string, guardPost: number) => Promise<void>;
|
|
2871
|
+
updateById: (_id: string, payload: TSite) => Promise<void>;
|
|
2872
|
+
siteInformation: ({ id, payload }: {
|
|
2873
|
+
id: string;
|
|
2874
|
+
payload: TSiteInformation;
|
|
2875
|
+
}) => Promise<number>;
|
|
2876
|
+
};
|
|
2877
|
+
|
|
2878
|
+
/**
|
|
2879
|
+
* Who is asking, resolved from the session id alone.
|
|
2880
|
+
*
|
|
2881
|
+
* Every invitation action re-derives this — the caller never states who they
|
|
2882
|
+
* are in a body or a query field.
|
|
2883
|
+
*
|
|
2884
|
+
* **Super admin is a membership, not an email address.** `createDefaultUser()`
|
|
2885
|
+
* seeds a role named "Super Admin" with `type: "admin"` and a `members` row with
|
|
2886
|
+
* `type: "admin"` and NO organisation; the user behind it is whatever
|
|
2887
|
+
* `DEFAULT_USER_EMAIL` is set to in that environment (`admin@gmail.com` on
|
|
2888
|
+
* staging, something else in production). Gating on the email address would
|
|
2889
|
+
* therefore work on staging and fail in production, and would break the day the
|
|
2890
|
+
* account is rotated. Both halves are required — a `members` row of type
|
|
2891
|
+
* "admin" whose role is also of type "admin" — because staging carries a second
|
|
2892
|
+
* role merely NAMED "Super Admin" that is an ordinary organisation role.
|
|
2893
|
+
*/
|
|
2894
|
+
type InviteActor = {
|
|
2895
|
+
id: string;
|
|
2896
|
+
name: string;
|
|
2897
|
+
isSuperAdmin: boolean;
|
|
2898
|
+
/** every organisation this user is a live member of */
|
|
2899
|
+
orgIds: string[];
|
|
2900
|
+
/** organisations this user represents as a property management company */
|
|
2901
|
+
propertyManagementOrgIds: string[];
|
|
2902
|
+
/**
|
|
2903
|
+
* Every live membership as an `(org, siteId)` pair, `siteId` empty when the
|
|
2904
|
+
* membership carries no site — i.e. when it is an org-wide role.
|
|
2905
|
+
*
|
|
2906
|
+
* `orgIds` above flattens this and throws the site away, which is right for
|
|
2907
|
+
* the organisation-level gates that read it. The LISTING paths need the site
|
|
2908
|
+
* back: `GET /api/customer-sites?org=` authorises at organisation level and
|
|
2909
|
+
* then returned the organisation's whole estate, so a user invited to one
|
|
2910
|
+
* site was offered every site in the client. See `orgSiteScope`.
|
|
2911
|
+
*
|
|
2912
|
+
* `orgLevelRole` is true when the membership's ROLE is organisation-level —
|
|
2913
|
+
* the `roles` document carries no `site` of its own. Owner decision of
|
|
2914
|
+
* 2026-09-02: an org-level role sees every site EVEN IF its membership row
|
|
2915
|
+
* also names one, so the stray `siteId` on an Org Owner row must not narrow
|
|
2916
|
+
* them. It fails closed: a missing, soft-deleted or unreadable role is not
|
|
2917
|
+
* org-level.
|
|
2918
|
+
*/
|
|
2919
|
+
memberships: Array<{
|
|
2920
|
+
org: string;
|
|
2921
|
+
siteId: string;
|
|
2922
|
+
orgLevelRole: boolean;
|
|
2923
|
+
/** The membership's `type` (`resident`, `security_agency`, …); `""` when absent. */
|
|
2924
|
+
type?: string;
|
|
2925
|
+
}>;
|
|
2926
|
+
/**
|
|
2927
|
+
* The `permissions` array of the LIVE staff role behind `isSuperAdmin`, or
|
|
2928
|
+
* undefined when the caller is not Seven365 staff.
|
|
2929
|
+
*
|
|
2930
|
+
* The role document is already read two lines below to decide
|
|
2931
|
+
* `isSuperAdmin`; only its `permissions` field was being thrown away. Carrying
|
|
2932
|
+
* it costs no extra query and is what lets `staffMayBypass` ask the console
|
|
2933
|
+
* catalogue's question instead of identity alone. Undefined and `[]` are NOT
|
|
2934
|
+
* the same thing: `[]` is a staff role that holds everything (the empty-list
|
|
2935
|
+
* rule), undefined is somebody who is not staff at all.
|
|
2936
|
+
*/
|
|
2937
|
+
staffPermissions?: string[];
|
|
2938
|
+
};
|
|
2939
|
+
declare function resolveInviteActor(userId?: string | ObjectId | null): Promise<InviteActor>;
|
|
2940
|
+
/**
|
|
2941
|
+
* Does this person hold an invitation naming this organisation?
|
|
2942
|
+
*
|
|
2943
|
+
* The org-scoping rule on roles and memberships is "Seven365 staff, or a live
|
|
2944
|
+
* member of this organisation" — but three live flows legitimately reach an
|
|
2945
|
+
* organisation the caller is **not yet** a member of, because joining it is the
|
|
2946
|
+
* whole point:
|
|
2947
|
+
*
|
|
2948
|
+
* - the service-provider signing in against a `service-provider-invite`
|
|
2949
|
+
* (`web-app-main pages/sign-in.vue:298,428`), who looks up that customer's
|
|
2950
|
+
* "Admin Service Provider" role and then enrols;
|
|
2951
|
+
* - the admin member finishing sign-up from a `member-invite`
|
|
2952
|
+
* (`web-app-main pages/verify/email/index.vue:462`);
|
|
2953
|
+
* - the client owner walking the onboarding wizard
|
|
2954
|
+
* (`web-app-org pages/onboarding/getting-started/index.vue`).
|
|
2955
|
+
*
|
|
2956
|
+
* All three are holding an invitation addressed to their OWN email whose
|
|
2957
|
+
* `metadata.org` is the organisation being reached, so that invitation is the
|
|
2958
|
+
* relationship the rule tests. Both string and ObjectId shapes are matched,
|
|
2959
|
+
* because `MVerification` casts `metadata.org` to an ObjectId while older rows
|
|
2960
|
+
* carry a string — the same pair `completePendingInvites` matches on.
|
|
2961
|
+
*
|
|
2962
|
+
* Any status counts: `completeOrgAdminAccount` marks the verification complete
|
|
2963
|
+
* before the member row is written, so a pending-only test would refuse the
|
|
2964
|
+
* flow it exists to protect.
|
|
2965
|
+
*/
|
|
2966
|
+
declare function hasOrgInvitation(userId?: string | ObjectId | null, orgId?: string | ObjectId | null): Promise<boolean>;
|
|
2967
|
+
/**
|
|
2968
|
+
* Does one of this person's own invitations into this organisation OFFER this
|
|
2969
|
+
* role?
|
|
2970
|
+
*
|
|
2971
|
+
* `hasOrgInvitation` answers "may you reach the organisation"; this answers
|
|
2972
|
+
* "may you wear THIS role there". An invitation that names a role offers that
|
|
2973
|
+
* role and nothing else. An invitation that names NO role — the
|
|
2974
|
+
* service-provider invite, whose sign-in then finds or creates the org's
|
|
2975
|
+
* "Admin Service Provider" role (`web-app-main pages/sign-in.vue`) — offers a
|
|
2976
|
+
* role of this organisation whose `type` is the invitation's own `app`, which
|
|
2977
|
+
* is exactly what that flow can pick.
|
|
2978
|
+
*
|
|
2979
|
+
* A `cancelled` invitation offers nothing: the organisation took it back. Any
|
|
2980
|
+
* other status counts, for the reason `hasOrgInvitation` gives (the member row
|
|
2981
|
+
* is written after the invitation is marked complete).
|
|
2982
|
+
*/
|
|
2983
|
+
declare function invitationOffersRole(userId?: string | ObjectId | null, orgId?: string | ObjectId | null, roleId?: string | ObjectId | null): Promise<boolean>;
|
|
2984
|
+
/**
|
|
2985
|
+
* Which of these role ids are ORGANISATION-level, i.e. the `roles` document
|
|
2986
|
+
* carries no `site` of its own. One batched lookup, `site` the only field it
|
|
2987
|
+
* needs.
|
|
2988
|
+
*
|
|
2989
|
+
* Fails closed: a role that is missing, soft-deleted or unreadable is absent
|
|
2990
|
+
* from the set and therefore reads as SITE-level — the narrowing side, which is
|
|
2991
|
+
* the safe way to be wrong about a rule that widens access.
|
|
2992
|
+
*
|
|
2993
|
+
* Shared by `resolveInviteActor` (the site LIST half, `orgSiteScope`) and by
|
|
2994
|
+
* `resolveSiteAccess` in the camera service (the ACCESS half, `cameraGrant`),
|
|
2995
|
+
* because the two must answer "is this an org-level role?" identically or the
|
|
2996
|
+
* switcher offers sites the camera view refuses.
|
|
2997
|
+
*/
|
|
2998
|
+
declare function orgLevelRoles(db: Db, roles: Array<unknown>): Promise<Set<string>>;
|
|
2999
|
+
/**
|
|
3000
|
+
* Does this person OWN this organisation — did they create it, or is it
|
|
3001
|
+
* registered under their own account e-mail?
|
|
3002
|
+
*
|
|
3003
|
+
* DV-0248. The client owner who signs themselves up creates the organisation
|
|
3004
|
+
* (`POST /api/organizations/onboarding`) and only gets their `members` row at
|
|
3005
|
+
* the LAST onboarding step, from `ensureCurrentUserMemberExists`. Every step in
|
|
3006
|
+
* between — save the org details, create the first site, create the roles,
|
|
3007
|
+
* invite the admins — asked for a membership or an invitation, and the owner
|
|
3008
|
+
* has neither. So the wizard refused its own owner at step 1, and the
|
|
3009
|
+
* organisation never appeared in their list either. On staging, 64 of 195
|
|
3010
|
+
* organisations have no member and no invitation at all.
|
|
3011
|
+
*
|
|
3012
|
+
* Two roads, because the second repairs the ones already stuck:
|
|
3013
|
+
*
|
|
3014
|
+
* - `createdBy` — stamped from the session when the organisation is created,
|
|
3015
|
+
* never from the request body. Fixes every NEW signup, and is the road that
|
|
3016
|
+
* would have been enough on its own if the field had always existed.
|
|
3017
|
+
* - `email` — the organisation is registered under the caller's own account
|
|
3018
|
+
* address. This is the SAME comparison `organization.repo getAll` already
|
|
3019
|
+
* makes to scope the client list, against the same session-resolved address,
|
|
3020
|
+
* and it is what lets the 64 existing organisations repair themselves with no
|
|
3021
|
+
* data backfill.
|
|
3022
|
+
*
|
|
3023
|
+
* The e-mail road is only sound because `PATCH /api/users/field/:id` no longer
|
|
3024
|
+
* lets a user set their own address (`requireUserFieldWrite`). While it did,
|
|
3025
|
+
* anyone could have typed a victim organisation's address and walked in; that
|
|
3026
|
+
* hole is closed in the same change, and re-opening it re-opens this.
|
|
3027
|
+
*
|
|
3028
|
+
* Case-insensitive by collation rather than `$regex`, for the reason
|
|
3029
|
+
* `hasOrgInvitation` gives: an address may contain `+` or `.` and building a
|
|
3030
|
+
* pattern out of one invites an escaping bug.
|
|
3031
|
+
*/
|
|
3032
|
+
declare function hasOrgOwnership(userId?: string | ObjectId | null, orgId?: string | ObjectId | null): Promise<boolean>;
|
|
3033
|
+
/**
|
|
3034
|
+
* Has this account been APPROVED? `isAccountLive` (blank = an older live
|
|
3035
|
+
* account) minus `resubmit`: a resident applicant asked to resubmit can sign
|
|
3036
|
+
* in, and self-signup already gave them an active resident `members` row and
|
|
3037
|
+
* the site they applied for, but the client has not accepted them.
|
|
3038
|
+
*/
|
|
3039
|
+
declare function readsAsApprovedAccount(status?: string | null): boolean;
|
|
3040
|
+
/** `readsAsApprovedAccount` for a user id. Fails closed: unreadable is "no". */
|
|
3041
|
+
declare function callerAccountApproved(userId?: string | ObjectId | null): Promise<boolean>;
|
|
3042
|
+
/**
|
|
3043
|
+
* Does this person LIVE at, or WORK on, one of this organisation's sites?
|
|
3044
|
+
*
|
|
3045
|
+
* The two relationships `requireOrgReach` does not see, because neither is a
|
|
3046
|
+
* membership OF this organisation:
|
|
3047
|
+
*
|
|
3048
|
+
* - **a resident** (`residents-are-not-members`): the Service365 app reads its
|
|
3049
|
+
* own client's record (`residentAppModules`, `defaultSite`) and a resident's
|
|
3050
|
+
* tie to the estate lives on the `users` document (`site`, `unitId`) or a
|
|
3051
|
+
* `site.people` row, not in `members`. Every one of those is server-written,
|
|
3052
|
+
* but a self-signup stores the site and unit it APPLIED for, and a rejected
|
|
3053
|
+
* or resubmit applicant can still sign in. So these roads count only for an
|
|
3054
|
+
* approved account (`readsAsApprovedAccount`), and only an
|
|
3055
|
+
* `active`/`approved` `site.people` row. `PATCH
|
|
3056
|
+
* /api/users/field` does not accept `site` or `unitId`. The organisation's
|
|
3057
|
+
* `defaultSite` being the resident's own site counts too — it is exactly the
|
|
3058
|
+
* fallback the app itself uses.
|
|
3059
|
+
* - **a service provider** engaged by this client: an active `customer.sites`
|
|
3060
|
+
* row between one of the caller's organisations and this one
|
|
3061
|
+
* (`customer-sites-row-is-the-engagement`).
|
|
3062
|
+
*
|
|
3063
|
+
* `memberOrgIds` is the caller's own organisations, already resolved by the
|
|
3064
|
+
* caller of this function. Fails closed: anything unreadable is "no".
|
|
3065
|
+
*/
|
|
3066
|
+
declare function hasOrgSiteReach(userId?: string | ObjectId | null, orgId?: string | ObjectId | null, memberOrgIds?: string[]): Promise<boolean>;
|
|
3067
|
+
/**
|
|
3068
|
+
* Does this person themselves HOLD this role?
|
|
3069
|
+
*
|
|
3070
|
+
* `GET /api/roles/id/:id` is read on the hot path by every signed-in session —
|
|
3071
|
+
* `layer-common plugins/secure-member.client.ts` resolves the caller's own app
|
|
3072
|
+
* role, and the guard app's `permission.store.ts` does the same — so the only
|
|
3073
|
+
* scoping rule that can go on it has to keep "my own role" working. Scoping it
|
|
3074
|
+
* by the role's organisation alone does not: staging carries 12 roles with NO
|
|
3075
|
+
* `org` at all, one of which ("Org Owner") is held by 119 ordinary tenant
|
|
3076
|
+
* members across eight membership types. An org-less role routes to the staff
|
|
3077
|
+
* gate, so those 119 accounts would 401 on their own role and both callers fail
|
|
3078
|
+
* closed — permissions silently emptying, with nothing in the product to say
|
|
3079
|
+
* why.
|
|
3080
|
+
*
|
|
3081
|
+
* The relationship is a live `members` row joining the caller's user id to this
|
|
3082
|
+
* exact role id. **Both halves are resolved server-side**: the user id comes
|
|
3083
|
+
* from the session (`callerId`), never from a body or a query field, and the
|
|
3084
|
+
* role id is the resource being asked for. There is nothing a caller can send
|
|
3085
|
+
* that makes this answer yes for a role they do not hold — naming somebody
|
|
3086
|
+
* else's role id simply finds no row.
|
|
3087
|
+
*
|
|
3088
|
+
* `status: { $ne: "deleted" }` is the same liveness test every other membership
|
|
3089
|
+
* read in this package uses, so a revoked membership stops conferring the read.
|
|
3090
|
+
*/
|
|
3091
|
+
declare function holdsRole(userId?: string | ObjectId | null, roleId?: string | ObjectId | null,
|
|
3092
|
+
/** when given, the live membership must also be in THIS organisation */
|
|
3093
|
+
orgId?: string | ObjectId | null): Promise<boolean>;
|
|
3094
|
+
|
|
3095
|
+
/** What the site module-list handlers read and write; injected so a unit test runs them with no database. */
|
|
3096
|
+
type TSiteModulesDeps = {
|
|
3097
|
+
requireSiteWrite: (req: Request, siteId: string) => Promise<InviteActor>;
|
|
3098
|
+
_getSiteById: (id: string) => Promise<any>;
|
|
3099
|
+
_getOrgById: (id: string) => Promise<any>;
|
|
3100
|
+
_updateById: (id: string, value: any) => Promise<unknown>;
|
|
3101
|
+
recordConsoleAction: (entry: Parameters<typeof recordConsoleAction>[0]) => Promise<unknown>;
|
|
3102
|
+
gateData?: TModuleGateData;
|
|
2295
3103
|
};
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
orgId: string;
|
|
2300
|
-
name: string;
|
|
2301
|
-
description?: string | undefined;
|
|
2302
|
-
customerId: string;
|
|
2303
|
-
category: SiteCategories;
|
|
2304
|
-
address: {
|
|
2305
|
-
line1: string;
|
|
2306
|
-
line2?: string;
|
|
2307
|
-
city: string;
|
|
2308
|
-
state?: string;
|
|
2309
|
-
postalCode: string;
|
|
2310
|
-
country: string;
|
|
2311
|
-
};
|
|
2312
|
-
}) => Promise<{
|
|
2313
|
-
site: bson.ObjectId;
|
|
2314
|
-
}>;
|
|
2315
|
-
updateGuardPostById: (site: string, guardPost: number) => Promise<void>;
|
|
2316
|
-
updateById: (_id: string, payload: TSite) => Promise<void>;
|
|
2317
|
-
siteInformation: ({ id, payload }: {
|
|
2318
|
-
id: string;
|
|
2319
|
-
payload: TSiteInformation;
|
|
2320
|
-
}) => Promise<number>;
|
|
3104
|
+
declare function siteModulesHandlers({ requireSiteWrite, _getSiteById, _getOrgById, _updateById, recordConsoleAction, gateData, }: TSiteModulesDeps): {
|
|
3105
|
+
updateSiteModules: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
3106
|
+
previewSiteModules: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
2321
3107
|
};
|
|
2322
|
-
|
|
2323
3108
|
declare function useSiteController(): {
|
|
2324
3109
|
createSite: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
2325
3110
|
getSites: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
@@ -2327,7 +3112,8 @@ declare function useSiteController(): {
|
|
|
2327
3112
|
updateSiteBlock: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
2328
3113
|
deleteSite: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
2329
3114
|
updateById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
2330
|
-
updateSiteModules: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
3115
|
+
updateSiteModules: (req: Request<express_serve_static_core.ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction) => Promise<void>;
|
|
3116
|
+
previewSiteModules: (req: Request<express_serve_static_core.ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction) => Promise<void>;
|
|
2331
3117
|
updateGuardPostsById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
2332
3118
|
siteInformation: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
2333
3119
|
getAllSitesForResidentCreation: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
@@ -6756,7 +7542,7 @@ declare function useBulletinBoardRepo(): {
|
|
|
6756
7542
|
site: string | ObjectId;
|
|
6757
7543
|
status: string;
|
|
6758
7544
|
recipients: Array<string>;
|
|
6759
|
-
expiration?: "
|
|
7545
|
+
expiration?: "no" | "yes" | undefined;
|
|
6760
7546
|
}, session?: ClientSession) => Promise<{
|
|
6761
7547
|
items: any[];
|
|
6762
7548
|
pages: number;
|
|
@@ -10822,187 +11608,25 @@ type TSelfServiceResendFacts = {
|
|
|
10822
11608
|
now: number;
|
|
10823
11609
|
};
|
|
10824
11610
|
type TSelfServiceResendDecision = {
|
|
10825
|
-
ok: true;
|
|
10826
|
-
email: string;
|
|
10827
|
-
persistEmail: boolean;
|
|
10828
|
-
} | {
|
|
10829
|
-
ok: false;
|
|
10830
|
-
httpStatus: 400 | 404 | 429;
|
|
10831
|
-
reason: string;
|
|
10832
|
-
};
|
|
10833
|
-
/**
|
|
10834
|
-
* What the public resend route may do with an id.
|
|
10835
|
-
*
|
|
10836
|
-
* The rule that matters: an address ALREADY on the record wins, always. A
|
|
10837
|
-
* caller can fill in a blank one - that is what the card's inline field is for,
|
|
10838
|
-
* and it grants no more than the id already did, since the id alone opens the
|
|
10839
|
-
* pass page - but it can never redirect a pass that is already addressed to
|
|
10840
|
-
* someone. Without that, a harvested id would be a way to have another
|
|
10841
|
-
* person's check-in QR mailed anywhere.
|
|
10842
|
-
*/
|
|
10843
|
-
declare function decideSelfServiceResend(facts: TSelfServiceResendFacts): TSelfServiceResendDecision;
|
|
10844
|
-
|
|
10845
|
-
/**
|
|
10846
|
-
* Who is asking, resolved from the session id alone.
|
|
10847
|
-
*
|
|
10848
|
-
* Every invitation action re-derives this — the caller never states who they
|
|
10849
|
-
* are in a body or a query field.
|
|
10850
|
-
*
|
|
10851
|
-
* **Super admin is a membership, not an email address.** `createDefaultUser()`
|
|
10852
|
-
* seeds a role named "Super Admin" with `type: "admin"` and a `members` row with
|
|
10853
|
-
* `type: "admin"` and NO organisation; the user behind it is whatever
|
|
10854
|
-
* `DEFAULT_USER_EMAIL` is set to in that environment (`admin@gmail.com` on
|
|
10855
|
-
* staging, something else in production). Gating on the email address would
|
|
10856
|
-
* therefore work on staging and fail in production, and would break the day the
|
|
10857
|
-
* account is rotated. Both halves are required — a `members` row of type
|
|
10858
|
-
* "admin" whose role is also of type "admin" — because staging carries a second
|
|
10859
|
-
* role merely NAMED "Super Admin" that is an ordinary organisation role.
|
|
10860
|
-
*/
|
|
10861
|
-
type InviteActor = {
|
|
10862
|
-
id: string;
|
|
10863
|
-
name: string;
|
|
10864
|
-
isSuperAdmin: boolean;
|
|
10865
|
-
/** every organisation this user is a live member of */
|
|
10866
|
-
orgIds: string[];
|
|
10867
|
-
/** organisations this user represents as a property management company */
|
|
10868
|
-
propertyManagementOrgIds: string[];
|
|
10869
|
-
/**
|
|
10870
|
-
* Every live membership as an `(org, siteId)` pair, `siteId` empty when the
|
|
10871
|
-
* membership carries no site — i.e. when it is an org-wide role.
|
|
10872
|
-
*
|
|
10873
|
-
* `orgIds` above flattens this and throws the site away, which is right for
|
|
10874
|
-
* the organisation-level gates that read it. The LISTING paths need the site
|
|
10875
|
-
* back: `GET /api/customer-sites?org=` authorises at organisation level and
|
|
10876
|
-
* then returned the organisation's whole estate, so a user invited to one
|
|
10877
|
-
* site was offered every site in the client. See `orgSiteScope`.
|
|
10878
|
-
*
|
|
10879
|
-
* `orgLevelRole` is true when the membership's ROLE is organisation-level —
|
|
10880
|
-
* the `roles` document carries no `site` of its own. Owner decision of
|
|
10881
|
-
* 2026-09-02: an org-level role sees every site EVEN IF its membership row
|
|
10882
|
-
* also names one, so the stray `siteId` on an Org Owner row must not narrow
|
|
10883
|
-
* them. It fails closed: a missing, soft-deleted or unreadable role is not
|
|
10884
|
-
* org-level.
|
|
10885
|
-
*/
|
|
10886
|
-
memberships: Array<{
|
|
10887
|
-
org: string;
|
|
10888
|
-
siteId: string;
|
|
10889
|
-
orgLevelRole: boolean;
|
|
10890
|
-
}>;
|
|
10891
|
-
/**
|
|
10892
|
-
* The `permissions` array of the LIVE staff role behind `isSuperAdmin`, or
|
|
10893
|
-
* undefined when the caller is not Seven365 staff.
|
|
10894
|
-
*
|
|
10895
|
-
* The role document is already read two lines below to decide
|
|
10896
|
-
* `isSuperAdmin`; only its `permissions` field was being thrown away. Carrying
|
|
10897
|
-
* it costs no extra query and is what lets `staffMayBypass` ask the console
|
|
10898
|
-
* catalogue's question instead of identity alone. Undefined and `[]` are NOT
|
|
10899
|
-
* the same thing: `[]` is a staff role that holds everything (the empty-list
|
|
10900
|
-
* rule), undefined is somebody who is not staff at all.
|
|
10901
|
-
*/
|
|
10902
|
-
staffPermissions?: string[];
|
|
10903
|
-
};
|
|
10904
|
-
declare function resolveInviteActor(userId?: string | ObjectId | null): Promise<InviteActor>;
|
|
10905
|
-
/**
|
|
10906
|
-
* Does this person hold an invitation naming this organisation?
|
|
10907
|
-
*
|
|
10908
|
-
* The org-scoping rule on roles and memberships is "Seven365 staff, or a live
|
|
10909
|
-
* member of this organisation" — but three live flows legitimately reach an
|
|
10910
|
-
* organisation the caller is **not yet** a member of, because joining it is the
|
|
10911
|
-
* whole point:
|
|
10912
|
-
*
|
|
10913
|
-
* - the service-provider signing in against a `service-provider-invite`
|
|
10914
|
-
* (`web-app-main pages/sign-in.vue:298,428`), who looks up that customer's
|
|
10915
|
-
* "Admin Service Provider" role and then enrols;
|
|
10916
|
-
* - the admin member finishing sign-up from a `member-invite`
|
|
10917
|
-
* (`web-app-main pages/verify/email/index.vue:462`);
|
|
10918
|
-
* - the client owner walking the onboarding wizard
|
|
10919
|
-
* (`web-app-org pages/onboarding/getting-started/index.vue`).
|
|
10920
|
-
*
|
|
10921
|
-
* All three are holding an invitation addressed to their OWN email whose
|
|
10922
|
-
* `metadata.org` is the organisation being reached, so that invitation is the
|
|
10923
|
-
* relationship the rule tests. Both string and ObjectId shapes are matched,
|
|
10924
|
-
* because `MVerification` casts `metadata.org` to an ObjectId while older rows
|
|
10925
|
-
* carry a string — the same pair `completePendingInvites` matches on.
|
|
10926
|
-
*
|
|
10927
|
-
* Any status counts: `completeOrgAdminAccount` marks the verification complete
|
|
10928
|
-
* before the member row is written, so a pending-only test would refuse the
|
|
10929
|
-
* flow it exists to protect.
|
|
10930
|
-
*/
|
|
10931
|
-
declare function hasOrgInvitation(userId?: string | ObjectId | null, orgId?: string | ObjectId | null): Promise<boolean>;
|
|
10932
|
-
/**
|
|
10933
|
-
* Which of these role ids are ORGANISATION-level, i.e. the `roles` document
|
|
10934
|
-
* carries no `site` of its own. One batched lookup, `site` the only field it
|
|
10935
|
-
* needs.
|
|
10936
|
-
*
|
|
10937
|
-
* Fails closed: a role that is missing, soft-deleted or unreadable is absent
|
|
10938
|
-
* from the set and therefore reads as SITE-level — the narrowing side, which is
|
|
10939
|
-
* the safe way to be wrong about a rule that widens access.
|
|
10940
|
-
*
|
|
10941
|
-
* Shared by `resolveInviteActor` (the site LIST half, `orgSiteScope`) and by
|
|
10942
|
-
* `resolveSiteAccess` in the camera service (the ACCESS half, `cameraGrant`),
|
|
10943
|
-
* because the two must answer "is this an org-level role?" identically or the
|
|
10944
|
-
* switcher offers sites the camera view refuses.
|
|
10945
|
-
*/
|
|
10946
|
-
declare function orgLevelRoles(db: Db, roles: Array<unknown>): Promise<Set<string>>;
|
|
10947
|
-
/**
|
|
10948
|
-
* Does this person OWN this organisation — did they create it, or is it
|
|
10949
|
-
* registered under their own account e-mail?
|
|
10950
|
-
*
|
|
10951
|
-
* DV-0248. The client owner who signs themselves up creates the organisation
|
|
10952
|
-
* (`POST /api/organizations/onboarding`) and only gets their `members` row at
|
|
10953
|
-
* the LAST onboarding step, from `ensureCurrentUserMemberExists`. Every step in
|
|
10954
|
-
* between — save the org details, create the first site, create the roles,
|
|
10955
|
-
* invite the admins — asked for a membership or an invitation, and the owner
|
|
10956
|
-
* has neither. So the wizard refused its own owner at step 1, and the
|
|
10957
|
-
* organisation never appeared in their list either. On staging, 64 of 195
|
|
10958
|
-
* organisations have no member and no invitation at all.
|
|
10959
|
-
*
|
|
10960
|
-
* Two roads, because the second repairs the ones already stuck:
|
|
10961
|
-
*
|
|
10962
|
-
* - `createdBy` — stamped from the session when the organisation is created,
|
|
10963
|
-
* never from the request body. Fixes every NEW signup, and is the road that
|
|
10964
|
-
* would have been enough on its own if the field had always existed.
|
|
10965
|
-
* - `email` — the organisation is registered under the caller's own account
|
|
10966
|
-
* address. This is the SAME comparison `organization.repo getAll` already
|
|
10967
|
-
* makes to scope the client list, against the same session-resolved address,
|
|
10968
|
-
* and it is what lets the 64 existing organisations repair themselves with no
|
|
10969
|
-
* data backfill.
|
|
10970
|
-
*
|
|
10971
|
-
* The e-mail road is only sound because `PATCH /api/users/field/:id` no longer
|
|
10972
|
-
* lets a user set their own address (`requireUserFieldWrite`). While it did,
|
|
10973
|
-
* anyone could have typed a victim organisation's address and walked in; that
|
|
10974
|
-
* hole is closed in the same change, and re-opening it re-opens this.
|
|
10975
|
-
*
|
|
10976
|
-
* Case-insensitive by collation rather than `$regex`, for the reason
|
|
10977
|
-
* `hasOrgInvitation` gives: an address may contain `+` or `.` and building a
|
|
10978
|
-
* pattern out of one invites an escaping bug.
|
|
10979
|
-
*/
|
|
10980
|
-
declare function hasOrgOwnership(userId?: string | ObjectId | null, orgId?: string | ObjectId | null): Promise<boolean>;
|
|
10981
|
-
/**
|
|
10982
|
-
* Does this person themselves HOLD this role?
|
|
10983
|
-
*
|
|
10984
|
-
* `GET /api/roles/id/:id` is read on the hot path by every signed-in session —
|
|
10985
|
-
* `layer-common plugins/secure-member.client.ts` resolves the caller's own app
|
|
10986
|
-
* role, and the guard app's `permission.store.ts` does the same — so the only
|
|
10987
|
-
* scoping rule that can go on it has to keep "my own role" working. Scoping it
|
|
10988
|
-
* by the role's organisation alone does not: staging carries 12 roles with NO
|
|
10989
|
-
* `org` at all, one of which ("Org Owner") is held by 119 ordinary tenant
|
|
10990
|
-
* members across eight membership types. An org-less role routes to the staff
|
|
10991
|
-
* gate, so those 119 accounts would 401 on their own role and both callers fail
|
|
10992
|
-
* closed — permissions silently emptying, with nothing in the product to say
|
|
10993
|
-
* why.
|
|
10994
|
-
*
|
|
10995
|
-
* The relationship is a live `members` row joining the caller's user id to this
|
|
10996
|
-
* exact role id. **Both halves are resolved server-side**: the user id comes
|
|
10997
|
-
* from the session (`callerId`), never from a body or a query field, and the
|
|
10998
|
-
* role id is the resource being asked for. There is nothing a caller can send
|
|
10999
|
-
* that makes this answer yes for a role they do not hold — naming somebody
|
|
11000
|
-
* else's role id simply finds no row.
|
|
11611
|
+
ok: true;
|
|
11612
|
+
email: string;
|
|
11613
|
+
persistEmail: boolean;
|
|
11614
|
+
} | {
|
|
11615
|
+
ok: false;
|
|
11616
|
+
httpStatus: 400 | 404 | 429;
|
|
11617
|
+
reason: string;
|
|
11618
|
+
};
|
|
11619
|
+
/**
|
|
11620
|
+
* What the public resend route may do with an id.
|
|
11001
11621
|
*
|
|
11002
|
-
*
|
|
11003
|
-
*
|
|
11622
|
+
* The rule that matters: an address ALREADY on the record wins, always. A
|
|
11623
|
+
* caller can fill in a blank one - that is what the card's inline field is for,
|
|
11624
|
+
* and it grants no more than the id already did, since the id alone opens the
|
|
11625
|
+
* pass page - but it can never redirect a pass that is already addressed to
|
|
11626
|
+
* someone. Without that, a harvested id would be a way to have another
|
|
11627
|
+
* person's check-in QR mailed anywhere.
|
|
11004
11628
|
*/
|
|
11005
|
-
declare function
|
|
11629
|
+
declare function decideSelfServiceResend(facts: TSelfServiceResendFacts): TSelfServiceResendDecision;
|
|
11006
11630
|
|
|
11007
11631
|
declare function useAuthControllerV2(): {
|
|
11008
11632
|
signUp: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
@@ -12006,7 +12630,7 @@ declare function MHidAmicoIdentity(value: THidAmicoIdentity): {
|
|
|
12006
12630
|
member: ObjectId | undefined;
|
|
12007
12631
|
serviceProvider: ObjectId | undefined;
|
|
12008
12632
|
visitor: ObjectId | undefined;
|
|
12009
|
-
type: "admin" | "resident" | "
|
|
12633
|
+
type: "admin" | "resident" | "staff" | "contractor" | "unknown" | "visitor";
|
|
12010
12634
|
status: "deleted" | "active" | "inactive";
|
|
12011
12635
|
metadata: Record<string, unknown>;
|
|
12012
12636
|
createdAt: string | Date;
|
|
@@ -12118,7 +12742,7 @@ declare function useHidAmicoRepo(): {
|
|
|
12118
12742
|
member: ObjectId | undefined;
|
|
12119
12743
|
serviceProvider: ObjectId | undefined;
|
|
12120
12744
|
visitor: ObjectId | undefined;
|
|
12121
|
-
type: "admin" | "resident" | "
|
|
12745
|
+
type: "admin" | "resident" | "staff" | "contractor" | "unknown" | "visitor";
|
|
12122
12746
|
status: "deleted" | "active" | "inactive";
|
|
12123
12747
|
metadata: Record<string, unknown>;
|
|
12124
12748
|
createdAt: string | Date;
|
|
@@ -12522,7 +13146,7 @@ declare function useHidAmicoService(): {
|
|
|
12522
13146
|
member: bson.ObjectId | undefined;
|
|
12523
13147
|
serviceProvider: bson.ObjectId | undefined;
|
|
12524
13148
|
visitor: bson.ObjectId | undefined;
|
|
12525
|
-
type: "admin" | "resident" | "
|
|
13149
|
+
type: "admin" | "resident" | "staff" | "contractor" | "unknown" | "visitor";
|
|
12526
13150
|
status: "deleted" | "active" | "inactive";
|
|
12527
13151
|
metadata: Record<string, unknown>;
|
|
12528
13152
|
createdAt: string | Date;
|
|
@@ -12912,267 +13536,89 @@ declare function usePlatformTermsRepo(): {
|
|
|
12912
13536
|
}>;
|
|
12913
13537
|
getById: (id: string | ObjectId) => Promise<TPlatformTerms>;
|
|
12914
13538
|
getByVersion: (version: number) => Promise<mongodb.WithId<TPlatformTerms> | null>;
|
|
12915
|
-
getLatest: () => Promise<TPlatformTerms>;
|
|
12916
|
-
getNextVersion: () => Promise<number>;
|
|
12917
|
-
};
|
|
12918
|
-
|
|
12919
|
-
declare function usePlatformTermsService(): {
|
|
12920
|
-
getLatest: () => Promise<{
|
|
12921
|
-
_id: ObjectId | undefined;
|
|
12922
|
-
version: number;
|
|
12923
|
-
terms: string;
|
|
12924
|
-
policies: string;
|
|
12925
|
-
createdAt: string | undefined;
|
|
12926
|
-
}>;
|
|
12927
|
-
getById: (id: string | ObjectId) => Promise<{
|
|
12928
|
-
_id: ObjectId | undefined;
|
|
12929
|
-
version: number;
|
|
12930
|
-
terms: string;
|
|
12931
|
-
policies: string;
|
|
12932
|
-
createdAt: string | undefined;
|
|
12933
|
-
}>;
|
|
12934
|
-
assertLatestTerms: (termsId: string | ObjectId) => Promise<TPlatformTerms>;
|
|
12935
|
-
getStatusByUserId: (userId: string | ObjectId) => Promise<{
|
|
12936
|
-
latestVersion: {
|
|
12937
|
-
_id: ObjectId | undefined;
|
|
12938
|
-
version: number;
|
|
12939
|
-
};
|
|
12940
|
-
acceptedTerms: string | null;
|
|
12941
|
-
acceptedTermsAt: string | null;
|
|
12942
|
-
isCurrent: boolean;
|
|
12943
|
-
}>;
|
|
12944
|
-
acceptByUserId: (userId: string | ObjectId, termsId: string | ObjectId, session?: ClientSession) => Promise<{
|
|
12945
|
-
acceptedTerms: ObjectId | undefined;
|
|
12946
|
-
version: number;
|
|
12947
|
-
}>;
|
|
12948
|
-
getStatusByPersonId: (personId: string | ObjectId) => Promise<{
|
|
12949
|
-
latestVersion: {
|
|
12950
|
-
_id: ObjectId | undefined;
|
|
12951
|
-
version: number;
|
|
12952
|
-
};
|
|
12953
|
-
acceptedTerms: string | null;
|
|
12954
|
-
acceptedTermsAt: string | null;
|
|
12955
|
-
isCurrent: boolean;
|
|
12956
|
-
}>;
|
|
12957
|
-
acceptByPersonId: (personId: string | ObjectId, termsId: string | ObjectId) => Promise<{
|
|
12958
|
-
acceptedTerms: ObjectId | undefined;
|
|
12959
|
-
version: number;
|
|
12960
|
-
}>;
|
|
12961
|
-
listAcceptance: ({ version, accepted, page, limit, }: {
|
|
12962
|
-
version?: number | null | undefined;
|
|
12963
|
-
accepted?: boolean | undefined;
|
|
12964
|
-
page?: number | undefined;
|
|
12965
|
-
limit?: number | undefined;
|
|
12966
|
-
}) => Promise<{
|
|
12967
|
-
items: any[];
|
|
12968
|
-
pages: number;
|
|
12969
|
-
pageRange: string;
|
|
12970
|
-
}>;
|
|
12971
|
-
add: ({ terms, policies, createdBy, }: {
|
|
12972
|
-
terms: string;
|
|
12973
|
-
policies: string;
|
|
12974
|
-
createdBy: string | ObjectId;
|
|
12975
|
-
}) => Promise<{
|
|
12976
|
-
_id: ObjectId;
|
|
12977
|
-
version: number;
|
|
12978
|
-
terms: string;
|
|
12979
|
-
policies: string;
|
|
12980
|
-
createdBy: string | ObjectId;
|
|
12981
|
-
status?: string | undefined;
|
|
12982
|
-
createdAt?: string | undefined;
|
|
12983
|
-
updatedAt?: string | undefined;
|
|
12984
|
-
}>;
|
|
12985
|
-
};
|
|
12986
|
-
|
|
12987
|
-
declare function usePlatformTermsController(): {
|
|
12988
|
-
getLatest: (_req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
12989
|
-
getById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
12990
|
-
getStatus: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
12991
|
-
getAcceptance: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
12992
|
-
accept: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
12993
|
-
add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
12994
|
-
};
|
|
12995
|
-
|
|
12996
|
-
declare function isTermsCurrent(accepted: string | null | undefined, latestVersionId: string): boolean;
|
|
12997
|
-
declare function normalizeAcceptedTerms(acceptedTerms: ObjectId | string | null | undefined): string | null;
|
|
12998
|
-
|
|
12999
|
-
/**
|
|
13000
|
-
* What the Seven365 staff console records, as pure functions.
|
|
13001
|
-
*
|
|
13002
|
-
* Everything here is decidable without a database, a network or an Express
|
|
13003
|
-
* request, which is the point: the rules that decide **what is allowed into an
|
|
13004
|
-
* audit row** must be testable on their own. The row is written by
|
|
13005
|
-
* `console-audit.repo.ts`; this file decides its shape and its contents.
|
|
13006
|
-
*
|
|
13007
|
-
* The one rule that governs the whole file: an audit row holds **who, what,
|
|
13008
|
-
* which object, when, and enough of the values to make sense of the change**.
|
|
13009
|
-
* It is not a copy of the document. Fields are admitted by an **allow-list per
|
|
13010
|
-
* action** — anything not named there is dropped, so a handler that later
|
|
13011
|
-
* passes a whole record cannot leak an email address, a phone number, a
|
|
13012
|
-
* password hash or a token into the audit collection by accident.
|
|
13013
|
-
*/
|
|
13014
|
-
/** The staff actions worth keeping a record of. */
|
|
13015
|
-
declare enum ConsoleAuditAction {
|
|
13016
|
-
SUBSCRIPTION_CREATED = "subscription.created",
|
|
13017
|
-
SUBSCRIPTION_UPDATED = "subscription.updated",
|
|
13018
|
-
CLIENT_CREATED = "client.created",
|
|
13019
|
-
CLIENT_SUSPENDED = "client.suspended",
|
|
13020
|
-
CLIENT_REACTIVATED = "client.reactivated",
|
|
13021
|
-
/**
|
|
13022
|
-
* Seven365 staff changing which catalogue modules a client is offered.
|
|
13023
|
-
*
|
|
13024
|
-
* Recorded because it is a commercial decision about a paying client that
|
|
13025
|
-
* somebody has to be able to answer for later, even though it grants and
|
|
13026
|
-
* revokes nothing by itself (`org-modules.util.ts` - it narrows what a role
|
|
13027
|
-
* editor OFFERS, and the server re-decides every request regardless).
|
|
13028
|
-
*/
|
|
13029
|
-
CLIENT_MODULES_CHANGED = "client.modules-changed",
|
|
13030
|
-
PROMO_CODE_CREATED = "promo-code.created",
|
|
13031
|
-
PROMO_CODE_UPDATED = "promo-code.updated",
|
|
13032
|
-
PROMO_CODE_STATUS_CHANGED = "promo-code.status-changed",
|
|
13033
|
-
PROMO_CODE_REMOVED = "promo-code.removed",
|
|
13034
|
-
PLAN_CREATED = "plan.created",
|
|
13035
|
-
PLAN_UPDATED = "plan.updated",
|
|
13036
|
-
PLAN_STATUS_CHANGED = "plan.status-changed",
|
|
13037
|
-
TERMS_PUBLISHED = "terms.published",
|
|
13038
|
-
/**
|
|
13039
|
-
* Seven365 staff switching a client's camera on or off.
|
|
13040
|
-
*
|
|
13041
|
-
* The only tenant-owned object on this list, and it is here because it is the
|
|
13042
|
-
* only one staff may touch: a faulty camera at a client's site has to be
|
|
13043
|
-
* switchable off by us. See `updateById` in `site-camera.controller.ts` for
|
|
13044
|
-
* the boundary that allows it and nothing else.
|
|
13045
|
-
*/
|
|
13046
|
-
CAMERA_STATUS_CHANGED = "camera.status-changed",
|
|
13047
|
-
/**
|
|
13048
|
-
* A camera being added, edited or removed BY THE SITE'S OWN PEOPLE.
|
|
13049
|
-
*
|
|
13050
|
-
* The three below are the answer to "who changed this camera's address, and
|
|
13051
|
-
* when" - a question that had no answer anywhere in the system. A camera
|
|
13052
|
-
* record carries `createdAt`/`updatedAt` and no actor, and a write overwrites
|
|
13053
|
-
* the previous `host` in place, so a wrong port number could only be traced by
|
|
13054
|
-
* asking people what they remembered doing. At Seventh Condominium that turned
|
|
13055
|
-
* a one-line correction into nine days.
|
|
13056
|
-
*
|
|
13057
|
-
* This is a widening of what the collection holds: `CAMERA_STATUS_CHANGED` is
|
|
13058
|
-
* a Seven365 STAFF action, and these are tenant actions. That is deliberate.
|
|
13059
|
-
* The console is where an operator goes to answer exactly this question, the
|
|
13060
|
-
* row already carries `actor`, `target` and `createdAt`, and the alternative -
|
|
13061
|
-
* a second audit collection with its own repository, model and indexes - is
|
|
13062
|
-
* more moving parts for the same row. Nothing existing changes: the collection
|
|
13063
|
-
* is append-only and every reader filters by `action`.
|
|
13064
|
-
*/
|
|
13065
|
-
CAMERA_ADDED = "camera.added",
|
|
13066
|
-
CAMERA_UPDATED = "camera.updated",
|
|
13067
|
-
CAMERA_REMOVED = "camera.removed"
|
|
13068
|
-
}
|
|
13069
|
-
/**
|
|
13070
|
-
* The three actions that live in `organization.controller.ts`.
|
|
13071
|
-
*
|
|
13072
|
-
* They are defined, labelled and tested here, but **nothing calls them yet**.
|
|
13073
|
-
* `organization.controller.ts` is being edited by open PR #1884 (suspend), and
|
|
13074
|
-
* editing the same handlers here would hand a reviewer a merge conflict for no
|
|
13075
|
-
* gain. Each needs exactly one `recordConsoleAction(...)` call once #1884
|
|
13076
|
-
* lands; the action names and labels are already in place for it.
|
|
13077
|
-
*/
|
|
13078
|
-
declare const CLIENT_ACTIONS: ConsoleAuditAction[];
|
|
13079
|
-
/** What a person reads on the screen. The row carries it so the screen need not map it. */
|
|
13080
|
-
declare const CONSOLE_AUDIT_LABELS: Record<ConsoleAuditAction, string>;
|
|
13081
|
-
/** What kind of thing the action was done to. */
|
|
13082
|
-
declare enum ConsoleAuditTarget {
|
|
13083
|
-
ORGANIZATION = "organization",
|
|
13084
|
-
SUBSCRIPTION = "subscription",
|
|
13085
|
-
PROMO_CODE = "promo-code",
|
|
13086
|
-
PLAN = "plan",
|
|
13087
|
-
TERMS = "terms",
|
|
13088
|
-
CAMERA = "camera"
|
|
13089
|
-
}
|
|
13090
|
-
/** A stored value is a primitive or it is not stored. */
|
|
13091
|
-
declare const AUDIT_VALUE_MAX_LENGTH = 120;
|
|
13092
|
-
/**
|
|
13093
|
-
* The part of a change that may be stored, for this action.
|
|
13094
|
-
*
|
|
13095
|
-
* Returns `undefined` rather than `{}` when nothing survives, so an empty
|
|
13096
|
-
* object never occupies a row and a reader can tell "nothing recorded" from
|
|
13097
|
-
* "recorded as empty".
|
|
13098
|
-
*/
|
|
13099
|
-
declare function pickAuditFields(action: ConsoleAuditAction, value?: Record<string, unknown> | null): Record<string, string | number | boolean> | undefined;
|
|
13100
|
-
|
|
13101
|
-
/**
|
|
13102
|
-
* One staff action in the Seven365 console.
|
|
13103
|
-
*
|
|
13104
|
-
* A new collection. Nothing existing is changed, no field is added to any live
|
|
13105
|
-
* document, and there is no migration — a client, a subscription, a promo code
|
|
13106
|
-
* and a plan are all exactly as they were.
|
|
13107
|
-
*
|
|
13108
|
-
* `actor` is a `users._id` and it comes from the SESSION, never from the
|
|
13109
|
-
* request body. The body-attribution defect fixed on `POST /api/terms` earlier
|
|
13110
|
-
* today is the reason that is written down rather than assumed.
|
|
13111
|
-
*/
|
|
13112
|
-
type TConsoleAudit = {
|
|
13113
|
-
_id?: ObjectId;
|
|
13114
|
-
action: ConsoleAuditAction;
|
|
13115
|
-
/** Who. A `users._id`, resolved from the session. */
|
|
13116
|
-
actor: string | ObjectId;
|
|
13117
|
-
/** Which client it affected, when the action is about one. */
|
|
13118
|
-
org?: string | ObjectId | null;
|
|
13119
|
-
/** Which object changed, and of what kind. */
|
|
13120
|
-
target?: string | ObjectId | null;
|
|
13121
|
-
targetType?: ConsoleAuditTarget | null;
|
|
13122
|
-
/** Enough of the change to make sense of it — never a whole document. */
|
|
13123
|
-
before?: Record<string, unknown> | null;
|
|
13124
|
-
after?: Record<string, unknown> | null;
|
|
13125
|
-
/** ISO-8601 UTC, so a lexicographic range filter is also a date range filter. */
|
|
13126
|
-
createdAt?: string;
|
|
13127
|
-
};
|
|
13128
|
-
declare const schemaConsoleAudit: Joi.ObjectSchema<any>;
|
|
13129
|
-
declare function MConsoleAudit(value: TConsoleAudit): TConsoleAudit;
|
|
13130
|
-
|
|
13131
|
-
declare const console_audit_namespace_collection = "console-audit";
|
|
13132
|
-
type TConsoleAuditQuery = {
|
|
13133
|
-
org?: string;
|
|
13134
|
-
action?: string;
|
|
13135
|
-
/** ISO-8601. Inclusive at both ends of the day the caller names. */
|
|
13136
|
-
from?: string;
|
|
13137
|
-
to?: string;
|
|
13138
|
-
page?: number;
|
|
13139
|
-
limit?: number;
|
|
13140
|
-
};
|
|
13141
|
-
declare function useConsoleAuditRepo(): {
|
|
13142
|
-
createIndexes: () => Promise<void>;
|
|
13143
|
-
add: (value: TConsoleAudit) => Promise<{
|
|
13144
|
-
_id: ObjectId;
|
|
13145
|
-
action: ConsoleAuditAction;
|
|
13146
|
-
actor: string | ObjectId;
|
|
13147
|
-
org?: string | ObjectId | null | undefined;
|
|
13148
|
-
target?: string | ObjectId | null | undefined;
|
|
13149
|
-
targetType?: ConsoleAuditTarget | null | undefined;
|
|
13150
|
-
before?: Record<string, unknown> | null | undefined;
|
|
13151
|
-
after?: Record<string, unknown> | null | undefined;
|
|
13152
|
-
createdAt?: string | undefined;
|
|
13539
|
+
getLatest: () => Promise<TPlatformTerms>;
|
|
13540
|
+
getNextVersion: () => Promise<number>;
|
|
13541
|
+
};
|
|
13542
|
+
|
|
13543
|
+
declare function usePlatformTermsService(): {
|
|
13544
|
+
getLatest: () => Promise<{
|
|
13545
|
+
_id: ObjectId | undefined;
|
|
13546
|
+
version: number;
|
|
13547
|
+
terms: string;
|
|
13548
|
+
policies: string;
|
|
13549
|
+
createdAt: string | undefined;
|
|
13153
13550
|
}>;
|
|
13154
|
-
|
|
13551
|
+
getById: (id: string | ObjectId) => Promise<{
|
|
13552
|
+
_id: ObjectId | undefined;
|
|
13553
|
+
version: number;
|
|
13554
|
+
terms: string;
|
|
13555
|
+
policies: string;
|
|
13556
|
+
createdAt: string | undefined;
|
|
13557
|
+
}>;
|
|
13558
|
+
assertLatestTerms: (termsId: string | ObjectId) => Promise<TPlatformTerms>;
|
|
13559
|
+
getStatusByUserId: (userId: string | ObjectId) => Promise<{
|
|
13560
|
+
latestVersion: {
|
|
13561
|
+
_id: ObjectId | undefined;
|
|
13562
|
+
version: number;
|
|
13563
|
+
};
|
|
13564
|
+
acceptedTerms: string | null;
|
|
13565
|
+
acceptedTermsAt: string | null;
|
|
13566
|
+
isCurrent: boolean;
|
|
13567
|
+
}>;
|
|
13568
|
+
acceptByUserId: (userId: string | ObjectId, termsId: string | ObjectId, session?: ClientSession) => Promise<{
|
|
13569
|
+
acceptedTerms: ObjectId | undefined;
|
|
13570
|
+
version: number;
|
|
13571
|
+
}>;
|
|
13572
|
+
getStatusByPersonId: (personId: string | ObjectId) => Promise<{
|
|
13573
|
+
latestVersion: {
|
|
13574
|
+
_id: ObjectId | undefined;
|
|
13575
|
+
version: number;
|
|
13576
|
+
};
|
|
13577
|
+
acceptedTerms: string | null;
|
|
13578
|
+
acceptedTermsAt: string | null;
|
|
13579
|
+
isCurrent: boolean;
|
|
13580
|
+
}>;
|
|
13581
|
+
acceptByPersonId: (personId: string | ObjectId, termsId: string | ObjectId) => Promise<{
|
|
13582
|
+
acceptedTerms: ObjectId | undefined;
|
|
13583
|
+
version: number;
|
|
13584
|
+
}>;
|
|
13585
|
+
listAcceptance: ({ version, accepted, page, limit, }: {
|
|
13586
|
+
version?: number | null | undefined;
|
|
13587
|
+
accepted?: boolean | undefined;
|
|
13588
|
+
page?: number | undefined;
|
|
13589
|
+
limit?: number | undefined;
|
|
13590
|
+
}) => Promise<{
|
|
13155
13591
|
items: any[];
|
|
13156
13592
|
pages: number;
|
|
13157
13593
|
pageRange: string;
|
|
13158
13594
|
}>;
|
|
13595
|
+
add: ({ terms, policies, createdBy, }: {
|
|
13596
|
+
terms: string;
|
|
13597
|
+
policies: string;
|
|
13598
|
+
createdBy: string | ObjectId;
|
|
13599
|
+
}) => Promise<{
|
|
13600
|
+
_id: ObjectId;
|
|
13601
|
+
version: number;
|
|
13602
|
+
terms: string;
|
|
13603
|
+
policies: string;
|
|
13604
|
+
createdBy: string | ObjectId;
|
|
13605
|
+
status?: string | undefined;
|
|
13606
|
+
createdAt?: string | undefined;
|
|
13607
|
+
updatedAt?: string | undefined;
|
|
13608
|
+
}>;
|
|
13159
13609
|
};
|
|
13160
|
-
|
|
13161
|
-
|
|
13162
|
-
|
|
13163
|
-
|
|
13164
|
-
|
|
13165
|
-
|
|
13166
|
-
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
13170
|
-
|
|
13171
|
-
|
|
13172
|
-
* accepted: an action can happen and its row fail to be written, in which case
|
|
13173
|
-
* the log carries it.
|
|
13174
|
-
*/
|
|
13175
|
-
declare function recordConsoleAction(entry: TConsoleAudit): Promise<void>;
|
|
13610
|
+
|
|
13611
|
+
declare function usePlatformTermsController(): {
|
|
13612
|
+
getLatest: (_req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
13613
|
+
getById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
13614
|
+
getStatus: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
13615
|
+
getAcceptance: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
13616
|
+
accept: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
13617
|
+
add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
13618
|
+
};
|
|
13619
|
+
|
|
13620
|
+
declare function isTermsCurrent(accepted: string | null | undefined, latestVersionId: string): boolean;
|
|
13621
|
+
declare function normalizeAcceptedTerms(acceptedTerms: ObjectId | string | null | undefined): string | null;
|
|
13176
13622
|
|
|
13177
13623
|
/**
|
|
13178
13624
|
* The staff console's own history: who did what, to which client, and when.
|
|
@@ -13447,172 +13893,104 @@ declare function isSuperAdmin(userId?: string | ObjectId | null): Promise<boolea
|
|
|
13447
13893
|
declare function isPlatformOwner(userId?: string | ObjectId | null): Promise<boolean>;
|
|
13448
13894
|
|
|
13449
13895
|
/**
|
|
13450
|
-
*
|
|
13451
|
-
*
|
|
13452
|
-
* `console-authz.util.ts` `requirePlatformStaff` answers ONE question — is this
|
|
13453
|
-
* session a Seven365 staff membership — and twelve controllers ask it before
|
|
13454
|
-
* every console write. It has never read which modules the staff role holds, so
|
|
13455
|
-
* a staff account onboarded onto a role ticked for Promo Codes alone could still
|
|
13456
|
-
* suspend a client, publish platform Terms, mint a subscription and read every
|
|
13457
|
-
* user on the platform. The console's own guard
|
|
13458
|
-
* (`web-app-org middleware/console-tier.global.ts` + `composables/useConsoleGate.ts`,
|
|
13459
|
-
* shipped in org #186) hides those screens from that role, but hiding a screen
|
|
13460
|
-
* is drawing, not securing: the endpoint behind it answered anybody with a staff
|
|
13461
|
-
* session. This file is the server half.
|
|
13462
|
-
*
|
|
13463
|
-
* ## The catalogue is a MIRROR, and it is pinned as one
|
|
13464
|
-
*
|
|
13465
|
-
* The strings below are `web-app-org composables/useAdminPermission.ts` — the
|
|
13466
|
-
* tick-boxes a `type: "admin"` role is actually built from — plus the two
|
|
13467
|
-
* families that composable pulls out of layer-common's `useCommonPermissions`
|
|
13468
|
-
* (`members`, `roles-and-permissions`). It is copied rather than imported
|
|
13469
|
-
* because `core` is a backend package and cannot depend on a Nuxt layer; a
|
|
13470
|
-
* server that invented its own vocabulary would be the
|
|
13471
|
-
* `visitor:create`/`visitor-mgmt:add-visitor` split all over again — a string
|
|
13472
|
-
* the server enforces that no role editor can grant.
|
|
13473
|
-
*
|
|
13474
|
-
* ## THE EMPTY-LIST RULE — why switching this on locks nobody out
|
|
13475
|
-
*
|
|
13476
|
-
* `user.service.ts createDefaultUser()` seeds the platform-staff role with
|
|
13477
|
-
* `permissions: []`, NOT `["*"]`. A plain membership test over this catalogue
|
|
13478
|
-
* would therefore refuse the Seven365 owner's own account on the day it shipped.
|
|
13479
|
-
*
|
|
13480
|
-
* So an EMPTY list means "everything", exactly as it does today, and `"*"` keeps
|
|
13481
|
-
* the short-circuit it has everywhere else in the estate. Both spellings the
|
|
13482
|
-
* staging owner role and the seeder can produce (`["*"]` and `[]`) allow all, so
|
|
13483
|
-
* **no role, member or user document has to be written for this to ship** —
|
|
13484
|
-
* which matters, because nothing in a repo may write one.
|
|
13485
|
-
*
|
|
13486
|
-
* The moment somebody ticks a module on a staff role, that role becomes
|
|
13487
|
-
* governed at BOTH ends. That is the intended behaviour, and it is the one case
|
|
13488
|
-
* to check before granting: a staff role that already holds a partial list is
|
|
13489
|
-
* enforced immediately.
|
|
13490
|
-
*
|
|
13491
|
-
* ## WIDENING ONLY
|
|
13492
|
-
*
|
|
13493
|
-
* Every check here is layered ON TOP of the staff identity test, never in place
|
|
13494
|
-
* of it — nobody who was refused before is admitted now. And the match accepts
|
|
13495
|
-
* ANY shipped spelling of a grant, the rule
|
|
13496
|
-
* `layer-common utils/permission-spellings.ts` already applies on the client:
|
|
13497
|
-
* `-admin`'s role editor writes `roles-and-permissions:add-role` while eight
|
|
13498
|
-
* apps write `roles:add-role`, and a role holding either must pass. Accepting
|
|
13499
|
-
* both costs nothing and needs no role migration; picking one would silently
|
|
13500
|
-
* un-grant every role holding the other.
|
|
13501
|
-
*/
|
|
13502
|
-
/** Console resource -> the actions a staff role can be granted on it. */
|
|
13503
|
-
declare const CONSOLE_PERMISSIONS: Readonly<Record<string, readonly string[]>>;
|
|
13504
|
-
/** Every shipped spelling of `resource:action`. */
|
|
13505
|
-
declare function consoleSpellings(resource: string, action: string): readonly string[];
|
|
13506
|
-
/** True when this staff role is ungoverned and reaches the whole console. */
|
|
13507
|
-
declare function consoleRoleAllowsAll(held?: readonly string[] | null): boolean;
|
|
13508
|
-
/**
|
|
13509
|
-
* May a staff role holding `held` take `action` on `resource`?
|
|
13510
|
-
*
|
|
13511
|
-
* Omit `action` to ask the SCREEN question — "does this role reach the resource
|
|
13512
|
-
* at all" — which is `consoleCanSee` on the client: any single action on the
|
|
13513
|
-
* resource is enough. Used where the catalogue has no string for the operation
|
|
13514
|
-
* (creating a client organisation, writing a platform role/member row), because
|
|
13515
|
-
* inventing a `create-organization` string here would be a grant no role editor
|
|
13516
|
-
* anywhere can tick.
|
|
13517
|
-
*
|
|
13518
|
-
* An unknown resource, or an action the catalogue does not carry, is REFUSED for
|
|
13519
|
-
* a governed role — the same answer `hasPermission` gives on the client, and the
|
|
13520
|
-
* control the tests assert.
|
|
13521
|
-
*/
|
|
13522
|
-
declare function consoleRoleAllows(held: readonly string[] | null | undefined, resource: string, action?: string): boolean;
|
|
13523
|
-
/**
|
|
13524
|
-
* THE CROSS-CLIENT GRANT — the one string that lets Seven365 staff out of
|
|
13525
|
-
* tenant scoping.
|
|
13526
|
-
*
|
|
13527
|
-
* Every tenant-scoping helper in this package (`requireSiteReach`,
|
|
13528
|
-
* `siteReachOf`, `entitledSites`, `requireOwnUnit`, `requireOrgReach`) opened
|
|
13529
|
-
* with `if (actor.isSuperAdmin) return`. That is an IDENTITY test: it asks who
|
|
13530
|
-
* the caller is and never asks what their staff role is ticked for. So a staff
|
|
13531
|
-
* account onboarded onto a role holding Promo Codes alone still read and wrote
|
|
13532
|
-
* every client's sites, people, files, documents, forms and facilities — the
|
|
13533
|
-
* console gate shipped at revision 35 governs the console's OWN endpoints, and
|
|
13534
|
-
* these are the tenant ones behind it.
|
|
13535
|
-
*
|
|
13536
|
-
* `organizations` is the catalogue string that already means "this staff role
|
|
13537
|
-
* reaches across clients" (`CONSOLE_PERMISSIONS.organizations` =
|
|
13538
|
-
* `see-all-organizations` / `see-organization-details`), and it is a tick-box
|
|
13539
|
-
* the admin role editor can actually grant. No new vocabulary is invented — a
|
|
13540
|
-
* string the server enforces that no editor can grant is the
|
|
13541
|
-
* `visitor:create` mistake, and this deliberately avoids it. The SCREEN
|
|
13542
|
-
* question is asked (no `action`), so either tick is enough.
|
|
13543
|
-
*/
|
|
13544
|
-
declare const CROSS_CLIENT_GRANT: {
|
|
13545
|
-
resource: string;
|
|
13546
|
-
action?: string;
|
|
13547
|
-
};
|
|
13548
|
-
/**
|
|
13549
|
-
* May this staff caller skip tenant scoping?
|
|
13896
|
+
* Q7 (owner, 2026-09-11): staff get NO notifications for modules they cannot
|
|
13897
|
+
* open.
|
|
13550
13898
|
*
|
|
13551
|
-
*
|
|
13552
|
-
*
|
|
13553
|
-
*
|
|
13554
|
-
*
|
|
13555
|
-
* exactly as they are today. The change is that platform identity alone stops
|
|
13556
|
-
* being a skeleton key.
|
|
13899
|
+
* Only the Super Admin module list drops anybody: a recipient is dropped when
|
|
13900
|
+
* EVERY membership they hold at the site denies EVERY module the category is
|
|
13901
|
+
* about. A resource the list does not govern (`site-settings` for camera
|
|
13902
|
+
* faults) is never denied, so it always keeps the notification.
|
|
13557
13903
|
*
|
|
13558
|
-
*
|
|
13904
|
+
* The role check is computed and LOGGED only (master plan rule 3). The apps do
|
|
13905
|
+
* not enforce most role gates today, so a role-based drop would hide alerts for
|
|
13906
|
+
* screens people can open, and RP-5 forbids that loss.
|
|
13559
13907
|
*
|
|
13560
|
-
*
|
|
13561
|
-
*
|
|
13562
|
-
*
|
|
13563
|
-
*
|
|
13564
|
-
* user document has to be written for this to ship and nobody loses access on
|
|
13565
|
-
* deploy.
|
|
13908
|
+
* Exempt, never dropped: residents; anyone with no membership at the site
|
|
13909
|
+
* (invitees, a push-token user with no member row); Seven365 staff; a send
|
|
13910
|
+
* with no site (marketplace, broadcasts); a category not in the catalogue or
|
|
13911
|
+
* with no permission resources (resident-only and marketplace ones).
|
|
13566
13912
|
*
|
|
13567
|
-
*
|
|
13568
|
-
*
|
|
13569
|
-
*
|
|
13570
|
-
* client it holds a membership or engagement in; it loses only the reach it was
|
|
13571
|
-
* never ticked for.
|
|
13572
|
-
*/
|
|
13573
|
-
declare function staffMayBypass(actor: {
|
|
13574
|
-
isSuperAdmin: boolean;
|
|
13575
|
-
staffPermissions?: string[];
|
|
13576
|
-
}, grant?: {
|
|
13577
|
-
resource: string;
|
|
13578
|
-
action?: string;
|
|
13579
|
-
}): boolean;
|
|
13580
|
-
|
|
13581
|
-
/**
|
|
13582
|
-
* ONE console module, optionally ONE action on it.
|
|
13913
|
+
* `NOTIFY_ACCESS_FILTER`: `log` (code default) counts, logs and SENDS TO
|
|
13914
|
+
* EVERYONE; `on` drops; `off` reads nothing. `MODULE_LIST_GATE=off` is the
|
|
13915
|
+
* same as `off`. Any error sends to everyone.
|
|
13583
13916
|
*
|
|
13584
|
-
*
|
|
13585
|
-
*
|
|
13586
|
-
*
|
|
13917
|
+
* Both senders call this: core's `notification.service.ts send()` here, and
|
|
13918
|
+
* API-core's own `send()` (a separate class; memory
|
|
13919
|
+
* `two-notification-senders-not-one`), which must call it the same way.
|
|
13587
13920
|
*/
|
|
13588
|
-
type
|
|
13589
|
-
|
|
13590
|
-
|
|
13921
|
+
type TNotifyAccessMode = "log" | "on" | "off";
|
|
13922
|
+
declare const NOTIFY_ACCESS_FILTER_DEFAULT: TNotifyAccessMode;
|
|
13923
|
+
declare function notifyAccessMode(env?: Record<string, string | undefined>): TNotifyAccessMode;
|
|
13924
|
+
type TNotifyAccessContext = {
|
|
13925
|
+
category?: string | null;
|
|
13926
|
+
siteId?: unknown;
|
|
13591
13927
|
};
|
|
13592
|
-
|
|
13593
|
-
|
|
13594
|
-
|
|
13595
|
-
|
|
13596
|
-
|
|
13597
|
-
|
|
13598
|
-
|
|
13599
|
-
|
|
13600
|
-
|
|
13601
|
-
|
|
13602
|
-
*
|
|
13603
|
-
*
|
|
13604
|
-
|
|
13605
|
-
|
|
13606
|
-
|
|
13607
|
-
|
|
13608
|
-
|
|
13609
|
-
|
|
13610
|
-
*
|
|
13611
|
-
*
|
|
13612
|
-
*
|
|
13613
|
-
*
|
|
13614
|
-
|
|
13615
|
-
|
|
13928
|
+
type TNotifyAccessReport = {
|
|
13929
|
+
dropByModule: string[];
|
|
13930
|
+
/** Logged only, never dropped. */
|
|
13931
|
+
dropByRole: string[];
|
|
13932
|
+
/** No membership at the site: counted, never dropped. */
|
|
13933
|
+
noMember: string[];
|
|
13934
|
+
};
|
|
13935
|
+
/** Who this send would drop, and why. `null` when the send is exempt as a whole. */
|
|
13936
|
+
declare function notificationAccessReport(userIds: readonly unknown[], context: TNotifyAccessContext, data?: TModuleGateData): Promise<TNotifyAccessReport | null>;
|
|
13937
|
+
/**
|
|
13938
|
+
* The recipients this send may reach. In `log` mode (the default) that is
|
|
13939
|
+
* always all of them. Never throws.
|
|
13940
|
+
*/
|
|
13941
|
+
declare function filterByAccess<T extends string | {
|
|
13942
|
+
toString(): string;
|
|
13943
|
+
}>(userIds: T[], context: TNotifyAccessContext, data?: TModuleGateData): Promise<T[]>;
|
|
13944
|
+
|
|
13945
|
+
/**
|
|
13946
|
+
* Q3 (owner, 2026-09-11): the server must ALSO refuse modules a client has not
|
|
13947
|
+
* been given. This is the primitive. API-core's `requireSiteAccess` maps a
|
|
13948
|
+
* route to its module and asks here once the site is resolved.
|
|
13949
|
+
*
|
|
13950
|
+
* `MODULE_GATE_MODE`: `log` (code default) never refuses anything, it logs a
|
|
13951
|
+
* `would-refuse` line; `enforce` refuses only the modules listed in
|
|
13952
|
+
* `MODULE_GATE_ENFORCE_KEYS`; `off` reads nothing. `MODULE_LIST_GATE=off` is
|
|
13953
|
+
* the same as `off`.
|
|
13954
|
+
*
|
|
13955
|
+
* Allowed, always: Seven365 staff, residents, anyone with no membership at the
|
|
13956
|
+
* site, an ungoverned or unmapped module, a module only SOME of the person's
|
|
13957
|
+
* memberships at the site deny, and every error.
|
|
13958
|
+
*
|
|
13959
|
+
* OFFLINE WORK (owner, 2026-09-11): work done while the person still had
|
|
13960
|
+
* access is accepted. A queued offline item carries its original, frozen
|
|
13961
|
+
* timestamp (memory `isecure365-offline-mode`); pass it as `at`. It is refused
|
|
13962
|
+
* only if it was stamped at or after the acknowledged save that denied the
|
|
13963
|
+
* module. With no `at`, the request is treated as happening now.
|
|
13964
|
+
*
|
|
13965
|
+
* ponytail: `at` is the client's own clock, so a forged old timestamp slips
|
|
13966
|
+
* through. That fails open, which is the rule everywhere here; bound it by a
|
|
13967
|
+
* maximum queue age when enforcement starts.
|
|
13968
|
+
*/
|
|
13969
|
+
type TModuleGateMode = "log" | "enforce" | "off";
|
|
13970
|
+
declare const MODULE_GATE_MODE_DEFAULT: TModuleGateMode;
|
|
13971
|
+
declare function moduleGateMode(env?: Record<string, string | undefined>): TModuleGateMode;
|
|
13972
|
+
/** The modules `enforce` refuses: comma-separated, any spelling. Empty = none. */
|
|
13973
|
+
declare function moduleGateEnforceKeys(env?: Record<string, string | undefined>): string[];
|
|
13974
|
+
type TModuleAccess = {
|
|
13975
|
+
/** Answer 403: only in `enforce` mode, and only for an enforced key. */
|
|
13976
|
+
refuse: boolean;
|
|
13977
|
+
/** The client's list denies this module for this person, at the time of the work. */
|
|
13978
|
+
denied: boolean;
|
|
13979
|
+
};
|
|
13980
|
+
declare function moduleDeniedForCaller({ userId, site, module, at, }: {
|
|
13981
|
+
userId?: unknown;
|
|
13982
|
+
/** The site id, or the site document when the caller already has it. */
|
|
13983
|
+
site?: {
|
|
13984
|
+
_id?: unknown;
|
|
13985
|
+
orgId?: unknown;
|
|
13986
|
+
metadata?: {
|
|
13987
|
+
modules?: unknown;
|
|
13988
|
+
} | null;
|
|
13989
|
+
} | string | null;
|
|
13990
|
+
module?: string | null;
|
|
13991
|
+
/** When the work was done: an offline item's original timestamp. */
|
|
13992
|
+
at?: Date | string | number | null;
|
|
13993
|
+
}, data?: TModuleGateData): Promise<TModuleAccess>;
|
|
13616
13994
|
|
|
13617
13995
|
type Recipient = string | ObjectId | Array<string | ObjectId>;
|
|
13618
13996
|
declare class NotificationService {
|
|
@@ -14234,4 +14612,4 @@ declare function usePersonalEmergencyChainController(): {
|
|
|
14234
14612
|
update: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
14235
14613
|
};
|
|
14236
14614
|
|
|
14237
|
-
export { ANPRMode, APP_BASE_URLS, AUDIT_VALUE_MAX_LENGTH, AccessTypeProps, AppKey, AppServiceType, AssignCardConfig, BULK_CAMERA_COLUMNS, BidStatus, BidType, BuildingLevelStatus, BuildingStatus, BulkCameraAccepted, BulkCameraOutcome, BulkCameraPlan, BulkCameraResult, BulkCardUpdate, BulletinOrder, BulletinRecipient, BulletinSort, BulletinStatus, BulletinVideoOrder, BulletinVideoSort, CAMERA_ANPR_PERMISSIONS, CAMERA_CAPABILITIES, CAMERA_CAPABILITY_REASONS, CAMERA_MANAGE_ANY_PERMISSIONS, CAMERA_NOT_PATROL_OR_CCTV, CAMERA_NO_SUB_STREAM_TTL_SECONDS, CAMERA_PTZ_PERMISSIONS, CAMERA_REQUEST_TIMEOUT_MS, CAMERA_RTSP_TIMEOUT_MS, CAMERA_SETUP_PERMISSIONS, CAMERA_SNAPSHOT_CACHE_SECONDS, CAMERA_SNAPSHOT_MAX_BYTES, CAMERA_TEST_MIN_INTERVAL_SECONDS, CAMERA_TEST_ROUND_LIMIT, CAMERA_TEST_ROUND_SECONDS, CAMERA_TYPE_ANPR, CAMERA_TYPE_IP, CAMERA_VIEW_PERMISSIONS, CLIENT_ACTIONS, CLOCK_DRIFT_WARN_SECONDS, CONSOLE_AUDIT_LABELS, CONSOLE_PERMISSIONS, CONTRACTOR_TYPE_LABELS, CROSS_CLIENT_GRANT, CURRENT_TIME_ENDPOINT, Camera, CameraAddressInput, CameraCapability, CameraCapabilityContext, CameraCapabilityDescriptor, CameraCapabilityEntry, CameraCapabilityReason, CameraCapabilityState, CameraCapabilityTrace, CameraDevice, CameraFrame, CameraMembership, CameraStream, CameraTestStatus, CameraTransport, CameraType, ConsoleAuditAction, ConsoleAuditTarget, ConsoleGrant, DEFAULT_RING_SECONDS, DEFAULT_SITE_TIMEZONE, DEVICE_STATUS, DOBStatus, DUPLICATE_TERMS_VERSION_MESSAGE, DayOfWeek, DeviceHttpTarget, DeviceProbeResult, DynamicFormFields, E164, EAccessCardTypes, EAccessCardUserTypes, EmailSender, EntryOrder, EntrySort, EventOrder, EventSort, EventStatus, EventType, FacilitySort, FacilityStatus, FormEntryStatus, GuestSort, GuestStatus, HID_CARD_VALUE_FACTOR, HID_PERMISSION_CATEGORIES, HID_UINT32_MAX, HID_UINT64_MAX, HidRawUint64, IAccessCard, IAccessCardTransaction, InviteActor, LIVE_ROLE, MAX_BULK_CAMERA_ROWS, MAX_CAMERA_CHANNEL, MAX_CAMERA_NAME_LENGTH, MAX_PERSONAL_EMERGENCY_CONTACTS, MAX_RING_SECONDS, MAccessCard, MAccessCardTransaction, MAddress, MAttendance, MAttendanceSettings, MBidPreloved, MBillingConfiguration, MBillingItem, MBuilding, MBuildingLevel, MBuildingUnit, MBulletinBoard, MBulletinVideo, MCategoryPreloved, MChannelPreloved, MChat, MChatPreloved, MConsoleAudit, MCustomer, MCustomerSite, MDocumentManagement, MEMBER_TYPES, MEntryPassSettings, MEventManagement, MFeedback, MFile, MFormEntry, MGuestManagement, MHidAmicoEvent, MHidAmicoIdentity, MHidAmicoReader, MHidSipAccount, MHidSitePermissions, MIN_RING_SECONDS, MIncidentReport, MManpowerDesignations, MManpowerMonitoring, MManpowerRemarks, MManpowerSites, MMember, MNfcPatrolLog, MNfcPatrolRoute, MNfcPatrolSettings, MNfcPatrolSettingsUpdate, MNfcPatrolTag, MNotification, MNotificationPreference, MOccurrenceBook, MOccurrenceEntry, MOccurrenceSubject, MOnlineForm, MOrg, MOvernightParkingApprovalHours, MOvernightParkingRequest, MPatrolEmail, MPatrolLog, MPatrolQuestion, MPatrolRoute, MPerson, MPersonalEmergencyChain, MPlatformTerms, MPost, MPostFavorite, MPromoCode, MRobot, MRole, MRoleV2, MServiceProvider, MServiceProviderBilling, MSession, MSite, MSiteCamera, MSiteFacility, MSiteFacilityBooking, MStatementOfAccount, MSubcategoryPreloved, MSubscription, MSubscriptionPlan, MUnitBilling, MUser, MVehicle, MVehicleTransaction, MVerification, MVerificationV2, MVisitorTransaction, MWorkOrder, NOTIFICATION_CATEGORIES, NOTIFICATION_CHANNELS, NOTIFICATION_CHANNEL_LABELS, NOTIFICATION_NAMESPACE, NotificationAppSlug, NotificationCategory, NotificationChannel, NotificationModule, NotificationPreferenceView, NotificationService, ORG_MARKETPLACE_VENDOR_FIELD, OrgNature, OvernightParkingRequestSort, OvernightParkingRequestStatus, PATROL_CCTV_CAMERA_FILTER, PATROL_EMAIL_MAX_LOGS, PATROL_EMAIL_MAX_PER_HOUR, PATROL_EMAIL_MAX_RECIPIENTS, PERSON_TYPES, PLATFORM_STAFF_MEMBER_TYPE, PLATFORM_STAFF_ROLE_TYPE, PROPERTY_MANAGEMENT_MEMBER_TYPES, PStatus, PTZ_ALLOWED_ACTIONS, PTZ_ALLOWED_CODES, Period, PersonStatus, PersonType, PersonTypes, PlatformTermsStatus, PostOrder, PostSort, PostStatus, QrTagProps, REALTIME_MAX_FANOUT, ResidentAppModuleKey, SELF_SERVICE_RESEND_COOLDOWN_MS, SELF_SIGNUP_PLATFORM, SELF_SIGNUP_STATUS, SELF_SIGNUP_TYPES, SERVICE_PROVIDER_INVITE_LABELS, SERVICE_PROVIDER_INVITE_TRANSITIONS, SERVICE_PROVIDER_SIGN_IN_SUBJECT, SERVICE_PROVIDER_SIGN_IN_TYPE, SERVICE_PROVIDER_SIGN_UP_SUBJECT, SERVICE_PROVIDER_SIGN_UP_TYPE, SOFTWARE_VERSION_ENDPOINT, ServiceProviderInviteAction, ServiceProviderInviteDecision, ServiceProviderInviteFacts, SiteAddress, SiteCategories, SiteStatus, SortFields, SortOrder, Status, SubjectOrder, SubjectSort, SubscriptionBillingMode, SubscriptionType, TAccessMngmntSettings, TActionStatus, TAddress, TAffectedEntities, TAffectedInjured, TAppServiceType, TApprovedBy, TApprover, TAttendance, TAttendanceCheckIn, TAttendanceCheckOut, TAttendanceCheckTime, TAttendanceLocation, TAttendanceSettings, TAttendanceSettingsGetBySite, TAuthorities, TAuthoritiesCalled, TBidPreloved, TBilling, TBillingConfiguration, TBillingItem, TBuilding, TBuildingLevel, TBuildingUnit, TBulletinBoard, TBulletinVideo, TCamera, TCameraHealthClaim, TCategoryPreloved, TChannelPreloved, TChat, TChatPreloved, TCheckPoint$1 as TCheckPoint, TComplaintInfo, TComplaintReceivedTo, TConsoleAudit, TConsoleAuditQuery, TCounter, TCreateNfcPatrolLog, TCustomer, TCustomerSite, TCustomerSitePropertyField, TDayNumber, TDaySchedule, TDefaultAccessCard, TDesignations, TDocs, TDocumentCreate, TDocumentManagement, TEntryPassSettings, TEventManagement, TFeedback, TFeedbackMetadata, TFeedbackUpdate, TFeedbackUpdateCategory, TFeedbackUpdateServiceProvider, TFeedbackUpdateStatus, TFeedbackUpdateToCompleted, TFile, TFiles, TFolderUpdate, TFormEntry, TGetAttendancesByUserQuery, TGetAttendancesQuery, TGuestManagement, THidAmicoEvent, THidAmicoGatewayJob, THidAmicoIdentity, THidAmicoPhysicalCard, THidAmicoReader, THidPermissionAssignment, THidPermissionCategory, THidPermissionUserBinding, THidPhysicalCardInput, THidPhysicalCardType$1 as THidPhysicalCardType, THidSipAccount, THidSitePermissions, TIncidentInformation, TIncidentReport, TIncidentTypeAndTime, TInvoice, TKeyRef, TManpowerDesignations, TManpowerDesignationsUpdate, TManpowerMonitoring, TManpowerMonitoringUpdate, TManpowerRemarks, TManpowerRemarksStatusUpdate, TManpowerRemarksUpdate, TManpowerSearchFilter, TManpowerSites, TMember, TMemberUpdateStatus, TMessagePreloved, TMiniRole, TNfcPatrolLog, TNfcPatrolRoute, TNfcPatrolRouteEdit, TNfcPatrolSettings, TNfcPatrolSettingsGetBySite, TNfcPatrolSettingsUpdate, TNfcPatrolTag, TNfcPatrolTagConfigureReset, TNfcPatrolTagEdit, TNfcPatrolTagUpdateData, TNotification, TNotificationPreference, TNotificationPreferenceOff, TOccurrenceBook, TOccurrenceEntry, TOccurrenceSubject, TOnlineForm, TOrg, TOvernightParkingApprovalHours, TOvernightParkingRequest, TPatrolEmail, TPatrolEmailCreatedBy, TPatrolEmailLogRef, TPatrolLog, TPatrolQuestion, TPatrolRoute, TPerson, TPersonalEmergencyChain, TPersonalEmergencyContact, TPlaceOfIncident, TPlates, TPlatformTerms, TPost, TPostFavorite, TPrice, TPriceType, TPromoCode, TPromoCurrencyInput, TPromoTier, TRANSPORT_DEVICE_HTTP, TRANSPORT_RELAY_PLAYER, TRANSPORT_RTSP_FRAME, TRecipientOfComplaint, TRemarks, TResident, TResidentAppModules, TRobot, TRobotMetadata, TRole, TRolePermissionHistoryEntry, TRoleV2, TRoute, TSOABillingItem, TSOAStatus, TSelfServiceEmailOccasion, TSelfServiceEmailRecord, TSelfServiceResendDecision, TSelfServiceResendFacts, TServiceProvider, TServiceProviderBilling, TSession, TSessionCreate, TShifts, TSignNfcPatrolLog, TSite, TSiteCamera, TSiteDayBounds, TSiteFacility, TSiteFacilityBooking, TSiteInfo, TSiteInformation, TSiteMetadata, TSiteUpdateBlock, TStatementOfAccount, TSubcategoryPreloved, TSubmissionForm, TSubscription, TSubscriptionPlan, TSubscriptionPlanApplication, TUnitBilling, TUnits, TUpdateFormEntry, TUpdateName, TUser, TUserCreate, TVehicle, TVehicleTransaction, TVehicleUpdate, TVerification, TVerificationCode, TVerificationEvent, TVerificationMetadata, TVerificationMetadataV2, TVerificationOnboarding, TVerificationV2, TVisitorTransaction, TWorkOrder, TWorkOrderMetadata, TWorkOrderUpdate, TWorkOrderUpdateStatus, TWorkOrderUpdateToCompleted, TanyoneDamageToProperty, UNSTORED_COLUMNS, UseAccessManagementRepo, UserStatus, VERIFICATION_OPEN_STATUSES, VehicleCategory, VehicleOrder, VehicleSort, VehicleStatus, VehicleType, VerificationLinkType, VerificationStatus, VerificationSubjectType, VerificationType, VisitorSort, VisitorStatus, addressSchema, allowedFieldsSite, allowedNatures, allowedPlanApplications, attendanceSchema, attendanceSettingsSchema, buildSelfServiceEmailContext, building_level_namespace_collection, building_units_namespace_collection, buildings_namespace_collection, bulletin_boards_namespace_collection, callerId, cameraBaseUrl, cameraCapabilitiesFor, cameraDevices, cameraGrant, cameraHealthClaim, cameraHealthSummary, cameraManagePermissions, cameraProbeCacheKey, cameraTransports, canRevokeRefreshTokenFamily, categoriesForPermissions, categorySupportsChannel, chatPrelovedEvents, chatSchema, clampPtzSpeed, clockDriftSeconds, consoleRoleAllows, consoleRoleAllowsAll, consoleSpellings, console_audit_namespace_collection, createManpowerRemarksDaily, customerSchema, customerSitePropertyFields, decideSelfServiceResend, decideServiceProviderInvite, decodeHidPacsCard, deriveBulletinStatus, deriveCameraHost, describeCameraCapabilities, designationsSchema, deviceControlEnabled, deviceHttpEnabled, deviceHttpTargets, deviceHttpTimeoutMs, deviceProbeTtlSeconds, emitNotificationCreated, emptyPersonalEmergencyChain, encodeHidPacsCard, entitledSiteScope, events_namespace_collection, expiredBulletinSweepFilter, expiredVehicleSweepFilter, facility_bookings_namespace_collection, feedbackSchema, feedbacks2_namespace_collection, feedbacks_namespace_collection, ffmpegFrameArgs, ffmpegPath, formatCapabilityTrace, formatDahuaDate, getIO, getSessionIdFromRequest, grabWithSubStreamFallback, guests_namespace_collection, hasAnyCapability, hasAnyPermission, hasOrgInvitation, hasOrgOwnership, hidRawUint64, holdsRole, incidentReport, incidentReportLog, incidents_namespace_collection, isCameraEntitled, isDuplicateVersionError, isLikelySelfServiceEmail, isPatrolCctvCamera, isPlatformOwner, isPromoCodeExpired, isRelayPlayerUrl, isSafeRelativePath, isSuperAdmin, isTermsCurrent, isValidTimezone, logCamera, manpowerDesignationsSchema, manpowerEvents, manpowerMonitoringSchema, manpowerRemarksSchema, manpowerSitesSchema, mapWithLimit, maskNric, nfcPatrolSettingsSchema, nfcPatrolSettingsSchemaUpdate, normalizeAcceptedTerms, normalizeHidCardValue, notificationCategory, notificationCategoryLabel, notificationEvents, notificationRoom, occasionForStatus, occurrence_book_namespace_collection, online_forms_namespace_collection, orgLevelRoles, orgSchema, overnight_parking_requests_namespace_collection, parseCameraChannel, parseCameraHost, parseDahuaFind, parseDeviceTime, parseHidJsonLossless, parsePromoExpiry, parseSoftwareVersion, pickAuditFields, pickCustomerSiteProperties, planBulkCameraImport, platform_terms_namespace_collection, promoCodeRefusal, promoCodeSchema, promoCodeStatusSchema, promoCodeUpdate, promoCodeUpdateSchema, ptzEndpoint, publicCameraFields, recordConsoleAction, refuseServiceProviderInviteAction, registerCameraTransport, relayForRecorder, remarksSchema, renderPagePdf, requireConsolePermission, requirePlatformStaff, resetCameraTransports, residentAppModuleKeys, residentAppModulesSchema, residentFormEntry, resolutionRefusalReason, resolveCamera, resolveDeviceHttp, resolveHidPhysicalCardValue, resolveInviteActor, resolveSiteTimezone, resolveStaffRole, robotSchema, rtspUrl, schema, schemaAppSlugNotification, schemaApprovedBy, schemaApprover, schemaBidPreloved, schemaBilling, schemaBillingConfiguration, schemaBillingItem, schemaBuilding, schemaBuildingLevel, schemaBuildingUnit, schemaBuildingUpdateOptions, schemaBulletinBoard, schemaBulletinVideo, schemaCategoryPreloved, schemaChannelPreloved, schemaChatPreloved, schemaConsoleAudit, schemaCreateHidAmicoIdentity, schemaCreateNfcPatrolLog, schemaCreateNotification, schemaCustomerSite, schemaDiscoverHidAmicoReader, schemaDocumentManagement, schemaEntryPassSettings, schemaEventManagement, schemaFiles, schemaFormEntry, schemaGuestManagement, schemaHidAmicoAccessLogQuery, schemaHidAmicoAssignUserCard, schemaHidAmicoConfiguration, schemaHidAmicoEnrollUserCard, schemaHidAmicoEvent, schemaHidAmicoExecuteActions, schemaHidAmicoIdentity, schemaHidAmicoIdentityIdParams, schemaHidAmicoIdentityQuery, schemaHidAmicoIntercomCall, schemaHidAmicoLogQuery, schemaHidAmicoMonitor, schemaHidAmicoNotificationParams, schemaHidAmicoObjectOperation, schemaHidAmicoOperatingMode, schemaHidAmicoReader, schemaHidAmicoReaderIdParams, schemaHidAmicoReaderListQuery, schemaHidAmicoReaderUserQuery, schemaHidAmicoSetConfiguration, schemaHidAmicoSiteIdParams, schemaHidAmicoSync, schemaHidAmicoUserCardIdParams, schemaHidAmicoUserCardParams, schemaHidAmicoUserImageParams, schemaHidAmicoUserImageUploadQuery, schemaHidAmicoUserPin, schemaHidAmicoUserPinParams, schemaHidAmicoVisitorImageParams, schemaHidAmicoVisitorImageUploadQuery, schemaHidAmicoVisitorQr, schemaHidPermissionCandidateQuery, schemaHidPermissionScopeQuery, schemaHidSipAccountRequest, schemaIncidentReport, schemaListNotification, schemaMultipleDocumentManagement, schemaNfcPatrolLog, schemaNfcPatrolRoute, schemaNfcPatrolTag, schemaNfcPatrolTagUpdateData, schemaNotification, schemaNotificationPreference, schemaNotificationPreferenceOff, schemaOccurrenceBook, schemaOccurrenceEntry, schemaOccurrenceSubject, schemaOnlineForm, schemaOvernightParkingApprovalHours, schemaOvernightParkingRequest, schemaPatrolEmail, schemaPatrolEmailCreatedBy, schemaPatrolEmailLogRef, schemaPatrolEmailQuery, schemaPatrolLog, schemaPatrolQuestion, schemaPatrolRoute, schemaPerson, schemaPersonalEmergencyContact, schemaPlate, schemaPlatformTerms, schemaPost, schemaPostFavorite, schemaResendPatrolEmail, schemaResidentSelfSignUp, schemaSelfServiceVisitor, schemaSendPatrolEmail, schemaServiceProvider, schemaServiceProviderBilling, schemaSignNfcPatrolLog, schemaSiteCamera, schemaSiteFacility, schemaSiteFacilityBooking, schemaStatementOfAccount, schemaSubcategoryPreloved, schemaUnitBilling, schemaUpdateBidPreloved, schemaUpdateBuildingLevel, schemaUpdateBulletinBoard, schemaUpdateBulletinVideo, schemaUpdateCategoryPreloved, schemaUpdateChatPreloved, schemaUpdateDocumentManagement, schemaUpdateEntryPassSettings, schemaUpdateEventManagement, schemaUpdateFolderManagement, schemaUpdateFormEntry, schemaUpdateGuestManagement, schemaUpdateHidAmicoIdentity, schemaUpdateHidAmicoReader, schemaUpdateHidSitePermissions, schemaUpdateIncidentReport, schemaUpdateNotification, schemaUpdateNotificationPreference, schemaUpdateOccurrenceBook, schemaUpdateOccurrenceEntry, schemaUpdateOccurrenceSubject, schemaUpdateOnlineForm, schemaUpdateOptions, schemaUpdateOvernightParkingRequest, schemaUpdatePatrolLog, schemaUpdatePatrolQuestion, schemaUpdatePatrolRoute, schemaUpdatePerson, schemaUpdatePersonalEmergencyChain, schemaUpdatePost, schemaUpdatePostFavorite, schemaUpdateServiceProviderBilling, schemaUpdateSiteBillingConfiguration, schemaUpdateSiteBillingItem, schemaUpdateSiteCamera, schemaUpdateSiteFacility, schemaUpdateSiteFacilityBooking, schemaUpdateSiteUnitBilling, schemaUpdateStatementOfAccount, schemaUpdateSubcategoryPreloved, schemaUpdateVisTrans, schemaVehicleTransaction, schemaVisitorTransaction, schemeCamera, schemeLogCamera, selectHealthTargets, selfServiceEmailSubject, serviceProviderInviteLabel, sessionSchema, setIO, shiftSchema, siteDayBounds, siteSchema, site_people_namespace_collection, snapshotEndpoint, snapshotRefusalReason, staffMayBypass, stringifyHidJson, stripFacialImageMetadata, subscriptionPlanSchema, summariseBulkCameraPlan, updateRemarksStatusEod, updateRemarksisAcknowledged, updateSiteSchema, useAccessManagementController, useAddressRepo, useAttendanceController, useAttendanceRepository, useAttendanceSettingsController, useAttendanceSettingsRepository, useAttendanceSettingsService, useAuthController, useAuthControllerV2, useAuthService, useAuthServiceV2, useBidPrelovedController, useBidPrelovedRepo, useBidPrelovedService, useBuildingController, useBuildingLevelController, useBuildingLevelRepo, useBuildingLevelService, useBuildingRepo, useBuildingService, useBuildingUnitController, useBuildingUnitRepo, useBuildingUnitService, useBulletinBoardController, useBulletinBoardRepo, useBulletinBoardService, useBulletinVideoController, useBulletinVideoRepo, useBulletinVideoService, useCameraViewController, useCameraViewService, useCategoryPrelovedController, useCategoryPrelovedRepo, useChannelPrelovedController, useChannelPrelovedRepo, useChatController, useChatPrelovedController, useChatPrelovedRepo, useChatPrelovedService, useChatRepo, useConsoleAuditController, useConsoleAuditRepo, useCounterModel, useCounterRepo, useCustomerController, useCustomerRepo, useCustomerSiteController, useCustomerSiteRepo, useCustomerSiteService, useDahuaService, useDashboardController, useDashboardRepo, useDocumentManagementController, useDocumentManagementRepo, useDocumentManagementService, useEntryPassSettingsController, useEntryPassSettingsRepo, useEventManagementController, useEventManagementRepo, useEventManagementService, useFeedbackController, useFeedbackRepo, useFeedbackService, useFileController, useFileRepo, useFileService, useFormEntryController, useFormEntryRepo, useGuestManagementController, useGuestManagementRepo, useGuestManagementService, useHidAmicoController, useHidAmicoRepo, useHidAmicoService, useHrmLabsAttendanceCtrl, useHrmLabsAttendanceSrvc, useIncidentReportController, useIncidentReportRepo, useIncidentReportService, useInvoiceController, useInvoiceModel, useInvoiceRepo, useManpowerDesignationCtrl, useManpowerDesignationRepo, useManpowerMonitoringCtrl, useManpowerMonitoringRepo, useManpowerMonitoringSrvc, useManpowerRemarkCtrl, useManpowerRemarksRepo, useManpowerSitesCtrl, useManpowerSitesRepo, useManpowerSitesSrvc, useMemberController, useMemberRepo, useMemberService, useNewDashboardController, useNewDashboardRepo, useNfcPatrolLogController, useNfcPatrolLogRepo, useNfcPatrolLogService, useNfcPatrolRouteController, useNfcPatrolRouteRepo, useNfcPatrolRouteService, useNfcPatrolSettingsController, useNfcPatrolSettingsRepository, useNfcPatrolSettingsService, useNfcPatrolTagController, useNfcPatrolTagRepo, useNfcPatrolTagService, useNotificationController, useNotificationPreferenceController, useNotificationPreferenceRepo, useNotificationPreferenceService, useNotificationRepo, useOccurrenceBookController, useOccurrenceBookRepo, useOccurrenceBookService, useOccurrenceEntryController, useOccurrenceEntryRepo, useOccurrenceEntryService, useOccurrenceSubjectController, useOccurrenceSubjectRepo, useOccurrenceSubjectService, useOnlineFormController, useOnlineFormRepo, useOrgController, useOrgControllerV2, useOrgRepo, useOvernightParkingController, useOvernightParkingRepo, useOvernightParkingRequestController, useOvernightParkingRequestRepo, useOvernightParkingRequestService, usePatrolEmailController, usePatrolEmailRepo, usePatrolEmailService, usePatrolLogController, usePatrolLogRepo, usePatrolLogService, usePatrolQuestionController, usePatrolQuestionRepo, usePatrolRouteController, usePatrolRouteRepo, usePersonController, usePersonRepo, usePersonalEmergencyChainController, usePersonalEmergencyChainRepo, usePersonalEmergencyChainService, usePlatformTermsController, usePlatformTermsRepo, usePlatformTermsService, usePostFavoriteController, usePostFavoriteRepo, usePostFavoriteService, usePostPrelovedController, usePostPrelovedRepo, usePriceController, usePriceModel, usePriceRepo, usePromoCodeController, usePromoCodeRepo, useRedDotPaymentController, useRedDotPaymentRepo, useRedDotPaymentSvc, useRobotController, useRobotRepo, useRobotService, useRoleController, useRoleControllerV2, useRoleRepo, useRoleRepoV2, useRoleServiceV2, useServiceProviderBillingController, useServiceProviderBillingRepo, useServiceProviderBillingService, useServiceProviderController, useServiceProviderInviteController, useServiceProviderInviteService, useServiceProviderRepo, useSessionRepo, useSiteBillingConfigurationController, useSiteBillingConfigurationRepo, useSiteBillingItemController, useSiteBillingItemRepo, useSiteCameraController, useSiteCameraRepo, useSiteCameraService, useSiteController, useSiteFacilityBookingController, useSiteFacilityBookingRepo, useSiteFacilityBookingService, useSiteFacilityController, useSiteFacilityRepo, useSiteFacilityService, useSiteRepo, useSiteService, useSiteUnitBillingController, useSiteUnitBillingRepo, useSiteUnitBillingService, useStatementOfAccountController, useStatementOfAccountRepo, useSubcategoryPrelovedController, useSubcategoryPrelovedRepo, useSubscriptionController, useSubscriptionPlanController, useSubscriptionPlanRepo, useSubscriptionRepo, useSubscriptionService, useUserController, useUserControllerV2, useUserRepo, useUserRepoV2, useUserService, useUserServiceV2, useVehicleController, useVehicleRepo, useVehicleService, useVerificationController, useVerificationControllerV2, useVerificationRepo, useVerificationRepoV2, useVerificationService, useVerificationServiceV2, useVisitorTransactionController, useVisitorTransactionRepo, useVisitorTransactionService, useWorkOrderController, useWorkOrderRepo, useWorkOrderService, userSchema, vehicleSchema, vehicles_namespace_collection, visitorPersonRepo, visitorPersonService, visitorType, visitors_namespace_collection, wallConfig, workOrderSchema, work_orders2_namespace_collection, work_orders_namespace_collection };
|
|
14615
|
+
export { ANPRMode, APP_BASE_URLS, AUDIT_VALUE_MAX_LENGTH, AccessTypeProps, AppKey, AppServiceType, AssignCardConfig, BULK_CAMERA_COLUMNS, BidStatus, BidType, BuildingLevelStatus, BuildingStatus, BulkCameraAccepted, BulkCameraOutcome, BulkCameraPlan, BulkCameraResult, BulkCardUpdate, BulletinOrder, BulletinRecipient, BulletinSort, BulletinStatus, BulletinVideoOrder, BulletinVideoSort, CAMERA_ANPR_PERMISSIONS, CAMERA_CAPABILITIES, CAMERA_CAPABILITY_REASONS, CAMERA_MANAGE_ANY_PERMISSIONS, CAMERA_NOT_PATROL_OR_CCTV, CAMERA_NO_SUB_STREAM_TTL_SECONDS, CAMERA_PTZ_PERMISSIONS, CAMERA_REQUEST_TIMEOUT_MS, CAMERA_RTSP_TIMEOUT_MS, CAMERA_SETUP_PERMISSIONS, CAMERA_SNAPSHOT_CACHE_SECONDS, CAMERA_SNAPSHOT_MAX_BYTES, CAMERA_TEST_MIN_INTERVAL_SECONDS, CAMERA_TEST_ROUND_LIMIT, CAMERA_TEST_ROUND_SECONDS, CAMERA_TYPE_ANPR, CAMERA_TYPE_IP, CAMERA_VIEW_PERMISSIONS, CLIENT_ACTIONS, CLOCK_DRIFT_WARN_SECONDS, CONSOLE_AUDIT_LABELS, CONSOLE_PERMISSIONS, CONTRACTOR_TYPE_LABELS, CROSS_CLIENT_GRANT, CURRENT_TIME_ENDPOINT, Camera, CameraAddressInput, CameraCapability, CameraCapabilityContext, CameraCapabilityDescriptor, CameraCapabilityEntry, CameraCapabilityReason, CameraCapabilityState, CameraCapabilityTrace, CameraDevice, CameraFrame, CameraMembership, CameraStream, CameraTestStatus, CameraTransport, CameraType, ConsoleAuditAction, ConsoleAuditTarget, ConsoleGrant, DEFAULT_RING_SECONDS, DEFAULT_SITE_TIMEZONE, DEVICE_STATUS, DOBStatus, DUPLICATE_TERMS_VERSION_MESSAGE, DayOfWeek, DeviceHttpTarget, DeviceProbeResult, DynamicFormFields, E164, EAccessCardTypes, EAccessCardUserTypes, EmailSender, EntryOrder, EntrySort, EventOrder, EventSort, EventStatus, EventType, FacilitySort, FacilityStatus, FormEntryStatus, GOVERNED_MODULES, GuestSort, GuestStatus, HID_CARD_VALUE_FACTOR, HID_PERMISSION_CATEGORIES, HID_UINT32_MAX, HID_UINT64_MAX, HidRawUint64, IAccessCard, IAccessCardTransaction, InviteActor, LIVE_ROLE, MAX_BULK_CAMERA_ROWS, MAX_CAMERA_CHANNEL, MAX_CAMERA_NAME_LENGTH, MAX_PERSONAL_EMERGENCY_CONTACTS, MAX_RING_SECONDS, MAccessCard, MAccessCardTransaction, MAddress, MAttendance, MAttendanceSettings, MBidPreloved, MBillingConfiguration, MBillingItem, MBuilding, MBuildingLevel, MBuildingUnit, MBulletinBoard, MBulletinVideo, MCategoryPreloved, MChannelPreloved, MChat, MChatPreloved, MConsoleAudit, MCustomer, MCustomerSite, MDocumentManagement, MEMBER_TYPES, MEntryPassSettings, MEventManagement, MFeedback, MFile, MFormEntry, MGuestManagement, MHidAmicoEvent, MHidAmicoIdentity, MHidAmicoReader, MHidSipAccount, MHidSitePermissions, MIN_RING_SECONDS, MIncidentReport, MManpowerDesignations, MManpowerMonitoring, MManpowerRemarks, MManpowerSites, MMember, MNfcPatrolLog, MNfcPatrolRoute, MNfcPatrolSettings, MNfcPatrolSettingsUpdate, MNfcPatrolTag, MNotification, MNotificationPreference, MODULE_GATE_MODE_DEFAULT, MODULE_LIST_GATE_DEFAULT, MOccurrenceBook, MOccurrenceEntry, MOccurrenceSubject, MOnlineForm, MOrg, MOvernightParkingApprovalHours, MOvernightParkingRequest, MPatrolEmail, MPatrolLog, MPatrolQuestion, MPatrolRoute, MPerson, MPersonalEmergencyChain, MPlatformTerms, MPost, MPostFavorite, MPromoCode, MRobot, MRole, MRoleV2, MServiceProvider, MServiceProviderBilling, MSession, MSite, MSiteCamera, MSiteFacility, MSiteFacilityBooking, MStatementOfAccount, MSubcategoryPreloved, MSubscription, MSubscriptionPlan, MUnitBilling, MUser, MVehicle, MVehicleTransaction, MVerification, MVerificationV2, MVisitorTransaction, MWorkOrder, NOTIFICATION_CATEGORIES, NOTIFICATION_CHANNELS, NOTIFICATION_CHANNEL_LABELS, NOTIFICATION_NAMESPACE, NOTIFY_ACCESS_FILTER_DEFAULT, NotificationAppSlug, NotificationCategory, NotificationChannel, NotificationModule, NotificationPreferenceView, NotificationService, ORG_MARKETPLACE_VENDOR_FIELD, OrgNature, OvernightParkingRequestSort, OvernightParkingRequestStatus, PATROL_CCTV_CAMERA_FILTER, PATROL_EMAIL_MAX_LOGS, PATROL_EMAIL_MAX_PER_HOUR, PATROL_EMAIL_MAX_RECIPIENTS, PERSON_TYPES, PLATFORM_STAFF_MEMBER_TYPE, PLATFORM_STAFF_ROLE_TYPE, PROPERTY_MANAGEMENT_MEMBER_TYPES, PStatus, PTZ_ALLOWED_ACTIONS, PTZ_ALLOWED_CODES, Period, PersonStatus, PersonType, PersonTypes, PlatformTermsStatus, PostOrder, PostSort, PostStatus, QrTagProps, REALTIME_MAX_FANOUT, ResidentAppModuleKey, SELF_SERVICE_RESEND_COOLDOWN_MS, SELF_SIGNUP_PLATFORM, SELF_SIGNUP_STATUS, SELF_SIGNUP_TYPES, SERVICE_PROVIDER_INVITE_LABELS, SERVICE_PROVIDER_INVITE_TRANSITIONS, SERVICE_PROVIDER_SIGN_IN_SUBJECT, SERVICE_PROVIDER_SIGN_IN_TYPE, SERVICE_PROVIDER_SIGN_UP_SUBJECT, SERVICE_PROVIDER_SIGN_UP_TYPE, SOFTWARE_VERSION_ENDPOINT, ServiceProviderInviteAction, ServiceProviderInviteDecision, ServiceProviderInviteFacts, SiteAddress, SiteCategories, SiteStatus, SortFields, SortOrder, Status, SubjectOrder, SubjectSort, SubscriptionBillingMode, SubscriptionType, TAccessMngmntSettings, TActionStatus, TAddress, TAffectedEntities, TAffectedInjured, TAppServiceType, TApprovedBy, TApprover, TAttendance, TAttendanceCheckIn, TAttendanceCheckOut, TAttendanceCheckTime, TAttendanceLocation, TAttendanceSettings, TAttendanceSettingsGetBySite, TAuthorities, TAuthoritiesCalled, TBidPreloved, TBilling, TBillingConfiguration, TBillingItem, TBuilding, TBuildingLevel, TBuildingUnit, TBulletinBoard, TBulletinVideo, TCamera, TCameraHealthClaim, TCategoryPreloved, TChannelPreloved, TChat, TChatPreloved, TCheckPoint$1 as TCheckPoint, TComplaintInfo, TComplaintReceivedTo, TConsoleAudit, TConsoleAuditQuery, TCounter, TCreateNfcPatrolLog, TCustomer, TCustomerSite, TCustomerSitePropertyField, TDayNumber, TDaySchedule, TDefaultAccessCard, TDesignations, TDocs, TDocumentCreate, TDocumentManagement, TEntryPassSettings, TEventManagement, TFeedback, TFeedbackMetadata, TFeedbackUpdate, TFeedbackUpdateCategory, TFeedbackUpdateServiceProvider, TFeedbackUpdateStatus, TFeedbackUpdateToCompleted, TFile, TFiles, TFolderUpdate, TFormEntry, TGetAttendancesByUserQuery, TGetAttendancesQuery, TGuestManagement, THidAmicoEvent, THidAmicoGatewayJob, THidAmicoIdentity, THidAmicoPhysicalCard, THidAmicoReader, THidPermissionAssignment, THidPermissionCategory, THidPermissionUserBinding, THidPhysicalCardInput, THidPhysicalCardType$1 as THidPhysicalCardType, THidSipAccount, THidSitePermissions, TIncidentInformation, TIncidentReport, TIncidentTypeAndTime, TInvoice, TKeyRef, TManpowerDesignations, TManpowerDesignationsUpdate, TManpowerMonitoring, TManpowerMonitoringUpdate, TManpowerRemarks, TManpowerRemarksStatusUpdate, TManpowerRemarksUpdate, TManpowerSearchFilter, TManpowerSites, TMember, TMemberModulesDeps, TMemberUpdateStatus, TMessagePreloved, TMiniRole, TModuleAccess, TModuleGateMode, TModuleImpact, TNfcPatrolLog, TNfcPatrolRoute, TNfcPatrolRouteEdit, TNfcPatrolSettings, TNfcPatrolSettingsGetBySite, TNfcPatrolSettingsUpdate, TNfcPatrolTag, TNfcPatrolTagConfigureReset, TNfcPatrolTagEdit, TNfcPatrolTagUpdateData, TNotification, TNotificationPreference, TNotificationPreferenceOff, TNotifyAccessContext, TNotifyAccessMode, TNotifyAccessReport, TOccurrenceBook, TOccurrenceEntry, TOccurrenceSubject, TOnlineForm, TOrg, TOrgModulesDeps, TOvernightParkingApprovalHours, TOvernightParkingRequest, TPatrolEmail, TPatrolEmailCreatedBy, TPatrolEmailLogRef, TPatrolLog, TPatrolQuestion, TPatrolRoute, TPerson, TPersonalEmergencyChain, TPersonalEmergencyContact, TPlaceOfIncident, TPlates, TPlatformTerms, TPost, TPostFavorite, TPrice, TPriceType, TPromoCode, TPromoCurrencyInput, TPromoTier, TRANSPORT_DEVICE_HTTP, TRANSPORT_RELAY_PLAYER, TRANSPORT_RTSP_FRAME, TRecipientOfComplaint, TRemarks, TResident, TResidentAppModules, TRobot, TRobotMetadata, TRole, TRolePermissionHistoryEntry, TRoleV2, TRoute, TSOABillingItem, TSOAStatus, TSelfServiceEmailOccasion, TSelfServiceEmailRecord, TSelfServiceResendDecision, TSelfServiceResendFacts, TServiceProvider, TServiceProviderBilling, TSession, TSessionCreate, TShifts, TSignNfcPatrolLog, TSite, TSiteCamera, TSiteDayBounds, TSiteFacility, TSiteFacilityBooking, TSiteInfo, TSiteInformation, TSiteMetadata, TSiteModulesDeps, TSiteUpdateBlock, TStatementOfAccount, TSubcategoryPreloved, TSubmissionForm, TSubscription, TSubscriptionPlan, TSubscriptionPlanApplication, TUnitBilling, TUnits, TUpdateFormEntry, TUpdateName, TUser, TUserCreate, TVehicle, TVehicleTransaction, TVehicleUpdate, TVerification, TVerificationCode, TVerificationEvent, TVerificationMetadata, TVerificationMetadataV2, TVerificationOnboarding, TVerificationV2, TVisitorTransaction, TWorkOrder, TWorkOrderMetadata, TWorkOrderUpdate, TWorkOrderUpdateStatus, TWorkOrderUpdateToCompleted, TanyoneDamageToProperty, UNSTORED_COLUMNS, UseAccessManagementRepo, UserStatus, VERIFICATION_OPEN_STATUSES, VehicleCategory, VehicleOrder, VehicleSort, VehicleStatus, VehicleType, VerificationLinkType, VerificationStatus, VerificationSubjectType, VerificationType, VisitorSort, VisitorStatus, addressSchema, allowedFieldsSite, allowedNatures, allowedPlanApplications, attendanceSchema, attendanceSettingsSchema, buildSelfServiceEmailContext, building_level_namespace_collection, building_units_namespace_collection, buildings_namespace_collection, bulletin_boards_namespace_collection, callerAccountApproved, callerId, cameraBaseUrl, cameraCapabilitiesFor, cameraDevices, cameraGrant, cameraHealthClaim, cameraHealthSummary, cameraManagePermissions, cameraProbeCacheKey, cameraTransports, canRevokeRefreshTokenFamily, categoriesForPermissions, categorySupportsChannel, chatPrelovedEvents, chatSchema, clampPtzSpeed, clockDriftSeconds, consoleRoleAllows, consoleRoleAllowsAll, consoleSpellings, console_audit_namespace_collection, createManpowerRemarksDaily, customerSchema, customerSitePropertyFields, decideSelfServiceResend, decideServiceProviderInvite, decodeHidPacsCard, deniedModules, deriveBulletinStatus, deriveCameraHost, describeCameraCapabilities, designationsSchema, deviceControlEnabled, deviceHttpEnabled, deviceHttpTargets, deviceHttpTimeoutMs, deviceProbeTtlSeconds, emitNotificationCreated, emptyPersonalEmergencyChain, encodeHidPacsCard, entitledSiteScope, events_namespace_collection, expandModules, expiredBulletinSweepFilter, expiredVehicleSweepFilter, facility_bookings_namespace_collection, feedbackSchema, feedbacks2_namespace_collection, feedbacks_namespace_collection, ffmpegFrameArgs, ffmpegPath, filterByAccess, formatCapabilityTrace, formatDahuaDate, getIO, getSessionIdFromRequest, grabWithSubStreamFallback, guests_namespace_collection, hasAnyCapability, hasAnyPermission, hasOrgInvitation, hasOrgOwnership, hasOrgSiteReach, hidRawUint64, holdsRole, incidentReport, incidentReportLog, incidents_namespace_collection, invitationOffersRole, isCameraEntitled, isDuplicateVersionError, isLikelySelfServiceEmail, isPatrolCctvCamera, isPlatformOwner, isPromoCodeExpired, isRelayPlayerUrl, isSafeRelativePath, isSuperAdmin, isTermsCurrent, isValidTimezone, logCamera, manpowerDesignationsSchema, manpowerEvents, manpowerMonitoringSchema, manpowerRemarksSchema, manpowerSitesSchema, mapWithLimit, maskNric, memberModulesHandlers, moduleDeniedForCaller, moduleGateEnforceKeys, moduleGateMode, moduleImpact, moduleListGateOn, nfcPatrolSettingsSchema, nfcPatrolSettingsSchemaUpdate, normalizeAcceptedTerms, normalizeHidCardValue, notificationAccessReport, notificationCategory, notificationCategoryLabel, notificationEvents, notificationRoom, notifyAccessMode, occasionForStatus, occurrence_book_namespace_collection, online_forms_namespace_collection, orgLevelRoles, orgModulesHandlers, orgSchema, overnight_parking_requests_namespace_collection, parseCameraChannel, parseCameraHost, parseDahuaFind, parseDeviceTime, parseHidJsonLossless, parsePromoExpiry, parseSoftwareVersion, pickAuditFields, pickCustomerSiteProperties, planBulkCameraImport, platform_terms_namespace_collection, promoCodeRefusal, promoCodeSchema, promoCodeStatusSchema, promoCodeUpdate, promoCodeUpdateSchema, ptzEndpoint, publicCameraFields, readsAsApprovedAccount, recordConsoleAction, refuseServiceProviderInviteAction, registerCameraTransport, relayForRecorder, remarksSchema, renderPagePdf, requireConsolePermission, requirePlatformStaff, resetCameraTransports, residentAppModuleKeys, residentAppModulesSchema, residentFormEntry, resolutionRefusalReason, resolveCamera, resolveDeviceHttp, resolveHidPhysicalCardValue, resolveInviteActor, resolveSiteTimezone, resolveStaffRole, robotSchema, rtspUrl, schema, schemaAppSlugNotification, schemaApprovedBy, schemaApprover, schemaBidPreloved, schemaBilling, schemaBillingConfiguration, schemaBillingItem, schemaBuilding, schemaBuildingLevel, schemaBuildingUnit, schemaBuildingUpdateOptions, schemaBulletinBoard, schemaBulletinVideo, schemaCategoryPreloved, schemaChannelPreloved, schemaChatPreloved, schemaConsoleAudit, schemaCreateHidAmicoIdentity, schemaCreateNfcPatrolLog, schemaCreateNotification, schemaCustomerSite, schemaDiscoverHidAmicoReader, schemaDocumentManagement, schemaEntryPassSettings, schemaEventManagement, schemaFiles, schemaFormEntry, schemaGuestManagement, schemaHidAmicoAccessLogQuery, schemaHidAmicoAssignUserCard, schemaHidAmicoConfiguration, schemaHidAmicoEnrollUserCard, schemaHidAmicoEvent, schemaHidAmicoExecuteActions, schemaHidAmicoIdentity, schemaHidAmicoIdentityIdParams, schemaHidAmicoIdentityQuery, schemaHidAmicoIntercomCall, schemaHidAmicoLogQuery, schemaHidAmicoMonitor, schemaHidAmicoNotificationParams, schemaHidAmicoObjectOperation, schemaHidAmicoOperatingMode, schemaHidAmicoReader, schemaHidAmicoReaderIdParams, schemaHidAmicoReaderListQuery, schemaHidAmicoReaderUserQuery, schemaHidAmicoSetConfiguration, schemaHidAmicoSiteIdParams, schemaHidAmicoSync, schemaHidAmicoUserCardIdParams, schemaHidAmicoUserCardParams, schemaHidAmicoUserImageParams, schemaHidAmicoUserImageUploadQuery, schemaHidAmicoUserPin, schemaHidAmicoUserPinParams, schemaHidAmicoVisitorImageParams, schemaHidAmicoVisitorImageUploadQuery, schemaHidAmicoVisitorQr, schemaHidPermissionCandidateQuery, schemaHidPermissionScopeQuery, schemaHidSipAccountRequest, schemaIncidentReport, schemaListNotification, schemaMultipleDocumentManagement, schemaNfcPatrolLog, schemaNfcPatrolRoute, schemaNfcPatrolTag, schemaNfcPatrolTagUpdateData, schemaNotification, schemaNotificationPreference, schemaNotificationPreferenceOff, schemaOccurrenceBook, schemaOccurrenceEntry, schemaOccurrenceSubject, schemaOnlineForm, schemaOvernightParkingApprovalHours, schemaOvernightParkingRequest, schemaPatrolEmail, schemaPatrolEmailCreatedBy, schemaPatrolEmailLogRef, schemaPatrolEmailQuery, schemaPatrolLog, schemaPatrolQuestion, schemaPatrolRoute, schemaPerson, schemaPersonalEmergencyContact, schemaPlate, schemaPlatformTerms, schemaPost, schemaPostFavorite, schemaResendPatrolEmail, schemaResidentSelfSignUp, schemaSelfServiceVisitor, schemaSendPatrolEmail, schemaServiceProvider, schemaServiceProviderBilling, schemaSignNfcPatrolLog, schemaSiteCamera, schemaSiteFacility, schemaSiteFacilityBooking, schemaStatementOfAccount, schemaSubcategoryPreloved, schemaUnitBilling, schemaUpdateBidPreloved, schemaUpdateBuildingLevel, schemaUpdateBulletinBoard, schemaUpdateBulletinVideo, schemaUpdateCategoryPreloved, schemaUpdateChatPreloved, schemaUpdateDocumentManagement, schemaUpdateEntryPassSettings, schemaUpdateEventManagement, schemaUpdateFolderManagement, schemaUpdateFormEntry, schemaUpdateGuestManagement, schemaUpdateHidAmicoIdentity, schemaUpdateHidAmicoReader, schemaUpdateHidSitePermissions, schemaUpdateIncidentReport, schemaUpdateNotification, schemaUpdateNotificationPreference, schemaUpdateOccurrenceBook, schemaUpdateOccurrenceEntry, schemaUpdateOccurrenceSubject, schemaUpdateOnlineForm, schemaUpdateOptions, schemaUpdateOvernightParkingRequest, schemaUpdatePatrolLog, schemaUpdatePatrolQuestion, schemaUpdatePatrolRoute, schemaUpdatePerson, schemaUpdatePersonalEmergencyChain, schemaUpdatePost, schemaUpdatePostFavorite, schemaUpdateServiceProviderBilling, schemaUpdateSiteBillingConfiguration, schemaUpdateSiteBillingItem, schemaUpdateSiteCamera, schemaUpdateSiteFacility, schemaUpdateSiteFacilityBooking, schemaUpdateSiteUnitBilling, schemaUpdateStatementOfAccount, schemaUpdateSubcategoryPreloved, schemaUpdateVisTrans, schemaVehicleTransaction, schemaVisitorTransaction, schemeCamera, schemeLogCamera, selectHealthTargets, selfServiceEmailSubject, serviceProviderInviteLabel, sessionSchema, setIO, shiftSchema, siteDayBounds, siteModulesHandlers, siteSchema, site_people_namespace_collection, snapshotEndpoint, snapshotRefusalReason, staffMayBypass, stringifyHidJson, stripFacialImageMetadata, subscriptionPlanSchema, summariseBulkCameraPlan, updateRemarksStatusEod, updateRemarksisAcknowledged, updateSiteSchema, useAccessManagementController, useAddressRepo, useAttendanceController, useAttendanceRepository, useAttendanceSettingsController, useAttendanceSettingsRepository, useAttendanceSettingsService, useAuthController, useAuthControllerV2, useAuthService, useAuthServiceV2, useBidPrelovedController, useBidPrelovedRepo, useBidPrelovedService, useBuildingController, useBuildingLevelController, useBuildingLevelRepo, useBuildingLevelService, useBuildingRepo, useBuildingService, useBuildingUnitController, useBuildingUnitRepo, useBuildingUnitService, useBulletinBoardController, useBulletinBoardRepo, useBulletinBoardService, useBulletinVideoController, useBulletinVideoRepo, useBulletinVideoService, useCameraViewController, useCameraViewService, useCategoryPrelovedController, useCategoryPrelovedRepo, useChannelPrelovedController, useChannelPrelovedRepo, useChatController, useChatPrelovedController, useChatPrelovedRepo, useChatPrelovedService, useChatRepo, useConsoleAuditController, useConsoleAuditRepo, useCounterModel, useCounterRepo, useCustomerController, useCustomerRepo, useCustomerSiteController, useCustomerSiteRepo, useCustomerSiteService, useDahuaService, useDashboardController, useDashboardRepo, useDocumentManagementController, useDocumentManagementRepo, useDocumentManagementService, useEntryPassSettingsController, useEntryPassSettingsRepo, useEventManagementController, useEventManagementRepo, useEventManagementService, useFeedbackController, useFeedbackRepo, useFeedbackService, useFileController, useFileRepo, useFileService, useFormEntryController, useFormEntryRepo, useGuestManagementController, useGuestManagementRepo, useGuestManagementService, useHidAmicoController, useHidAmicoRepo, useHidAmicoService, useHrmLabsAttendanceCtrl, useHrmLabsAttendanceSrvc, useIncidentReportController, useIncidentReportRepo, useIncidentReportService, useInvoiceController, useInvoiceModel, useInvoiceRepo, useManpowerDesignationCtrl, useManpowerDesignationRepo, useManpowerMonitoringCtrl, useManpowerMonitoringRepo, useManpowerMonitoringSrvc, useManpowerRemarkCtrl, useManpowerRemarksRepo, useManpowerSitesCtrl, useManpowerSitesRepo, useManpowerSitesSrvc, useMemberController, useMemberRepo, useMemberService, useNewDashboardController, useNewDashboardRepo, useNfcPatrolLogController, useNfcPatrolLogRepo, useNfcPatrolLogService, useNfcPatrolRouteController, useNfcPatrolRouteRepo, useNfcPatrolRouteService, useNfcPatrolSettingsController, useNfcPatrolSettingsRepository, useNfcPatrolSettingsService, useNfcPatrolTagController, useNfcPatrolTagRepo, useNfcPatrolTagService, useNotificationController, useNotificationPreferenceController, useNotificationPreferenceRepo, useNotificationPreferenceService, useNotificationRepo, useOccurrenceBookController, useOccurrenceBookRepo, useOccurrenceBookService, useOccurrenceEntryController, useOccurrenceEntryRepo, useOccurrenceEntryService, useOccurrenceSubjectController, useOccurrenceSubjectRepo, useOccurrenceSubjectService, useOnlineFormController, useOnlineFormRepo, useOrgController, useOrgControllerV2, useOrgRepo, useOvernightParkingController, useOvernightParkingRepo, useOvernightParkingRequestController, useOvernightParkingRequestRepo, useOvernightParkingRequestService, usePatrolEmailController, usePatrolEmailRepo, usePatrolEmailService, usePatrolLogController, usePatrolLogRepo, usePatrolLogService, usePatrolQuestionController, usePatrolQuestionRepo, usePatrolRouteController, usePatrolRouteRepo, usePersonController, usePersonRepo, usePersonalEmergencyChainController, usePersonalEmergencyChainRepo, usePersonalEmergencyChainService, usePlatformTermsController, usePlatformTermsRepo, usePlatformTermsService, usePostFavoriteController, usePostFavoriteRepo, usePostFavoriteService, usePostPrelovedController, usePostPrelovedRepo, usePriceController, usePriceModel, usePriceRepo, usePromoCodeController, usePromoCodeRepo, useRedDotPaymentController, useRedDotPaymentRepo, useRedDotPaymentSvc, useRobotController, useRobotRepo, useRobotService, useRoleController, useRoleControllerV2, useRoleRepo, useRoleRepoV2, useRoleServiceV2, useServiceProviderBillingController, useServiceProviderBillingRepo, useServiceProviderBillingService, useServiceProviderController, useServiceProviderInviteController, useServiceProviderInviteService, useServiceProviderRepo, useSessionRepo, useSiteBillingConfigurationController, useSiteBillingConfigurationRepo, useSiteBillingItemController, useSiteBillingItemRepo, useSiteCameraController, useSiteCameraRepo, useSiteCameraService, useSiteController, useSiteFacilityBookingController, useSiteFacilityBookingRepo, useSiteFacilityBookingService, useSiteFacilityController, useSiteFacilityRepo, useSiteFacilityService, useSiteRepo, useSiteService, useSiteUnitBillingController, useSiteUnitBillingRepo, useSiteUnitBillingService, useStatementOfAccountController, useStatementOfAccountRepo, useSubcategoryPrelovedController, useSubcategoryPrelovedRepo, useSubscriptionController, useSubscriptionPlanController, useSubscriptionPlanRepo, useSubscriptionRepo, useSubscriptionService, useUserController, useUserControllerV2, useUserRepo, useUserRepoV2, useUserService, useUserServiceV2, useVehicleController, useVehicleRepo, useVehicleService, useVerificationController, useVerificationControllerV2, useVerificationRepo, useVerificationRepoV2, useVerificationService, useVerificationServiceV2, useVisitorTransactionController, useVisitorTransactionRepo, useVisitorTransactionService, useWorkOrderController, useWorkOrderRepo, useWorkOrderService, userSchema, vehicleSchema, vehicles_namespace_collection, visitorPersonRepo, visitorPersonService, visitorType, visitors_namespace_collection, wallConfig, workOrderSchema, work_orders2_namespace_collection, work_orders_namespace_collection };
|