@astram/guard 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/auth.module.d.ts +7 -0
- package/dist/auth/auth.module.d.ts.map +1 -1
- package/dist/auth/auth.module.js +43 -1
- package/dist/auth/tokens.d.ts +13 -0
- package/dist/auth/tokens.d.ts.map +1 -1
- package/dist/auth/tokens.js +14 -1
- package/dist/completeness/catalog-reconciler.d.ts +16 -1
- package/dist/completeness/catalog-reconciler.d.ts.map +1 -1
- package/dist/completeness/catalog-reconciler.js +70 -6
- package/dist/completeness/ports/catalog-store.d.ts +38 -3
- package/dist/completeness/ports/catalog-store.d.ts.map +1 -1
- package/dist/config/notification-config.d.ts +20 -0
- package/dist/config/notification-config.d.ts.map +1 -0
- package/dist/config/notification-config.js +33 -0
- package/dist/identity/module-registry.bridge.d.ts +9 -1
- package/dist/identity/module-registry.bridge.d.ts.map +1 -1
- package/dist/identity/module-registry.bridge.js +19 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -37
- package/dist/module/shield.module.d.ts +12 -0
- package/dist/module/shield.module.d.ts.map +1 -1
- package/dist/module/shield.module.js +11 -0
- package/dist/notifications/mariadb-notification-store.d.ts +38 -0
- package/dist/notifications/mariadb-notification-store.d.ts.map +1 -0
- package/dist/notifications/mariadb-notification-store.js +151 -0
- package/dist/notifications/notification-retention.job.d.ts +52 -0
- package/dist/notifications/notification-retention.job.d.ts.map +1 -0
- package/dist/notifications/notification-retention.job.js +97 -0
- package/dist/notifications/notification.service.d.ts +68 -0
- package/dist/notifications/notification.service.d.ts.map +1 -0
- package/dist/notifications/notification.service.js +247 -0
- package/dist/notifications/notifications.controller.d.ts +57 -0
- package/dist/notifications/notifications.controller.d.ts.map +1 -0
- package/dist/notifications/notifications.controller.js +257 -0
- package/dist/notifications/ports.d.ts +112 -0
- package/dist/notifications/ports.d.ts.map +1 -0
- package/dist/notifications/ports.js +63 -0
- package/migrations/1710000000107-AddPermissionTextAndFirstSeen.cjs +43 -0
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
* `@nestjs/core`, `reflect-metadata`, `rxjs` so the host owns one copy of each.
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.
|
|
20
|
-
exports.
|
|
21
|
-
exports.
|
|
22
|
-
exports.
|
|
23
|
-
exports.ScopeUnknownParentError = exports.ScopeDepthError = exports.ScopeCycleError = exports.buildClosureRows = exports.ConfirmEmailController = exports.AccountController = exports.generateRecoveryCodes = exports.buildOtpauthUri = exports.generateTotpSecret = exports.SHIELD_LOGIN_TOTP_VERIFIER = exports.SHIELD_MFA_STEP_UP = exports.SHIELD_MFA_LIMITER = exports.challengeMatches = exports.credentialFingerprint = exports.CredentialMfaStepUp = exports.RedisPendingMfaStore = exports.PendingMfaStore = exports.AuthController = exports.SHIELD_SCOPE_SUBTREE_RESOLVER = void 0;
|
|
19
|
+
exports.assertNoUnresolvedSecretRefs = exports.createSecretsProviderFromEnv = exports.resolveBootSecrets = exports.EncryptedFileSecretsProvider = exports.LocalKekCrypto = exports.resolveAuthLinkBaseUrls = exports.CredentialExistsError = exports.isLockedHash = exports.lockedPasswordHash = exports.SHIELD_PASSWORD_HASHER = exports.argon2idHasherProvider = exports.Argon2idPasswordHasher = exports.stubDecisionAuthority = exports.GlobalEnforcementGuard = exports.NO_SESSION_FACTS = exports.SHIELD_SESSION_FACTS_ALS = exports.MariaDbApiKeyStore = exports.isApiKey = exports.extractBearerToken = exports.principalFromClaims = exports.resolveRequestAuth = exports.resolveRequestPrincipal = exports.SessionTokenBinder = exports.SHIELD_SERVICE_AUTHENTICATOR = exports.SHIELD_SESSION_TOKEN_BINDER = exports.CatalogGatabilityError = exports.CatalogReconciler = exports.OperationInventoryScanner = exports.uuidArrayField = exports.optionalUuidField = exports.uuidField = exports.UuidPipe = exports.normalizeClassification = exports.DEFAULT_CLASSIFIED_ACTION = exports.CLASSIFICATION_METADATA = exports.Classified = exports.Public = exports.SHIELD_RECORD_AUTHORIZATION = exports.SHIELD_DECISION_AUTHORITY = exports.ShieldModule = exports.actionsOf = exports.actionsFor = exports.SERVICE_ACCOUNT_ACTIONS = exports.RECORD_SHARE_ACTIONS = exports.CROSS_TENANT_GRANT_ACTIONS = exports.IDENTITY_ACTIONS = exports.MODULE_KEY = exports.permissionTextByKey = exports.buildIdentityModuleRegistry = exports.guardMigrationsDir = void 0;
|
|
20
|
+
exports.SHIELD_RECORD_SHARE_WRITER = exports.RecordShareWriter = exports.SHIELD_RECORD_SHARE_PORT = exports.MariaDbRecordShareAdapter = exports.UnknownScopeFieldError = exports.translateListScope = exports.SHIELD_LIST_SCOPE_PORT = exports.MariaDbListScopeAdapter = exports.SHIELD_POLICY_STORE = exports.MariaDbPolicyStore = exports.SHIELD_RECORD_RULE_PORT = exports.MariaDbRecordPermissionRuleAdapter = exports.accessBindingTtlMs = exports.ROTATE_GRACE_MS = exports.SHIELD_SESSION_LIFETIMES = exports.HotRevokingSessionRecordStore = exports.SHIELD_CLOCK = exports.SHIELD_REFRESH_HASHER = exports.SHIELD_TOKEN_GENERATOR = exports.systemClockProvider = exports.refreshHasherProvider = exports.cryptoTokenGeneratorProvider = exports.SystemClock = exports.Sha256RefreshTokenHasher = exports.CryptoTokenGenerator = exports.RedisRecentRotationStore = exports.SHIELD_HOT_SESSION_STORE = exports.RedisHotSessionStore = exports.SHIELD_SESSION_RECORD_STORE = exports.MariaDbSessionRecordStore = exports.DEFAULT_OBJECT_STORAGE_MAX_BYTES = exports.loadObjectStorageConfig = exports.SHIELD_FILE_INGEST = exports.SHIELD_OBJECT_STORE = exports.FILE_INTAKE_DEFAULT_MAX_BYTES = exports.FILE_INTAKE_REQUEST_KEY = exports.FileIntake = exports.ObjectStoreBootCheck = exports.SHIELD_NOTIFICATIONS = exports.loadNotificationConfig = exports.NotificationUnavailableError = exports.NotificationValidationError = exports.NotificationKindError = exports.NOTIFICATION_CATEGORIES = exports.NotificationService = exports.loadAuditSealConfig = exports.NodeSha256Hash = exports.NodeSha256Digest = exports.S3ObjectStore = exports.wasResolvedFromSecretRef = void 0;
|
|
21
|
+
exports.isDevOrTestNodeEnv = exports.DEFAULT_LOGIN_IP_LIMIT = exports.loadRefreshReplayWindowMs = exports.loadLoginIpLimit = exports.DEFAULT_REDIS_URL = exports.DEFAULT_DB_CONFIG = exports.assertRefreshHmacKey = exports.loadRefreshHmacKey = exports.loadSessionLifetimes = exports.loadRedisConfig = exports.loadDbConfig = exports.SCHEMA_SVC_POOL_HARD_CAP = exports.DEFAULT_POOL_BUDGET = exports.evaluatePoolBudget = exports.loadPoolBudget = exports.loadAppConfig = exports.frameworkSchemasOf = exports.FRAMEWORK_SCHEMAS = exports.APP_CONFIG = exports.resolveMigrationLedgerCheck = exports.resolveMigrationLedger = exports.frameworkMigrationIds = exports.assertFrameworkMigrationsApplied = exports.SHIELD_MIGRATION_LEDGER_REGISTRY = exports.MigrationLedgerRegistry = exports.FrameworkMigrationLedgerCheck = exports.frameworkDatabasesLogLine = exports.assertPoolBudget = exports.BootSequence = exports.buildListScopeFn = exports.MariaDbSessionRestrictionStore = exports.SHIELD_SESSION_RESTRICTIONS = exports.SHIELD_PERMISSION_VERSION_CACHE = exports.DEFAULT_PERMISSION_VERSION_TTL_MS = exports.PERMISSION_VERSION_KEY_PREFIX = exports.RedisPermissionVersionCache = exports.withRedisPermissionVersion = exports.buildRecordAuthorization = exports.SHIELD_OPERATION_AUTHORITY_PORT = exports.ManifestOperationAuthorityAdapter = exports.GrantStoreUnavailableError = exports.InvalidGrantError = exports.GrantNotPermittedError = exports.SHIELD_CROSS_TENANT_GRANT_WRITER = exports.CrossTenantGrantWriter = exports.SHIELD_CROSS_TENANT_GRANT_PORT = exports.MariaDbCrossTenantGrantAdapter = exports.makeShareDeleteCascade = exports.ShareStoreUnavailableError = exports.ShareNotPermittedError = void 0;
|
|
22
|
+
exports.maskEmail = exports.isEmailShaped = exports.canonicalEmail = exports.hmacSha1 = exports.resolveTotpVerifier = exports.makeDefaultTotpVerifier = exports.AuthModule = exports.SHIELD_CAPTCHA_GATE = exports.RECAPTCHA_SITEVERIFY_URL = exports.RecaptchaVerifier = exports.TURNSTILE_SITEVERIFY_URL = exports.TurnstileVerifier = exports.MAX_CAPTCHA_TIMEOUT_MS = exports.DEFAULT_CAPTCHA_TIMEOUT_MS = exports.DEFAULT_CAPTCHA_MIN_SCORE = exports.DEFAULT_CAPTCHA_THRESHOLD = exports.CAPTCHA_FAIL_MODES = exports.CAPTCHA_MODES = exports.CAPTCHA_ENDPOINTS = exports.loadCaptchaConfig = exports.SHIELD_SIGN_IN_WITH = exports.DEFAULT_SIGN_IN_WITH = exports.resolveSignInWith = exports.MariaDbCredentialResolver = exports.SHIELD_TOTP_VERIFIER_OVERRIDE = exports.SHIELD_MFA_DEVICE_STORE = exports.SHIELD_AUDIT_SINK = exports.SHIELD_SESSION_SWEEPER = exports.SHIELD_PROFILE_WRITER = exports.SHIELD_RECOVERY_CODE_STORE = exports.SHIELD_MESSAGE_DISPATCHER = exports.SHIELD_EMAIL_SENDER = exports.SHIELD_EMAIL_CHANGE_TOKEN_STORE = exports.SHIELD_RESET_TOKEN_STORE = exports.SHIELD_CREDENTIAL_WRITER = exports.SHIELD_SESSION_AUTHORITY = exports.SHIELD_AUTHENTICATOR = exports.SHIELD_PROFILE_RESOLVER = exports.SHIELD_CREDENTIAL_RESOLVER = exports.SHIELD_REDIS = exports.withoutStatementTimeout = exports.mariadbPoolTuningOptions = exports.mariadbSslOption = exports.reservedOperationPrincipal = exports.RESERVED_OPERATION_PRINCIPALS = exports.assertNoReservedRootId = exports.ORG_BOOTSTRAP_PRINCIPAL_ID = exports.rootIdsFromEnv = exports.loadPoolTuning = exports.loadDbTlsConfig = void 0;
|
|
23
|
+
exports.ScopeUnknownParentError = exports.ScopeDepthError = exports.ScopeCycleError = exports.buildClosureRows = exports.ConfirmEmailController = exports.AccountController = exports.generateRecoveryCodes = exports.buildOtpauthUri = exports.generateTotpSecret = exports.SHIELD_LOGIN_TOTP_VERIFIER = exports.SHIELD_MFA_STEP_UP = exports.SHIELD_MFA_LIMITER = exports.challengeMatches = exports.credentialFingerprint = exports.CredentialMfaStepUp = exports.RedisPendingMfaStore = exports.PendingMfaStore = exports.AuthController = exports.SHIELD_SCOPE_SUBTREE_RESOLVER = exports.SHIELD_SESSION_FACTS_PROJECTOR = exports.ProfileNameTakenError = exports.maskPhone = exports.MAX_MESSAGE_SEND_TIMEOUT_MS = exports.DEFAULT_MESSAGE_SEND_TIMEOUT_MS = exports.EMAIL_PROVIDER_VALUES = exports.loadMessageConfig = exports.MariaDbEmailAddressChanger = void 0;
|
|
24
24
|
// Framework authz migrations (shield_authz DDL — permission / role_permission /
|
|
25
25
|
// authz_permission_version). Absolute path a consumer's `@astram/migrate` setup merges in.
|
|
26
26
|
var migrations_dir_js_1 = require("./migrations-dir.js");
|
|
@@ -34,6 +34,7 @@ Object.defineProperty(exports, "guardMigrationsDir", { enumerable: true, get: fu
|
|
|
34
34
|
// runtime option values the consumer threads in.
|
|
35
35
|
var module_registry_bridge_js_1 = require("./identity/module-registry.bridge.js");
|
|
36
36
|
Object.defineProperty(exports, "buildIdentityModuleRegistry", { enumerable: true, get: function () { return module_registry_bridge_js_1.buildIdentityModuleRegistry; } });
|
|
37
|
+
Object.defineProperty(exports, "permissionTextByKey", { enumerable: true, get: function () { return module_registry_bridge_js_1.permissionTextByKey; } });
|
|
37
38
|
var identity_actions_js_1 = require("./identity/identity-actions.js");
|
|
38
39
|
Object.defineProperty(exports, "MODULE_KEY", { enumerable: true, get: function () { return identity_actions_js_1.MODULE_KEY; } });
|
|
39
40
|
Object.defineProperty(exports, "IDENTITY_ACTIONS", { enumerable: true, get: function () { return identity_actions_js_1.IDENTITY_ACTIONS; } });
|
|
@@ -160,6 +161,19 @@ var node_sha256_hash_js_1 = require("./audit/node-sha256-hash.js");
|
|
|
160
161
|
Object.defineProperty(exports, "NodeSha256Hash", { enumerable: true, get: function () { return node_sha256_hash_js_1.NodeSha256Hash; } });
|
|
161
162
|
var audit_seal_config_js_1 = require("./audit/audit-seal-config.js");
|
|
162
163
|
Object.defineProperty(exports, "loadAuditSealConfig", { enumerable: true, get: function () { return audit_seal_config_js_1.loadAuditSealConfig; } });
|
|
164
|
+
// Notification store (G-027 step 2, notification-store SPEC §5B, §5C, §5F): post notices under
|
|
165
|
+
// kinds registered in `ShieldModule.forRoot({ notificationKinds })`; bound with `auth: true`.
|
|
166
|
+
var notification_service_js_1 = require("./notifications/notification.service.js");
|
|
167
|
+
Object.defineProperty(exports, "NotificationService", { enumerable: true, get: function () { return notification_service_js_1.NotificationService; } });
|
|
168
|
+
var ports_js_1 = require("./notifications/ports.js");
|
|
169
|
+
Object.defineProperty(exports, "NOTIFICATION_CATEGORIES", { enumerable: true, get: function () { return ports_js_1.NOTIFICATION_CATEGORIES; } });
|
|
170
|
+
Object.defineProperty(exports, "NotificationKindError", { enumerable: true, get: function () { return ports_js_1.NotificationKindError; } });
|
|
171
|
+
Object.defineProperty(exports, "NotificationValidationError", { enumerable: true, get: function () { return ports_js_1.NotificationValidationError; } });
|
|
172
|
+
Object.defineProperty(exports, "NotificationUnavailableError", { enumerable: true, get: function () { return ports_js_1.NotificationUnavailableError; } });
|
|
173
|
+
var notification_config_js_1 = require("./config/notification-config.js");
|
|
174
|
+
Object.defineProperty(exports, "loadNotificationConfig", { enumerable: true, get: function () { return notification_config_js_1.loadNotificationConfig; } });
|
|
175
|
+
var tokens_js_2 = require("./auth/tokens.js");
|
|
176
|
+
Object.defineProperty(exports, "SHIELD_NOTIFICATIONS", { enumerable: true, get: function () { return tokens_js_2.SHIELD_NOTIFICATIONS; } });
|
|
163
177
|
var object_store_boot_check_js_1 = require("./storage/object-store-boot-check.js");
|
|
164
178
|
Object.defineProperty(exports, "ObjectStoreBootCheck", { enumerable: true, get: function () { return object_store_boot_check_js_1.ObjectStoreBootCheck; } });
|
|
165
179
|
var file_intake_interceptor_js_1 = require("./storage/file-intake.interceptor.js");
|
|
@@ -310,12 +324,12 @@ var permission_version_cache_js_1 = require("./authz/permission-version-cache.js
|
|
|
310
324
|
Object.defineProperty(exports, "RedisPermissionVersionCache", { enumerable: true, get: function () { return permission_version_cache_js_1.RedisPermissionVersionCache; } });
|
|
311
325
|
Object.defineProperty(exports, "PERMISSION_VERSION_KEY_PREFIX", { enumerable: true, get: function () { return permission_version_cache_js_1.PERMISSION_VERSION_KEY_PREFIX; } });
|
|
312
326
|
Object.defineProperty(exports, "DEFAULT_PERMISSION_VERSION_TTL_MS", { enumerable: true, get: function () { return permission_version_cache_js_1.DEFAULT_PERMISSION_VERSION_TTL_MS; } });
|
|
313
|
-
var
|
|
314
|
-
Object.defineProperty(exports, "SHIELD_PERMISSION_VERSION_CACHE", { enumerable: true, get: function () { return
|
|
327
|
+
var tokens_js_3 = require("./auth/tokens.js");
|
|
328
|
+
Object.defineProperty(exports, "SHIELD_PERMISSION_VERSION_CACHE", { enumerable: true, get: function () { return tokens_js_3.SHIELD_PERMISSION_VERSION_CACHE; } });
|
|
315
329
|
// Durable session restrictions (Phase 3B review P1): the recovery-login re-enroll marker on the
|
|
316
330
|
// durable session + the account status the refresh-time rebuild checks.
|
|
317
|
-
var
|
|
318
|
-
Object.defineProperty(exports, "SHIELD_SESSION_RESTRICTIONS", { enumerable: true, get: function () { return
|
|
331
|
+
var tokens_js_4 = require("./auth/tokens.js");
|
|
332
|
+
Object.defineProperty(exports, "SHIELD_SESSION_RESTRICTIONS", { enumerable: true, get: function () { return tokens_js_4.SHIELD_SESSION_RESTRICTIONS; } });
|
|
319
333
|
var session_restriction_store_js_1 = require("./session/session-restriction-store.js");
|
|
320
334
|
Object.defineProperty(exports, "MariaDbSessionRestrictionStore", { enumerable: true, get: function () { return session_restriction_store_js_1.MariaDbSessionRestrictionStore; } });
|
|
321
335
|
// The LIST-FORM sibling (Task 2.2): the engine-facing `ListScopeFn` the module wiring hands
|
|
@@ -408,38 +422,38 @@ Object.defineProperty(exports, "withoutStatementTimeout", { enumerable: true, ge
|
|
|
408
422
|
// Shared DI provider tokens (the seams the teams bind/consume — see tokens.ts for
|
|
409
423
|
// who provides/consumes each). The raw pool token `SHIELD_DB_POOL` is NOT here (Phase 8 #5):
|
|
410
424
|
// it is on `@astram/guard/internal`, with the `PersistenceModule` that provides it.
|
|
411
|
-
var
|
|
412
|
-
Object.defineProperty(exports, "SHIELD_REDIS", { enumerable: true, get: function () { return
|
|
413
|
-
Object.defineProperty(exports, "SHIELD_CREDENTIAL_RESOLVER", { enumerable: true, get: function () { return
|
|
414
|
-
Object.defineProperty(exports, "SHIELD_PROFILE_RESOLVER", { enumerable: true, get: function () { return
|
|
415
|
-
Object.defineProperty(exports, "SHIELD_AUTHENTICATOR", { enumerable: true, get: function () { return
|
|
416
|
-
Object.defineProperty(exports, "SHIELD_SESSION_AUTHORITY", { enumerable: true, get: function () { return
|
|
425
|
+
var tokens_js_5 = require("./auth/tokens.js");
|
|
426
|
+
Object.defineProperty(exports, "SHIELD_REDIS", { enumerable: true, get: function () { return tokens_js_5.SHIELD_REDIS; } });
|
|
427
|
+
Object.defineProperty(exports, "SHIELD_CREDENTIAL_RESOLVER", { enumerable: true, get: function () { return tokens_js_5.SHIELD_CREDENTIAL_RESOLVER; } });
|
|
428
|
+
Object.defineProperty(exports, "SHIELD_PROFILE_RESOLVER", { enumerable: true, get: function () { return tokens_js_5.SHIELD_PROFILE_RESOLVER; } });
|
|
429
|
+
Object.defineProperty(exports, "SHIELD_AUTHENTICATOR", { enumerable: true, get: function () { return tokens_js_5.SHIELD_AUTHENTICATOR; } });
|
|
430
|
+
Object.defineProperty(exports, "SHIELD_SESSION_AUTHORITY", { enumerable: true, get: function () { return tokens_js_5.SHIELD_SESSION_AUTHORITY; } });
|
|
417
431
|
// Account & credential-surface seams (forgot/reset, change-password, MFA
|
|
418
432
|
// enrollment, profile edit) — all OPTIONAL, consumer-plugged through
|
|
419
433
|
// ShieldModule.forRoot. See tokens.ts for who provides/consumes each.
|
|
420
|
-
Object.defineProperty(exports, "SHIELD_CREDENTIAL_WRITER", { enumerable: true, get: function () { return
|
|
421
|
-
Object.defineProperty(exports, "SHIELD_RESET_TOKEN_STORE", { enumerable: true, get: function () { return
|
|
434
|
+
Object.defineProperty(exports, "SHIELD_CREDENTIAL_WRITER", { enumerable: true, get: function () { return tokens_js_5.SHIELD_CREDENTIAL_WRITER; } });
|
|
435
|
+
Object.defineProperty(exports, "SHIELD_RESET_TOKEN_STORE", { enumerable: true, get: function () { return tokens_js_5.SHIELD_RESET_TOKEN_STORE; } });
|
|
422
436
|
// Phase 12 (KI #14): the self-service email-change token store (framework default).
|
|
423
|
-
Object.defineProperty(exports, "SHIELD_EMAIL_CHANGE_TOKEN_STORE", { enumerable: true, get: function () { return
|
|
424
|
-
Object.defineProperty(exports, "SHIELD_EMAIL_SENDER", { enumerable: true, get: function () { return
|
|
425
|
-
Object.defineProperty(exports, "SHIELD_MESSAGE_DISPATCHER", { enumerable: true, get: function () { return
|
|
426
|
-
Object.defineProperty(exports, "SHIELD_RECOVERY_CODE_STORE", { enumerable: true, get: function () { return
|
|
427
|
-
Object.defineProperty(exports, "SHIELD_PROFILE_WRITER", { enumerable: true, get: function () { return
|
|
428
|
-
Object.defineProperty(exports, "SHIELD_SESSION_SWEEPER", { enumerable: true, get: function () { return
|
|
437
|
+
Object.defineProperty(exports, "SHIELD_EMAIL_CHANGE_TOKEN_STORE", { enumerable: true, get: function () { return tokens_js_5.SHIELD_EMAIL_CHANGE_TOKEN_STORE; } });
|
|
438
|
+
Object.defineProperty(exports, "SHIELD_EMAIL_SENDER", { enumerable: true, get: function () { return tokens_js_5.SHIELD_EMAIL_SENDER; } });
|
|
439
|
+
Object.defineProperty(exports, "SHIELD_MESSAGE_DISPATCHER", { enumerable: true, get: function () { return tokens_js_5.SHIELD_MESSAGE_DISPATCHER; } });
|
|
440
|
+
Object.defineProperty(exports, "SHIELD_RECOVERY_CODE_STORE", { enumerable: true, get: function () { return tokens_js_5.SHIELD_RECOVERY_CODE_STORE; } });
|
|
441
|
+
Object.defineProperty(exports, "SHIELD_PROFILE_WRITER", { enumerable: true, get: function () { return tokens_js_5.SHIELD_PROFILE_WRITER; } });
|
|
442
|
+
Object.defineProperty(exports, "SHIELD_SESSION_SWEEPER", { enumerable: true, get: function () { return tokens_js_5.SHIELD_SESSION_SWEEPER; } });
|
|
429
443
|
// The auth-surface audit sink seam (the first auth audit event — recovery login).
|
|
430
|
-
Object.defineProperty(exports, "SHIELD_AUDIT_SINK", { enumerable: true, get: function () { return
|
|
444
|
+
Object.defineProperty(exports, "SHIELD_AUDIT_SINK", { enumerable: true, get: function () { return tokens_js_5.SHIELD_AUDIT_SINK; } });
|
|
431
445
|
// The multi-device MFA store seam (multiple independent authenticator devices).
|
|
432
|
-
Object.defineProperty(exports, "SHIELD_MFA_DEVICE_STORE", { enumerable: true, get: function () { return
|
|
446
|
+
Object.defineProperty(exports, "SHIELD_MFA_DEVICE_STORE", { enumerable: true, get: function () { return tokens_js_5.SHIELD_MFA_DEVICE_STORE; } });
|
|
433
447
|
// The login totp-verifier OVERRIDE seam (Phase 2 — plug an OR-matching verifier).
|
|
434
|
-
Object.defineProperty(exports, "SHIELD_TOTP_VERIFIER_OVERRIDE", { enumerable: true, get: function () { return
|
|
448
|
+
Object.defineProperty(exports, "SHIELD_TOTP_VERIFIER_OVERRIDE", { enumerable: true, get: function () { return tokens_js_5.SHIELD_TOTP_VERIFIER_OVERRIDE; } });
|
|
435
449
|
// The credential-store contract (skeleton — Team A implements the SELECT).
|
|
436
450
|
var mariadb_credential_resolver_js_1 = require("./authentication/mariadb-credential-resolver.js");
|
|
437
451
|
Object.defineProperty(exports, "MariaDbCredentialResolver", { enumerable: true, get: function () { return mariadb_credential_resolver_js_1.MariaDbCredentialResolver; } });
|
|
438
452
|
var sign_in_with_js_1 = require("./authentication/sign-in-with.js");
|
|
439
453
|
Object.defineProperty(exports, "resolveSignInWith", { enumerable: true, get: function () { return sign_in_with_js_1.resolveSignInWith; } });
|
|
440
454
|
Object.defineProperty(exports, "DEFAULT_SIGN_IN_WITH", { enumerable: true, get: function () { return sign_in_with_js_1.DEFAULT_SIGN_IN_WITH; } });
|
|
441
|
-
var
|
|
442
|
-
Object.defineProperty(exports, "SHIELD_SIGN_IN_WITH", { enumerable: true, get: function () { return
|
|
455
|
+
var tokens_js_6 = require("./auth/tokens.js");
|
|
456
|
+
Object.defineProperty(exports, "SHIELD_SIGN_IN_WITH", { enumerable: true, get: function () { return tokens_js_6.SHIELD_SIGN_IN_WITH; } });
|
|
443
457
|
var captcha_config_js_1 = require("./config/captcha-config.js");
|
|
444
458
|
Object.defineProperty(exports, "loadCaptchaConfig", { enumerable: true, get: function () { return captcha_config_js_1.loadCaptchaConfig; } });
|
|
445
459
|
Object.defineProperty(exports, "CAPTCHA_ENDPOINTS", { enumerable: true, get: function () { return captcha_config_js_1.CAPTCHA_ENDPOINTS; } });
|
|
@@ -455,8 +469,8 @@ Object.defineProperty(exports, "TURNSTILE_SITEVERIFY_URL", { enumerable: true, g
|
|
|
455
469
|
var recaptcha_verifier_js_1 = require("./captcha/recaptcha-verifier.js");
|
|
456
470
|
Object.defineProperty(exports, "RecaptchaVerifier", { enumerable: true, get: function () { return recaptcha_verifier_js_1.RecaptchaVerifier; } });
|
|
457
471
|
Object.defineProperty(exports, "RECAPTCHA_SITEVERIFY_URL", { enumerable: true, get: function () { return recaptcha_verifier_js_1.RECAPTCHA_SITEVERIFY_URL; } });
|
|
458
|
-
var
|
|
459
|
-
Object.defineProperty(exports, "SHIELD_CAPTCHA_GATE", { enumerable: true, get: function () { return
|
|
472
|
+
var tokens_js_7 = require("./auth/tokens.js");
|
|
473
|
+
Object.defineProperty(exports, "SHIELD_CAPTCHA_GATE", { enumerable: true, get: function () { return tokens_js_7.SHIELD_CAPTCHA_GATE; } });
|
|
460
474
|
// The composition module skeletons (Team B fills the factory bodies; the
|
|
461
475
|
// integration owner imports AuthModule into ShieldModule — see auth.module.ts /
|
|
462
476
|
// DONE.md).
|
|
@@ -494,10 +508,10 @@ var recipient_mask_js_1 = require("./messaging/recipient-mask.js");
|
|
|
494
508
|
Object.defineProperty(exports, "maskPhone", { enumerable: true, get: function () { return recipient_mask_js_1.maskPhone; } });
|
|
495
509
|
var profile_writer_js_1 = require("./auth/ports/profile-writer.js");
|
|
496
510
|
Object.defineProperty(exports, "ProfileNameTakenError", { enumerable: true, get: function () { return profile_writer_js_1.ProfileNameTakenError; } });
|
|
497
|
-
var tokens_js_7 = require("./auth/tokens.js");
|
|
498
|
-
Object.defineProperty(exports, "SHIELD_SESSION_FACTS_PROJECTOR", { enumerable: true, get: function () { return tokens_js_7.SHIELD_SESSION_FACTS_PROJECTOR; } });
|
|
499
511
|
var tokens_js_8 = require("./auth/tokens.js");
|
|
500
|
-
Object.defineProperty(exports, "
|
|
512
|
+
Object.defineProperty(exports, "SHIELD_SESSION_FACTS_PROJECTOR", { enumerable: true, get: function () { return tokens_js_8.SHIELD_SESSION_FACTS_PROJECTOR; } });
|
|
513
|
+
var tokens_js_9 = require("./auth/tokens.js");
|
|
514
|
+
Object.defineProperty(exports, "SHIELD_SCOPE_SUBTREE_RESOLVER", { enumerable: true, get: function () { return tokens_js_9.SHIELD_SCOPE_SUBTREE_RESOLVER; } });
|
|
501
515
|
// The framework-owned `/auth/*` HTTP controller (Team C) + its pending-MFA store.
|
|
502
516
|
// The controller CONSUMES SHIELD_AUTHENTICATOR / SHIELD_SESSION_AUTHORITY and the
|
|
503
517
|
// PendingMfaStore. It is EXPORTED so AuthModule (Team B) / the integration owner
|
|
@@ -514,10 +528,10 @@ var mfa_step_up_js_1 = require("./auth/mfa-step-up.js");
|
|
|
514
528
|
Object.defineProperty(exports, "CredentialMfaStepUp", { enumerable: true, get: function () { return mfa_step_up_js_1.CredentialMfaStepUp; } });
|
|
515
529
|
Object.defineProperty(exports, "credentialFingerprint", { enumerable: true, get: function () { return mfa_step_up_js_1.credentialFingerprint; } });
|
|
516
530
|
Object.defineProperty(exports, "challengeMatches", { enumerable: true, get: function () { return mfa_step_up_js_1.challengeMatches; } });
|
|
517
|
-
var
|
|
518
|
-
Object.defineProperty(exports, "SHIELD_MFA_LIMITER", { enumerable: true, get: function () { return
|
|
519
|
-
Object.defineProperty(exports, "SHIELD_MFA_STEP_UP", { enumerable: true, get: function () { return
|
|
520
|
-
Object.defineProperty(exports, "SHIELD_LOGIN_TOTP_VERIFIER", { enumerable: true, get: function () { return
|
|
531
|
+
var tokens_js_10 = require("./auth/tokens.js");
|
|
532
|
+
Object.defineProperty(exports, "SHIELD_MFA_LIMITER", { enumerable: true, get: function () { return tokens_js_10.SHIELD_MFA_LIMITER; } });
|
|
533
|
+
Object.defineProperty(exports, "SHIELD_MFA_STEP_UP", { enumerable: true, get: function () { return tokens_js_10.SHIELD_MFA_STEP_UP; } });
|
|
534
|
+
Object.defineProperty(exports, "SHIELD_LOGIN_TOTP_VERIFIER", { enumerable: true, get: function () { return tokens_js_10.SHIELD_LOGIN_TOTP_VERIFIER; } });
|
|
521
535
|
// The pure TOTP-enrollment helpers (Phase 4 MFA). Re-exported for consumers/tests
|
|
522
536
|
// that need them; the multi-device MFA routes (Phase 3) reuse them to mint a device
|
|
523
537
|
// secret + provisioning URI + recovery codes. (The old in-memory
|
|
@@ -20,6 +20,7 @@ import type { SignInMethod } from '../authentication/sign-in-with.js';
|
|
|
20
20
|
export { SHIELD_DECISION_AUTHORITY, SHIELD_RECORD_AUTHORIZATION };
|
|
21
21
|
import { type ShieldStorageOption } from '../storage/storage.providers.js';
|
|
22
22
|
import type { ShieldCaptchaOption } from '../captcha/captcha.providers.js';
|
|
23
|
+
import type { NotificationKindRegistration } from '../notifications/ports.js';
|
|
23
24
|
export type { RecordAuthorizationInputs } from '../authz/wire-record-authorization.js';
|
|
24
25
|
/**
|
|
25
26
|
* Options for {@link ShieldModule.forRoot}. Intentionally minimal (ADR-0023 §7 —
|
|
@@ -227,6 +228,15 @@ export interface ShieldModuleOptions {
|
|
|
227
228
|
* pinged at boot (fail closed). `SHIELD_FILE_INGEST` (used by `FileIntake`) is always bound.
|
|
228
229
|
*/
|
|
229
230
|
readonly storage?: ShieldStorageOption;
|
|
231
|
+
/**
|
|
232
|
+
* G-027 step 2 (notification-store SPEC §5C): the kinds app code may post notices under, each
|
|
233
|
+
* `{ kind, category: 'announcement' | 'personal' }`. Kind pattern
|
|
234
|
+
* `^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$`, ≤ 64 characters, `shield.` reserved for the framework.
|
|
235
|
+
* Validated at registration (also without `auth`); a bad, duplicate or `shield.` entry fails the
|
|
236
|
+
* boot naming the kind. `NotificationService.post` (`SHIELD_NOTIFICATIONS`, `auth: true`)
|
|
237
|
+
* refuses any other kind and takes the category from here.
|
|
238
|
+
*/
|
|
239
|
+
readonly notificationKinds?: readonly NotificationKindRegistration[];
|
|
230
240
|
}
|
|
231
241
|
/** Async variant of {@link ShieldModuleOptions} (DI-computed config). */
|
|
232
242
|
export interface ShieldModuleAsyncOptions {
|
|
@@ -342,6 +352,8 @@ export interface ShieldModuleAsyncOptions {
|
|
|
342
352
|
readonly captcha?: ShieldCaptchaOption;
|
|
343
353
|
/** See {@link ShieldModuleOptions.storage}. STATIC here (registration-time, like `auth`). */
|
|
344
354
|
readonly storage?: ShieldStorageOption;
|
|
355
|
+
/** See {@link ShieldModuleOptions.notificationKinds}. STATIC here (registration-time). */
|
|
356
|
+
readonly notificationKinds?: readonly NotificationKindRegistration[];
|
|
345
357
|
}
|
|
346
358
|
/**
|
|
347
359
|
* `ShieldModule` — the SINGLE registration seam (ADR-0023 §4).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shield.module.d.ts","sourceRoot":"","sources":["../../src/module/shield.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,aAAa,EAAiB,MAAM,gBAAgB,CAAC;AAOnF,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAoB,MAAM,cAAc,CAAC;AAQzF,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACtF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AACpF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AASzE,OAAO,EAAqC,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAsC5F,OAAO,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAC;AAC5F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,CAAC;AAElE,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"shield.module.d.ts","sourceRoot":"","sources":["../../src/module/shield.module.ts"],"names":[],"mappings":"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"}
|
|
@@ -87,6 +87,7 @@ Object.defineProperty(exports, "SHIELD_DECISION_AUTHORITY", { enumerable: true,
|
|
|
87
87
|
Object.defineProperty(exports, "SHIELD_RECORD_AUTHORIZATION", { enumerable: true, get: function () { return shield_tokens_js_1.SHIELD_RECORD_AUTHORIZATION; } });
|
|
88
88
|
// FILE_STORAGE SPEC §6: the `storage` option (S3 adapter loaded lazily inside the provider).
|
|
89
89
|
const storage_providers_js_1 = require("../storage/storage.providers.js");
|
|
90
|
+
const notification_service_js_1 = require("../notifications/notification.service.js");
|
|
90
91
|
/**
|
|
91
92
|
* A `Function`-wrapped dynamic `import()` that survives the CommonJS **build** — the same
|
|
92
93
|
* shim as auth.module.ts's `evalImport`. Under `module: commonjs`, `tsc` would rewrite a
|
|
@@ -229,6 +230,9 @@ let ShieldModule = ShieldModule_1 = class ShieldModule {
|
|
|
229
230
|
static forRoot(options = {}) {
|
|
230
231
|
// G-009 N4: a reserved operation principal is never a root, however `rootIds` was built.
|
|
231
232
|
(0, reserved_principal_ids_js_1.assertNoReservedRootId)(options.rootIds);
|
|
233
|
+
// G-027 step 2: a bad `notificationKinds` entry fails the boot naming the kind, with or
|
|
234
|
+
// without auth (AuthModule re-validates the same list when it composes).
|
|
235
|
+
(0, notification_service_js_1.resolveNotificationKinds)(options.notificationKinds);
|
|
232
236
|
const config = options.config ?? loadEnvAppConfig();
|
|
233
237
|
// ADR-0035: with auth on and no explicit projector, sessions cache the facts the framework-built
|
|
234
238
|
// authority decides on (attached when the authority is built; inactive until then).
|
|
@@ -286,6 +290,9 @@ let ShieldModule = ShieldModule_1 = class ShieldModule {
|
|
|
286
290
|
: {}),
|
|
287
291
|
...(options.signInWith !== undefined ? { signInWith: options.signInWith } : {}),
|
|
288
292
|
...(options.captcha !== undefined ? { captcha: options.captcha } : {}),
|
|
293
|
+
...(options.notificationKinds !== undefined
|
|
294
|
+
? { notificationKinds: options.notificationKinds }
|
|
295
|
+
: {}),
|
|
289
296
|
})
|
|
290
297
|
: undefined;
|
|
291
298
|
return {
|
|
@@ -346,6 +353,7 @@ let ShieldModule = ShieldModule_1 = class ShieldModule {
|
|
|
346
353
|
*/
|
|
347
354
|
static forRootAsync(options) {
|
|
348
355
|
(0, reserved_principal_ids_js_1.assertNoReservedRootId)(options.rootIds); // G-009 N4 (the static allowlist; see forRoot)
|
|
356
|
+
(0, notification_service_js_1.resolveNotificationKinds)(options.notificationKinds); // G-027 step 2 (see forRoot)
|
|
349
357
|
const optionsToken = Symbol('SHIELD_MODULE_OPTIONS');
|
|
350
358
|
const asyncOptionsProvider = {
|
|
351
359
|
provide: optionsToken,
|
|
@@ -427,6 +435,9 @@ let ShieldModule = ShieldModule_1 = class ShieldModule {
|
|
|
427
435
|
: {}),
|
|
428
436
|
...(options.signInWith !== undefined ? { signInWith: options.signInWith } : {}),
|
|
429
437
|
...(options.captcha !== undefined ? { captcha: options.captcha } : {}),
|
|
438
|
+
...(options.notificationKinds !== undefined
|
|
439
|
+
? { notificationKinds: options.notificationKinds }
|
|
440
|
+
: {}),
|
|
430
441
|
})
|
|
431
442
|
: undefined;
|
|
432
443
|
return {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `MariaDbNotificationStore` — the framework-default {@link NotificationStore} (notification-store
|
|
3
|
+
* SPEC §5A) over `<ns>_identity.user_notification` (identity migration 108), on guard's core pool
|
|
4
|
+
* (`<ns>_core`, DML on `<ns>_identity`). Database names are resolved at construction, never per
|
|
5
|
+
* request; every statement is parameterized.
|
|
6
|
+
*
|
|
7
|
+
* Tenant wall (core 50 #4, #7; Shield #4): every per-user statement filters `un_user_uuid = ?
|
|
8
|
+
* AND un_tenant_id = ?`, including the post-insert count. `purge` is the one statement that is
|
|
9
|
+
* not per-user: it is the retention sweep over the whole table, bounded by `LIMIT`.
|
|
10
|
+
*
|
|
11
|
+
* `insertMany` is ONE multi-row `INSERT … ON DUPLICATE KEY UPDATE un_dedupe_key = un_dedupe_key`:
|
|
12
|
+
* a repeated `(user, tenant, dedupe key)` is a no-op on `uq_un_dedupe`; never `INSERT IGNORE`
|
|
13
|
+
* (that would also hide FK and data errors). The inserted count is NOT read from `affectedRows`:
|
|
14
|
+
* the `mariadb` driver connects with `CLIENT_FOUND_ROWS` by default (`foundRows` defaults to true,
|
|
15
|
+
* `lib/config/connection-options.js`), so an ODKU row left unchanged reports 1, the same as an
|
|
16
|
+
* insert. Instead the store counts its own freshly generated `un_uuid`s right after the insert, on
|
|
17
|
+
* the same `query` (the caller's transaction when given, so it sees its own uncommitted rows).
|
|
18
|
+
*/
|
|
19
|
+
import type { Pool } from 'mariadb';
|
|
20
|
+
import { type FrameworkSchemaNames } from '../config/framework-schema-names.js';
|
|
21
|
+
import { type NotificationCategory, type NotificationInsert, type NotificationListQuery, type NotificationListResult, type NotificationRetentionPolicy, type NotificationStore, type NotificationUnreadCounts, type NotificationWriteOptions } from './ports.js';
|
|
22
|
+
/** Rows per `insertMany` statement (the `post` recipient cap, SPEC §10). */
|
|
23
|
+
export declare const NOTIFICATION_INSERT_MAX_ROWS = 1000;
|
|
24
|
+
export declare class MariaDbNotificationStore implements NotificationStore {
|
|
25
|
+
private readonly pool;
|
|
26
|
+
/** `<identity>`.`user_notification`, resolved at construction. */
|
|
27
|
+
private readonly table;
|
|
28
|
+
constructor(pool: Pick<Pool, 'query'>,
|
|
29
|
+
/** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
|
|
30
|
+
schemas?: FrameworkSchemaNames);
|
|
31
|
+
list(userId: string, tenantId: string, query: NotificationListQuery): Promise<NotificationListResult>;
|
|
32
|
+
countUnread(userId: string, tenantId: string): Promise<NotificationUnreadCounts>;
|
|
33
|
+
markRead(userId: string, tenantId: string, uuid: string, nowMs: number): Promise<boolean>;
|
|
34
|
+
markAllRead(userId: string, tenantId: string, category: NotificationCategory | undefined, nowMs: number): Promise<number>;
|
|
35
|
+
insertMany(rows: readonly NotificationInsert[], opts?: NotificationWriteOptions): Promise<number>;
|
|
36
|
+
purge(nowMs: number, policy: NotificationRetentionPolicy, maxRows: number): Promise<number>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=mariadb-notification-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mariadb-notification-store.d.ts","sourceRoot":"","sources":["../../src/notifications/mariadb-notification-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAE3B,KAAK,2BAA2B,EAEhC,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC9B,MAAM,YAAY,CAAC;AAIpB,4EAA4E;AAC5E,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAgDjD,qBAAa,wBAAyB,YAAW,iBAAiB;IAK9D,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJvB,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAGZ,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;IAC1C,yFAAyF;IACzF,OAAO,CAAC,EAAE,oBAAoB;IAQ1B,IAAI,CACR,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,sBAAsB,CAAC;IA2B5B,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAchF,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBzF,WAAW,CACf,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,oBAAoB,GAAG,SAAS,EAC1C,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC;IAWZ,UAAU,CACd,IAAI,EAAE,SAAS,kBAAkB,EAAE,EACnC,IAAI,GAAE,wBAA6B,GAClC,OAAO,CAAC,MAAM,CAAC;IAuDZ,KAAK,CACT,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,2BAA2B,EACnC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC;CAiBnB"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MariaDbNotificationStore = exports.NOTIFICATION_INSERT_MAX_ROWS = void 0;
|
|
4
|
+
const framework_schema_names_js_1 = require("../config/framework-schema-names.js");
|
|
5
|
+
const ports_js_1 = require("./ports.js");
|
|
6
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
7
|
+
/** Rows per `insertMany` statement (the `post` recipient cap, SPEC §10). */
|
|
8
|
+
exports.NOTIFICATION_INSERT_MAX_ROWS = 1000;
|
|
9
|
+
const SELECT_COLUMNS = 'un_uuid, un_category, un_kind, un_title, un_body, un_link, un_created_at_ms, un_read_at_ms';
|
|
10
|
+
function isCategory(v) {
|
|
11
|
+
return ports_js_1.NOTIFICATION_CATEGORIES.includes(v);
|
|
12
|
+
}
|
|
13
|
+
/** BIGINT columns may arrive as bigint; the epoch-ms range fits a safe integer. */
|
|
14
|
+
const toRow = (r) => ({
|
|
15
|
+
uuid: String(r.un_uuid),
|
|
16
|
+
// The column carries a CHECK constraint; an unexpected value is still never passed on raw.
|
|
17
|
+
category: isCategory(r.un_category) ? r.un_category : 'personal',
|
|
18
|
+
kind: r.un_kind,
|
|
19
|
+
title: r.un_title,
|
|
20
|
+
body: r.un_body ?? null,
|
|
21
|
+
link: r.un_link ?? null,
|
|
22
|
+
createdAtMs: Number(r.un_created_at_ms),
|
|
23
|
+
readAtMs: r.un_read_at_ms == null ? null : Number(r.un_read_at_ms),
|
|
24
|
+
});
|
|
25
|
+
function affected(res) {
|
|
26
|
+
return Number(res?.affectedRows ?? 0);
|
|
27
|
+
}
|
|
28
|
+
function countOf(rows) {
|
|
29
|
+
const first = Array.isArray(rows) ? rows[0] : undefined;
|
|
30
|
+
return Number(first?.c ?? 0);
|
|
31
|
+
}
|
|
32
|
+
function assertPositiveInteger(name, v, max) {
|
|
33
|
+
if (!Number.isSafeInteger(v) || v < 1 || (max !== undefined && v > max)) {
|
|
34
|
+
throw new RangeError(`MariaDbNotificationStore: ${name} is out of range`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
class MariaDbNotificationStore {
|
|
38
|
+
pool;
|
|
39
|
+
/** `<identity>`.`user_notification`, resolved at construction. */
|
|
40
|
+
table;
|
|
41
|
+
constructor(pool,
|
|
42
|
+
/** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
|
|
43
|
+
schemas) {
|
|
44
|
+
this.pool = pool;
|
|
45
|
+
this.table = (0, framework_schema_names_js_1.qualifiedTableName)((0, framework_schema_names_js_1.schemaNamesAtConstruction)(schemas).identity, 'user_notification');
|
|
46
|
+
}
|
|
47
|
+
async list(userId, tenantId, query) {
|
|
48
|
+
assertPositiveInteger('page', query.page);
|
|
49
|
+
assertPositiveInteger('limit', query.limit, 100);
|
|
50
|
+
const where = ['un_user_uuid = ?', 'un_tenant_id = ?'];
|
|
51
|
+
const params = [userId, tenantId];
|
|
52
|
+
if (query.category !== undefined) {
|
|
53
|
+
where.push('un_category = ?');
|
|
54
|
+
params.push(query.category);
|
|
55
|
+
}
|
|
56
|
+
if (query.unreadOnly)
|
|
57
|
+
where.push('un_read_at_ms IS NULL');
|
|
58
|
+
const clause = where.join(' AND ');
|
|
59
|
+
const total = countOf(await this.pool.query(`SELECT COUNT(*) AS c FROM ${this.table} WHERE ${clause}`, params));
|
|
60
|
+
if (total === 0)
|
|
61
|
+
return { total: 0, rows: [] };
|
|
62
|
+
const offset = (query.page - 1) * query.limit;
|
|
63
|
+
if (!Number.isSafeInteger(offset)) {
|
|
64
|
+
throw new RangeError('MariaDbNotificationStore: page is out of range');
|
|
65
|
+
}
|
|
66
|
+
const rows = (await this.pool.query(`SELECT ${SELECT_COLUMNS} FROM ${this.table} WHERE ${clause}
|
|
67
|
+
ORDER BY un_created_at_ms DESC, un_uuid DESC LIMIT ? OFFSET ?`, [...params, query.limit, offset]));
|
|
68
|
+
return { total, rows: rows.map(toRow) };
|
|
69
|
+
}
|
|
70
|
+
async countUnread(userId, tenantId) {
|
|
71
|
+
const rows = (await this.pool.query(`SELECT un_category, COUNT(*) AS c FROM ${this.table}
|
|
72
|
+
WHERE un_user_uuid = ? AND un_tenant_id = ? AND un_read_at_ms IS NULL
|
|
73
|
+
GROUP BY un_category`, [userId, tenantId]));
|
|
74
|
+
const counts = { announcement: 0, personal: 0 };
|
|
75
|
+
for (const r of rows) {
|
|
76
|
+
if (isCategory(r.un_category))
|
|
77
|
+
counts[r.un_category] = Number(r.c);
|
|
78
|
+
}
|
|
79
|
+
return counts;
|
|
80
|
+
}
|
|
81
|
+
async markRead(userId, tenantId, uuid, nowMs) {
|
|
82
|
+
const res = await this.pool.query(`UPDATE ${this.table} SET un_read_at_ms = ?
|
|
83
|
+
WHERE un_uuid = ? AND un_user_uuid = ? AND un_tenant_id = ? AND un_read_at_ms IS NULL`, [nowMs, uuid, userId, tenantId]);
|
|
84
|
+
if (affected(res) > 0)
|
|
85
|
+
return true;
|
|
86
|
+
// Already read (the first read time is kept) or not this caller's notice in this tenant.
|
|
87
|
+
const rows = (await this.pool.query(`SELECT 1 AS found FROM ${this.table}
|
|
88
|
+
WHERE un_uuid = ? AND un_user_uuid = ? AND un_tenant_id = ? LIMIT 1`, [uuid, userId, tenantId]));
|
|
89
|
+
return rows.length > 0;
|
|
90
|
+
}
|
|
91
|
+
async markAllRead(userId, tenantId, category, nowMs) {
|
|
92
|
+
const params = [nowMs, userId, tenantId];
|
|
93
|
+
let sql = `UPDATE ${this.table} SET un_read_at_ms = ?
|
|
94
|
+
WHERE un_user_uuid = ? AND un_tenant_id = ? AND un_read_at_ms IS NULL`;
|
|
95
|
+
if (category !== undefined) {
|
|
96
|
+
sql += ' AND un_category = ?';
|
|
97
|
+
params.push(category);
|
|
98
|
+
}
|
|
99
|
+
return affected(await this.pool.query(sql, params));
|
|
100
|
+
}
|
|
101
|
+
async insertMany(rows, opts = {}) {
|
|
102
|
+
if (rows.length === 0)
|
|
103
|
+
return 0;
|
|
104
|
+
if (rows.length > exports.NOTIFICATION_INSERT_MAX_ROWS) {
|
|
105
|
+
throw new RangeError('MariaDbNotificationStore: too many rows for one insert');
|
|
106
|
+
}
|
|
107
|
+
const run = opts.query ?? ((sql, params) => this.pool.query(sql, params));
|
|
108
|
+
const params = [];
|
|
109
|
+
for (const r of rows) {
|
|
110
|
+
params.push(r.uuid, r.tenantId, r.userId, r.category, r.kind, r.title, r.body, r.link, r.dedupeKey, r.createdAtMs);
|
|
111
|
+
}
|
|
112
|
+
const values = rows.map(() => '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL)').join(', ');
|
|
113
|
+
await run(`INSERT INTO ${this.table}
|
|
114
|
+
(un_uuid, un_tenant_id, un_user_uuid, un_category, un_kind, un_title, un_body, un_link,
|
|
115
|
+
un_dedupe_key, un_created_at_ms, un_read_at_ms)
|
|
116
|
+
VALUES ${values}
|
|
117
|
+
ON DUPLICATE KEY UPDATE un_dedupe_key = un_dedupe_key`, params);
|
|
118
|
+
// Count the rows that landed (see the file header: affectedRows cannot tell an ODKU no-op from
|
|
119
|
+
// an insert). Grouped by tenant so every statement stays tenant- and user-scoped.
|
|
120
|
+
const byTenant = new Map();
|
|
121
|
+
for (const r of rows) {
|
|
122
|
+
const group = byTenant.get(r.tenantId);
|
|
123
|
+
if (group)
|
|
124
|
+
group.push(r);
|
|
125
|
+
else
|
|
126
|
+
byTenant.set(r.tenantId, [r]);
|
|
127
|
+
}
|
|
128
|
+
let inserted = 0;
|
|
129
|
+
for (const [tenantId, group] of byTenant) {
|
|
130
|
+
const users = [...new Set(group.map((r) => r.userId))];
|
|
131
|
+
const marks = (n) => new Array(n).fill('?').join(', ');
|
|
132
|
+
inserted += countOf(await run(`SELECT COUNT(*) AS c FROM ${this.table}
|
|
133
|
+
WHERE un_tenant_id = ? AND un_user_uuid IN (${marks(users.length)})
|
|
134
|
+
AND un_uuid IN (${marks(group.length)})`, [tenantId, ...users, ...group.map((r) => r.uuid)]));
|
|
135
|
+
}
|
|
136
|
+
return inserted;
|
|
137
|
+
}
|
|
138
|
+
async purge(nowMs, policy, maxRows) {
|
|
139
|
+
assertPositiveInteger('maxRows', maxRows);
|
|
140
|
+
const readCutoff = nowMs - policy.readDays * DAY_MS;
|
|
141
|
+
const maxCutoff = nowMs - policy.maxDays * DAY_MS;
|
|
142
|
+
// `maxDays ≥ readDays` (loader rule) ⇒ maxCutoff ≤ readCutoff, so the leading range keeps the
|
|
143
|
+
// statement on `idx_un_created`: read notices older than the read retention, and every notice
|
|
144
|
+
// older than the max retention.
|
|
145
|
+
const lead = Math.max(readCutoff, maxCutoff);
|
|
146
|
+
return affected(await this.pool.query(`DELETE FROM ${this.table}
|
|
147
|
+
WHERE un_created_at_ms < ? AND (un_read_at_ms IS NOT NULL OR un_created_at_ms < ?)
|
|
148
|
+
ORDER BY un_created_at_ms LIMIT ?`, [lead, maxCutoff, maxRows]));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.MariaDbNotificationStore = MariaDbNotificationStore;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `NotificationRetentionJob` — deletes expired notices (notification-store SPEC §5E, §10, §11).
|
|
3
|
+
*
|
|
4
|
+
* Registered with `ShieldModule.forRoot({ auth: true })` beside the store, over guard's core pool
|
|
5
|
+
* `SHIELD_DB_POOL` (it does not own the pool: `ConnectionLifecycle` ends it in
|
|
6
|
+
* `onApplicationShutdown`, after this job stopped).
|
|
7
|
+
*
|
|
8
|
+
* - First pass {@link NOTIFICATION_RETENTION_FIRST_RUN_MS} after bootstrap, then one pass every
|
|
9
|
+
* {@link NOTIFICATION_RETENTION_INTERVAL_MS} (hourly), scheduled only after the previous pass
|
|
10
|
+
* settled, so passes never overlap.
|
|
11
|
+
* - One pass = one `purge` of at most {@link NOTIFICATION_RETENTION_BATCH} rows: read notices older
|
|
12
|
+
* than `NOTIFICATION_READ_RETENTION_DAYS`, any notice older than `NOTIFICATION_MAX_RETENTION_DAYS`.
|
|
13
|
+
* - A failed pass is logged by error class only (never the driver message) and retried at the next
|
|
14
|
+
* interval; nothing here throws into Nest, so it never blocks boot (a missing table, migration
|
|
15
|
+
* 108 not applied, is just a logged pass).
|
|
16
|
+
* - Every timer is `unref()`'d. `onModuleDestroy` (Nest `close()` step 1) clears the timer and
|
|
17
|
+
* waits for a running pass. Off the request path (Shield #12).
|
|
18
|
+
*/
|
|
19
|
+
import { type OnApplicationBootstrap, type OnModuleDestroy } from '@nestjs/common';
|
|
20
|
+
import type { NotificationRetentionPolicy, NotificationStore } from './ports.js';
|
|
21
|
+
export declare const NOTIFICATION_RETENTION_FIRST_RUN_MS = 5000;
|
|
22
|
+
export declare const NOTIFICATION_RETENTION_INTERVAL_MS: number;
|
|
23
|
+
export declare const NOTIFICATION_RETENTION_BATCH = 5000;
|
|
24
|
+
export interface NotificationRetentionLogger {
|
|
25
|
+
log(message: string): void;
|
|
26
|
+
error(message: string): void;
|
|
27
|
+
}
|
|
28
|
+
export interface NotificationRetentionJobOptions {
|
|
29
|
+
/** Default `Date.now`. */
|
|
30
|
+
readonly now?: () => number;
|
|
31
|
+
/** Default `new Logger('Shield')`. */
|
|
32
|
+
readonly logger?: NotificationRetentionLogger;
|
|
33
|
+
}
|
|
34
|
+
export declare class NotificationRetentionJob implements OnApplicationBootstrap, OnModuleDestroy {
|
|
35
|
+
private readonly store;
|
|
36
|
+
private readonly policy;
|
|
37
|
+
private readonly now;
|
|
38
|
+
private readonly logger;
|
|
39
|
+
private stopped;
|
|
40
|
+
private timer;
|
|
41
|
+
private inFlight;
|
|
42
|
+
constructor(store: Pick<NotificationStore, 'purge'>, policy: NotificationRetentionPolicy, options?: NotificationRetentionJobOptions);
|
|
43
|
+
onApplicationBootstrap(): void;
|
|
44
|
+
onModuleDestroy(): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* One retention pass; resolves to the deleted count, or `null` when the pass failed (logged).
|
|
47
|
+
* Exposed for tests and operators; the timer calls it hourly.
|
|
48
|
+
*/
|
|
49
|
+
runOnce(): Promise<number | null>;
|
|
50
|
+
private schedule;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=notification-retention.job.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-retention.job.d.ts","sourceRoot":"","sources":["../../src/notifications/notification-retention.job.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,2BAA2B,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEjF,eAAO,MAAM,mCAAmC,OAAQ,CAAC;AACzD,eAAO,MAAM,kCAAkC,QAAiB,CAAC;AACjE,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAEjD,MAAM,WAAW,2BAA2B;IAC1C,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,+BAA+B;IAC9C,0BAA0B;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,sCAAsC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,2BAA2B,CAAC;CAC/C;AAED,qBACa,wBAAyB,YAAW,sBAAsB,EAAE,eAAe;IAQpF,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IARzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IACrD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,QAAQ,CAA4B;gBAGzB,KAAK,EAAE,IAAI,CAAC,iBAAiB,EAAE,OAAO,CAAC,EACvC,MAAM,EAAE,2BAA2B,EACpD,OAAO,GAAE,+BAAoC;IAM/C,sBAAsB,IAAI,IAAI;IAIxB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtC;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAavC,OAAO,CAAC,QAAQ;CAcjB"}
|