@futdevpro/nts-dynamo 1.15.233 → 1.15.240

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.
Files changed (47) hide show
  1. package/build/_enums/email-submission-outcome.enum.d.ts +8 -0
  2. package/build/_enums/email-submission-outcome.enum.d.ts.map +1 -0
  3. package/build/_enums/email-submission-outcome.enum.js +12 -0
  4. package/build/_enums/email-submission-outcome.enum.js.map +1 -0
  5. package/build/_models/interfaces/email-submission-receipt.interface.d.ts +19 -0
  6. package/build/_models/interfaces/email-submission-receipt.interface.d.ts.map +1 -0
  7. package/build/_models/interfaces/email-submission-receipt.interface.js +3 -0
  8. package/build/_models/interfaces/email-submission-receipt.interface.js.map +1 -0
  9. package/build/_modules/account-security/_models/account-challenge-transaction-settings.interface.d.ts +21 -0
  10. package/build/_modules/account-security/_models/account-challenge-transaction-settings.interface.d.ts.map +1 -0
  11. package/build/_modules/account-security/_models/account-challenge-transaction-settings.interface.js +3 -0
  12. package/build/_modules/account-security/_models/account-challenge-transaction-settings.interface.js.map +1 -0
  13. package/build/_modules/account-security/_models/account-session-transaction-settings.interface.d.ts +12 -0
  14. package/build/_modules/account-security/_models/account-session-transaction-settings.interface.d.ts.map +1 -0
  15. package/build/_modules/account-security/_models/account-session-transaction-settings.interface.js +3 -0
  16. package/build/_modules/account-security/_models/account-session-transaction-settings.interface.js.map +1 -0
  17. package/build/_modules/account-security/account-challenge-transaction.mongo-adapter.d.ts +44 -0
  18. package/build/_modules/account-security/account-challenge-transaction.mongo-adapter.d.ts.map +1 -0
  19. package/build/_modules/account-security/account-challenge-transaction.mongo-adapter.js +174 -0
  20. package/build/_modules/account-security/account-challenge-transaction.mongo-adapter.js.map +1 -0
  21. package/build/_modules/account-security/account-session-transaction.mongo-store.d.ts +24 -0
  22. package/build/_modules/account-security/account-session-transaction.mongo-store.d.ts.map +1 -0
  23. package/build/_modules/account-security/account-session-transaction.mongo-store.js +96 -0
  24. package/build/_modules/account-security/account-session-transaction.mongo-store.js.map +1 -0
  25. package/build/_modules/account-security/account-session.control-service.d.ts +12 -0
  26. package/build/_modules/account-security/account-session.control-service.d.ts.map +1 -1
  27. package/build/_modules/account-security/account-session.control-service.js +28 -3
  28. package/build/_modules/account-security/account-session.control-service.js.map +1 -1
  29. package/build/_modules/account-security/index.d.ts +4 -0
  30. package/build/_modules/account-security/index.d.ts.map +1 -1
  31. package/build/_modules/account-security/index.js +5 -1
  32. package/build/_modules/account-security/index.js.map +1 -1
  33. package/build/_modules/privacy-lifecycle/_models/privacy-rights-custody.interface.d.ts +12 -0
  34. package/build/_modules/privacy-lifecycle/_models/privacy-rights-custody.interface.d.ts.map +1 -1
  35. package/build/_modules/privacy-lifecycle/privacy-rights-custody.mongo-store.d.ts +2 -0
  36. package/build/_modules/privacy-lifecycle/privacy-rights-custody.mongo-store.d.ts.map +1 -1
  37. package/build/_modules/privacy-lifecycle/privacy-rights-custody.mongo-store.js +35 -6
  38. package/build/_modules/privacy-lifecycle/privacy-rights-custody.mongo-store.js.map +1 -1
  39. package/build/_services/core/email.service.d.ts +9 -0
  40. package/build/_services/core/email.service.d.ts.map +1 -1
  41. package/build/_services/core/email.service.js +90 -25
  42. package/build/_services/core/email.service.js.map +1 -1
  43. package/build/index.d.ts +2 -0
  44. package/build/index.d.ts.map +1 -1
  45. package/build/index.js +2 -0
  46. package/build/index.js.map +1 -1
  47. package/package.json +1 -1
@@ -0,0 +1,8 @@
1
+ /** SMTP submission evidence, never a mailbox-delivery or deduplication guarantee. */
2
+ export declare enum DyNTS_EmailSubmissionOutcome_Enum {
3
+ accepted = "accepted",
4
+ partial = "partial",
5
+ rejected = "rejected",
6
+ indeterminate = "indeterminate"
7
+ }
8
+ //# sourceMappingURL=email-submission-outcome.enum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-submission-outcome.enum.d.ts","sourceRoot":"","sources":["../../src/_enums/email-submission-outcome.enum.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,oBAAY,iCAAiC;IAC3C,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,aAAa,kBAAkB;CAChC"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyNTS_EmailSubmissionOutcome_Enum = void 0;
4
+ /** SMTP submission evidence, never a mailbox-delivery or deduplication guarantee. */
5
+ var DyNTS_EmailSubmissionOutcome_Enum;
6
+ (function (DyNTS_EmailSubmissionOutcome_Enum) {
7
+ DyNTS_EmailSubmissionOutcome_Enum["accepted"] = "accepted";
8
+ DyNTS_EmailSubmissionOutcome_Enum["partial"] = "partial";
9
+ DyNTS_EmailSubmissionOutcome_Enum["rejected"] = "rejected";
10
+ DyNTS_EmailSubmissionOutcome_Enum["indeterminate"] = "indeterminate";
11
+ })(DyNTS_EmailSubmissionOutcome_Enum || (exports.DyNTS_EmailSubmissionOutcome_Enum = DyNTS_EmailSubmissionOutcome_Enum = {}));
12
+ //# sourceMappingURL=email-submission-outcome.enum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-submission-outcome.enum.js","sourceRoot":"","sources":["../../src/_enums/email-submission-outcome.enum.ts"],"names":[],"mappings":";;;AAAA,qFAAqF;AACrF,IAAY,iCAKX;AALD,WAAY,iCAAiC;IAC3C,0DAAqB,CAAA;IACrB,wDAAmB,CAAA;IACnB,0DAAqB,CAAA;IACrB,oEAA+B,CAAA;AACjC,CAAC,EALW,iCAAiC,iDAAjC,iCAAiC,QAK5C"}
@@ -0,0 +1,19 @@
1
+ import { DyNTS_EmailSubmissionOutcome_Enum } from '../../_enums/email-submission-outcome.enum';
2
+ /** Submission evidence only: SMTP acceptance is neither inbox delivery nor provider idempotency. */
3
+ export interface DyNTS_EmailSubmissionReceipt_Interface {
4
+ /** Versioned, content-free receipt contract. */
5
+ contractVersion: 'dynts-email-submission-receipt/1';
6
+ /** Test-sink acknowledgement must never be interpreted as real SMTP submission. */
7
+ channel: 'smtp' | 'test-sink';
8
+ /** Partial or indeterminate submission must not trigger a blind automatic resend. */
9
+ outcome: DyNTS_EmailSubmissionOutcome_Enum;
10
+ /** Digest of the transport message ID, which may be locally generated; not a provider queue ID. */
11
+ submissionReference: string;
12
+ /** Aggregate accepted recipient count, without addresses. */
13
+ acceptedCount: number;
14
+ /** Aggregate rejected recipient count, without addresses. */
15
+ rejectedCount: number;
16
+ /** Aggregate pending recipient count, without addresses. */
17
+ pendingCount: number;
18
+ }
19
+ //# sourceMappingURL=email-submission-receipt.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-submission-receipt.interface.d.ts","sourceRoot":"","sources":["../../../src/_models/interfaces/email-submission-receipt.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iCAAiC,EAAE,MAAM,4CAA4C,CAAC;AAE/F,oGAAoG;AACpG,MAAM,WAAW,sCAAsC;IACrD,gDAAgD;IAChD,eAAe,EAAE,kCAAkC,CAAC;IACpD,mFAAmF;IACnF,OAAO,EAAE,MAAM,GAAG,WAAW,CAAC;IAC9B,qFAAqF;IACrF,OAAO,EAAE,iCAAiC,CAAC;IAC3C,mGAAmG;IACnG,mBAAmB,EAAE,MAAM,CAAC;IAC5B,6DAA6D;IAC7D,aAAa,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,aAAa,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAC;CACtB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=email-submission-receipt.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-submission-receipt.interface.js","sourceRoot":"","sources":["../../../src/_models/interfaces/email-submission-receipt.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import { ClientSession, Connection, mongo } from 'mongoose';
2
+ import { DyNTS_AccountChallengeRecord_Interface } from './account-challenge-record.interface';
3
+ /** Trusted storage mapping; challenge authority fields retain their canonical names and values. */
4
+ export interface DyNTS_AccountChallengeDocumentCodec_Interface {
5
+ encode(record: DyNTS_AccountChallengeRecord_Interface): mongo.Document;
6
+ decode(document: mongo.Document): DyNTS_AccountChallengeRecord_Interface;
7
+ /** Additional audit fields only; may not replace challenge fields or introduce update operators. */
8
+ stamp(at: string, subjectId: string): mongo.Document;
9
+ }
10
+ /** A short-lived adapter bound to one authenticated subject and one caller-owned strong transaction. */
11
+ export interface DyNTS_AccountChallengeTransactionSettings_Interface {
12
+ readonly connection: Connection;
13
+ readonly session: ClientSession;
14
+ readonly subjectId: string;
15
+ readonly collectionName: string;
16
+ readonly maxOperationTimeMs: number;
17
+ readonly codec: DyNTS_AccountChallengeDocumentCodec_Interface;
18
+ /** Must perform a real subject-eligibility write fence in this session; snapshot-only reads are insufficient. */
19
+ readonly lockSubject: (subjectId: string, session: ClientSession) => Promise<boolean>;
20
+ }
21
+ //# sourceMappingURL=account-challenge-transaction-settings.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-challenge-transaction-settings.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/account-security/_models/account-challenge-transaction-settings.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAE5D,OAAO,EAAE,sCAAsC,EAAE,MAAM,sCAAsC,CAAC;AAE9F,mGAAmG;AACnG,MAAM,WAAW,6CAA6C;IAC5D,MAAM,CAAC,MAAM,EAAE,sCAAsC,GAAG,KAAK,CAAC,QAAQ,CAAC;IACvE,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAG,sCAAsC,CAAC;IACzE,oGAAoG;IACpG,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC;CACtD;AAED,wGAAwG;AACxG,MAAM,WAAW,mDAAmD;IAClE,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,6CAA6C,CAAC;IAC9D,iHAAiH;IACjH,QAAQ,CAAC,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACvF"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=account-challenge-transaction-settings.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-challenge-transaction-settings.interface.js","sourceRoot":"","sources":["../../../../src/_modules/account-security/_models/account-challenge-transaction-settings.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ import { ClientSession, Connection } from 'mongoose';
2
+ import { DyNTS_AccountSessionClaims_Interface } from './account-session-claims.interface';
3
+ /** Trusted physical mapping for a short-lived session fence; no alternative account or token engine. */
4
+ export interface DyNTS_AccountSessionTransactionSettings_Interface {
5
+ readonly connection: Connection;
6
+ readonly session: ClientSession;
7
+ readonly collectionName: string;
8
+ readonly maxOperationTimeMs: number;
9
+ /** Must write-fence an active, verified, undeleted subject with this exact authorizationVersion in this session. */
10
+ readonly lockSubject: (claims: Readonly<DyNTS_AccountSessionClaims_Interface>, session: ClientSession) => Promise<boolean>;
11
+ }
12
+ //# sourceMappingURL=account-session-transaction-settings.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-session-transaction-settings.interface.d.ts","sourceRoot":"","sources":["../../../../src/_modules/account-security/_models/account-session-transaction-settings.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAErD,OAAO,EAAE,oCAAoC,EAAE,MAAM,oCAAoC,CAAC;AAE1F,wGAAwG;AACxG,MAAM,WAAW,iDAAiD;IAChE,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,oHAAoH;IACpH,QAAQ,CAAC,WAAW,EAAE,CACpB,MAAM,EAAE,QAAQ,CAAC,oCAAoC,CAAC,EAAE,OAAO,EAAE,aAAa,KAC3E,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=account-session-transaction-settings.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-session-transaction-settings.interface.js","sourceRoot":"","sources":["../../../../src/_modules/account-security/_models/account-session-transaction-settings.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,44 @@
1
+ import { DyNTS_AccountChallengePurpose_Type } from './_enums/account-challenge-purpose.type-enum';
2
+ import { DyNTS_AccountChallengeAdapter_Interface } from './_models/account-challenge-adapter.interface';
3
+ import { DyNTS_AccountChallengeRecord_Interface } from './_models/account-challenge-record.interface';
4
+ import { DyNTS_AccountChallengeTransactionSettings_Interface } from './_models/account-challenge-transaction-settings.interface';
5
+ /**
6
+ * Persistence for the existing challenge service, never a second token engine. All operations share the caller's
7
+ * snapshot/majority transaction and authenticated subject fence. Errors must escape the outer transaction.
8
+ * Bootstrap owns collection/index readiness; this adapter neither migrates schemas nor creates transactions.
9
+ */
10
+ export declare class DyNTS_AccountChallengeTransaction_MongoAdapter implements DyNTS_AccountChallengeAdapter_Interface {
11
+ private readonly settings;
12
+ private readonly ownedErrors;
13
+ /** Captures trusted connection, physical mapping and authority without reading or storing raw credentials. */
14
+ constructor(settings: DyNTS_AccountChallengeTransactionSettings_Interface);
15
+ /** Replaces active grants only within the bound subject; the outer commit publishes the new hash. */
16
+ replaceActiveChallenge(record: DyNTS_AccountChallengeRecord_Interface): Promise<void>;
17
+ /** Atomically consumes the exact subject/hash/purpose grant; a failed outer transaction restores it. */
18
+ consumeActiveChallenge(tokenHash: string, purpose: DyNTS_AccountChallengePurpose_Type, consumedAt: string): Promise<DyNTS_AccountChallengeRecord_Interface | null>;
19
+ /** Revokes one purpose without touching foreign subjects or already-terminal grants. */
20
+ revokeSubjectChallenges(subjectId: string, purpose: DyNTS_AccountChallengePurpose_Type, revokedAt: string): Promise<void>;
21
+ /** Checks session ownership before invoking the trusted account fence, preserving only safe driver retry labels. */
22
+ private execute;
23
+ /** Ensures trusted metadata conversion cannot substitute canonical persisted challenge authority. */
24
+ private decode;
25
+ /** Validates the canonical hash-only record after physical storage mapping, never echoing rejected data. */
26
+ private assertRecord;
27
+ /** Keeps audit-field hooks from replacing security state or injecting Mongo update paths. */
28
+ private stamp;
29
+ /** Uses immutable adapter authority, never a subject discovered by looking up a token. */
30
+ private active;
31
+ /** Passes the same caller-owned session and operation bound to every database call. */
32
+ private options;
33
+ /** Resolves only the caller's already-provisioned collection on the exact connection. */
34
+ private collection;
35
+ /** Requires the fixed ISO representation used by challenge services for safe indexed date comparisons. */
36
+ private date;
37
+ /** Bounds opaque server-derived identifiers without imposing a product naming convention. */
38
+ private subject;
39
+ /** Restricts issuance, consumption and revocation to the shared closed purpose vocabulary. */
40
+ private purpose;
41
+ /** Produces stable diagnostics without identifiers, token hashes, database commands or callback messages. */
42
+ private error;
43
+ }
44
+ //# sourceMappingURL=account-challenge-transaction.mongo-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-challenge-transaction.mongo-adapter.d.ts","sourceRoot":"","sources":["../../../src/_modules/account-security/account-challenge-transaction.mongo-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kCAAkC,EAAE,MAAM,8CAA8C,CAAC;AAClG,OAAO,EAAE,uCAAuC,EAAE,MAAM,+CAA+C,CAAC;AACxG,OAAO,EAAE,sCAAsC,EAAE,MAAM,8CAA8C,CAAC;AACtG,OAAO,EACL,mDAAmD,EACpD,MAAM,4DAA4D,CAAC;AAMpE;;;;GAIG;AACH,qBAAa,8CAA+C,YAAW,uCAAuC;IAC5G,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsD;IAC/E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiC;IAE7D,8GAA8G;gBAClG,QAAQ,EAAE,mDAAmD;IAYzE,qGAAqG;IACxF,sBAAsB,CAAC,MAAM,EAAE,sCAAsC,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBlG,wGAAwG;IAC3F,sBAAsB,CACjC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,kCAAkC,EAAE,UAAU,EAAE,MAAM,GACjF,OAAO,CAAC,sCAAsC,GAAG,IAAI,CAAC;IA0BzD,wFAAwF;IAC3E,uBAAuB,CAClC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,kCAAkC,EAAE,SAAS,EAAE,MAAM,GAChF,OAAO,CAAC,IAAI,CAAC;IAWhB,oHAAoH;YACtG,OAAO;IAkCrB,qGAAqG;IACrG,OAAO,CAAC,MAAM;IAcd,4GAA4G;IAC5G,OAAO,CAAC,YAAY;IAWpB,6FAA6F;IAC7F,OAAO,CAAC,KAAK;IAYb,0FAA0F;IAC1F,OAAO,CAAC,MAAM;IAId,uFAAuF;IACvF,OAAO,CAAC,OAAO;IAIf,yFAAyF;IACzF,OAAO,CAAC,UAAU;IAIlB,0GAA0G;IAC1G,OAAO,CAAC,IAAI;IAKZ,6FAA6F;IAC7F,OAAO,CAAC,OAAO;IAIf,8FAA8F;IAC9F,OAAO,CAAC,OAAO;IAIf,6GAA6G;IAC7G,OAAO,CAAC,KAAK;CAOd"}
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyNTS_AccountChallengeTransaction_MongoAdapter = void 0;
4
+ const mongoose_1 = require("mongoose");
5
+ const account_challenge_purpose_type_enum_1 = require("./_enums/account-challenge-purpose.type-enum");
6
+ const PROTECTED_FIELDS = [
7
+ '_id', 'challengeId', 'subjectId', 'purpose', 'tokenHash', 'createdAt', 'expiresAt', 'consumedAt', 'revokedAt',
8
+ ];
9
+ /**
10
+ * Persistence for the existing challenge service, never a second token engine. All operations share the caller's
11
+ * snapshot/majority transaction and authenticated subject fence. Errors must escape the outer transaction.
12
+ * Bootstrap owns collection/index readiness; this adapter neither migrates schemas nor creates transactions.
13
+ */
14
+ class DyNTS_AccountChallengeTransaction_MongoAdapter {
15
+ settings;
16
+ ownedErrors = new WeakSet();
17
+ /** Captures trusted connection, physical mapping and authority without reading or storing raw credentials. */
18
+ constructor(settings) {
19
+ if (!settings?.connection || !settings.session || !this.subject(settings.subjectId)
20
+ || typeof settings.collectionName !== 'string' || !/^[A-Za-z][A-Za-z0-9_]{0,119}$/u.test(settings.collectionName)
21
+ || !Number.isSafeInteger(settings.maxOperationTimeMs) || settings.maxOperationTimeMs < 1
22
+ || settings.maxOperationTimeMs > 2_147_483_647 || typeof settings.lockSubject !== 'function'
23
+ || typeof settings.codec?.encode !== 'function' || typeof settings.codec?.decode !== 'function'
24
+ || typeof settings.codec?.stamp !== 'function') {
25
+ throw this.error('SETTINGS_INVALID');
26
+ }
27
+ this.settings = Object.freeze({ ...settings });
28
+ }
29
+ /** Replaces active grants only within the bound subject; the outer commit publishes the new hash. */
30
+ async replaceActiveChallenge(record) {
31
+ await this.execute(async () => {
32
+ this.assertRecord(record);
33
+ if (record.consumedAt !== '' || record.revokedAt !== '') {
34
+ throw this.error('RECORD_INVALID');
35
+ }
36
+ const document = this.settings.codec.encode(Object.freeze({ ...record }));
37
+ const decoded = this.decode(document);
38
+ if (Object.keys(record).some((field) => (Reflect.get(record, field) !== Reflect.get(decoded, field)))) {
39
+ throw this.error('MAPPING_INVALID');
40
+ }
41
+ await this.collection().updateMany(this.active(record.purpose), {
42
+ $set: { ...this.stamp(record.createdAt), revokedAt: record.createdAt },
43
+ }, this.options());
44
+ await this.collection().insertOne(document, this.options());
45
+ });
46
+ }
47
+ /** Atomically consumes the exact subject/hash/purpose grant; a failed outer transaction restores it. */
48
+ async consumeActiveChallenge(tokenHash, purpose, consumedAt) {
49
+ return this.execute(async () => {
50
+ if (typeof tokenHash !== 'string' || !/^[a-f0-9]{64}$/u.test(tokenHash)
51
+ || !this.date(consumedAt) || !this.purpose(purpose)) {
52
+ throw this.error('CONSUME_INVALID');
53
+ }
54
+ const document = await this.collection().findOneAndUpdate({
55
+ ...this.active(purpose), tokenHash: tokenHash, expiresAt: { $gt: consumedAt },
56
+ }, { $set: { ...this.stamp(consumedAt), consumedAt: consumedAt } }, {
57
+ ...this.options(), returnDocument: 'after', includeResultMetadata: false,
58
+ });
59
+ if (!document) {
60
+ return null;
61
+ }
62
+ const record = this.decode(document);
63
+ if (record.tokenHash !== tokenHash || record.purpose !== purpose || record.consumedAt !== consumedAt
64
+ || record.revokedAt !== '' || record.expiresAt <= consumedAt) {
65
+ throw this.error('MAPPING_INVALID');
66
+ }
67
+ return record;
68
+ });
69
+ }
70
+ /** Revokes one purpose without touching foreign subjects or already-terminal grants. */
71
+ async revokeSubjectChallenges(subjectId, purpose, revokedAt) {
72
+ await this.execute(async () => {
73
+ if (subjectId !== this.settings.subjectId || !this.purpose(purpose) || !this.date(revokedAt)) {
74
+ throw this.error('REVOCATION_INVALID');
75
+ }
76
+ await this.collection().updateMany(this.active(purpose), {
77
+ $set: { ...this.stamp(revokedAt), revokedAt: revokedAt },
78
+ }, this.options());
79
+ });
80
+ }
81
+ /** Checks session ownership before invoking the trusted account fence, preserving only safe driver retry labels. */
82
+ async execute(task) {
83
+ const session = this.settings.session;
84
+ const concern = session?.transaction?.options?.readConcern;
85
+ if (!session?.inTransaction() || session.transaction.options.writeConcern?.w !== 'majority'
86
+ || (typeof concern === 'string' ? concern : concern?.level) !== 'snapshot') {
87
+ throw this.error('OWNING_TRANSACTION_REQUIRED');
88
+ }
89
+ try {
90
+ // The driver rejects a foreign MongoClient session before dispatching this indexed, content-free probe.
91
+ await this.collection().findOne({ _id: { $in: [] } }, this.options());
92
+ if (await this.settings.lockSubject(this.settings.subjectId, session) !== true) {
93
+ throw this.error('SUBJECT_NOT_ELIGIBLE');
94
+ }
95
+ return await task();
96
+ }
97
+ catch (error) {
98
+ if (error instanceof mongoose_1.mongo.MongoError && error.hasErrorLabel('TransientTransactionError')) {
99
+ const retryable = new mongoose_1.mongo.MongoError('DyNTS|ACCOUNT_CHALLENGE_TRANSACTION|FAILED');
100
+ retryable.addErrorLabel('TransientTransactionError');
101
+ throw retryable;
102
+ }
103
+ if (error instanceof Error && this.ownedErrors.has(error)) {
104
+ throw error;
105
+ }
106
+ throw this.error('FAILED');
107
+ }
108
+ }
109
+ /** Ensures trusted metadata conversion cannot substitute canonical persisted challenge authority. */
110
+ decode(document) {
111
+ const record = this.settings.codec.decode(document);
112
+ this.assertRecord(record);
113
+ for (const field of PROTECTED_FIELDS.filter((entry) => entry !== '_id' && entry !== 'createdAt')) {
114
+ if (document[field] !== Reflect.get(record, field)) {
115
+ throw this.error('MAPPING_INVALID');
116
+ }
117
+ }
118
+ return record;
119
+ }
120
+ /** Validates the canonical hash-only record after physical storage mapping, never echoing rejected data. */
121
+ assertRecord(record) {
122
+ if (record?.subjectId !== this.settings.subjectId || !this.subject(record.challengeId)
123
+ || !this.purpose(record.purpose) || typeof record.tokenHash !== 'string'
124
+ || !/^[a-f0-9]{64}$/u.test(record.tokenHash)
125
+ || !this.date(record.createdAt) || !this.date(record.expiresAt) || record.expiresAt <= record.createdAt
126
+ || (record.consumedAt !== '' && !this.date(record.consumedAt))
127
+ || (record.revokedAt !== '' && !this.date(record.revokedAt))) {
128
+ throw this.error('RECORD_INVALID');
129
+ }
130
+ }
131
+ /** Keeps audit-field hooks from replacing security state or injecting Mongo update paths. */
132
+ stamp(at) {
133
+ const fields = this.settings.codec.stamp(at, this.settings.subjectId);
134
+ if (!fields || typeof fields !== 'object' || Array.isArray(fields)
135
+ || Object.keys(fields).some((key) => PROTECTED_FIELDS.includes(key)
136
+ || key.startsWith('$') || key.includes('.') || key.includes('\0'))) {
137
+ throw this.error('STAMP_INVALID');
138
+ }
139
+ return fields;
140
+ }
141
+ /** Uses immutable adapter authority, never a subject discovered by looking up a token. */
142
+ active(purpose) {
143
+ return { subjectId: this.settings.subjectId, purpose: purpose, consumedAt: '', revokedAt: '' };
144
+ }
145
+ /** Passes the same caller-owned session and operation bound to every database call. */
146
+ options() {
147
+ return { session: this.settings.session, maxTimeMS: this.settings.maxOperationTimeMs };
148
+ }
149
+ /** Resolves only the caller's already-provisioned collection on the exact connection. */
150
+ collection() {
151
+ return this.settings.connection.db.collection(this.settings.collectionName);
152
+ }
153
+ /** Requires the fixed ISO representation used by challenge services for safe indexed date comparisons. */
154
+ date(value) {
155
+ return typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(value)
156
+ && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
157
+ }
158
+ /** Bounds opaque server-derived identifiers without imposing a product naming convention. */
159
+ subject(value) {
160
+ return typeof value === 'string' && value.length > 0 && value.length <= 256 && !value.includes('\0');
161
+ }
162
+ /** Restricts issuance, consumption and revocation to the shared closed purpose vocabulary. */
163
+ purpose(value) {
164
+ return Object.values(account_challenge_purpose_type_enum_1.DyNTS_AccountChallengePurpose_Type).includes(value);
165
+ }
166
+ /** Produces stable diagnostics without identifiers, token hashes, database commands or callback messages. */
167
+ error(code) {
168
+ const error = new Error(`DyNTS|ACCOUNT_CHALLENGE_TRANSACTION|${code}`);
169
+ this.ownedErrors.add(error);
170
+ return error;
171
+ }
172
+ }
173
+ exports.DyNTS_AccountChallengeTransaction_MongoAdapter = DyNTS_AccountChallengeTransaction_MongoAdapter;
174
+ //# sourceMappingURL=account-challenge-transaction.mongo-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-challenge-transaction.mongo-adapter.js","sourceRoot":"","sources":["../../../src/_modules/account-security/account-challenge-transaction.mongo-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { DyNTS_AccountSessionRecord_Interface } from './_models/account-session-record.interface';
2
+ import { DyNTS_AccountSessionTransactionSettings_Interface } from './_models/account-session-transaction-settings.interface';
3
+ /**
4
+ * Opt-in authorization write fence for the existing opaque-session service and canonical persisted session fields.
5
+ * A caller owns collection readiness, subject mapping and the snapshot/majority business transaction.
6
+ * Every failure must abort that transaction. This store never stores raw credentials or creates sessions.
7
+ */
8
+ export declare class DyNTS_AccountSessionTransaction_MongoStore {
9
+ private readonly settings;
10
+ private readonly ownedErrors;
11
+ /** Captures only trusted persistence configuration, not browser-supplied authority. */
12
+ constructor(settings: DyNTS_AccountSessionTransactionSettings_Interface);
13
+ /**
14
+ * Called with a record just authenticated by the existing session service, not cached request claims.
15
+ * Advances only persistence revision, never token generation/hash/expiry. Concurrent refresh may require retry;
16
+ * a stale token or snapshot is never silently upgraded to the replacement credential.
17
+ */
18
+ lockAuthenticatedSession(record: Readonly<DyNTS_AccountSessionRecord_Interface>): Promise<boolean>;
19
+ /** Fails closed on malformed persisted authority and safe-integer overflow before any subject mutation. */
20
+ private assertRecord;
21
+ /** Retains stable failure categories without account IDs, hashes, commands or callback diagnostics. */
22
+ private error;
23
+ }
24
+ //# sourceMappingURL=account-session-transaction.mongo-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-session-transaction.mongo-store.d.ts","sourceRoot":"","sources":["../../../src/_modules/account-security/account-session-transaction.mongo-store.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oCAAoC,EAAE,MAAM,4CAA4C,CAAC;AAClG,OAAO,EACL,iDAAiD,EAClD,MAAM,0DAA0D,CAAC;AAElE;;;;GAIG;AACH,qBAAa,0CAA0C;IACrD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoD;IAC7E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiC;IAE7D,uFAAuF;gBAC3E,QAAQ,EAAE,iDAAiD;IAUvE;;;;OAIG;IACU,wBAAwB,CAAC,MAAM,EAAE,QAAQ,CAAC,oCAAoC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IA0D/G,2GAA2G;IAC3G,OAAO,CAAC,YAAY;IAgBpB,uGAAuG;IACvG,OAAO,CAAC,KAAK;CAOd"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyNTS_AccountSessionTransaction_MongoStore = void 0;
4
+ const mongoose_1 = require("mongoose");
5
+ const account_session_state_type_enum_1 = require("./_enums/account-session-state.type-enum");
6
+ /**
7
+ * Opt-in authorization write fence for the existing opaque-session service and canonical persisted session fields.
8
+ * A caller owns collection readiness, subject mapping and the snapshot/majority business transaction.
9
+ * Every failure must abort that transaction. This store never stores raw credentials or creates sessions.
10
+ */
11
+ class DyNTS_AccountSessionTransaction_MongoStore {
12
+ settings;
13
+ ownedErrors = new WeakSet();
14
+ /** Captures only trusted persistence configuration, not browser-supplied authority. */
15
+ constructor(settings) {
16
+ if (!settings?.connection || !settings.session || typeof settings.lockSubject !== 'function'
17
+ || typeof settings.collectionName !== 'string' || !/^[A-Za-z][A-Za-z0-9_]{0,119}$/u.test(settings.collectionName)
18
+ || !Number.isSafeInteger(settings.maxOperationTimeMs) || settings.maxOperationTimeMs < 1
19
+ || settings.maxOperationTimeMs > 2_147_483_647) {
20
+ throw this.error('SETTINGS_INVALID');
21
+ }
22
+ this.settings = Object.freeze({ ...settings });
23
+ }
24
+ /**
25
+ * Called with a record just authenticated by the existing session service, not cached request claims.
26
+ * Advances only persistence revision, never token generation/hash/expiry. Concurrent refresh may require retry;
27
+ * a stale token or snapshot is never silently upgraded to the replacement credential.
28
+ */
29
+ async lockAuthenticatedSession(record) {
30
+ this.assertRecord(record);
31
+ const session = this.settings.session;
32
+ const concern = session?.transaction?.options?.readConcern;
33
+ if (!session?.inTransaction() || session.transaction.options.writeConcern?.w !== 'majority'
34
+ || (typeof concern === 'string' ? concern : concern?.level) !== 'snapshot') {
35
+ throw this.error('OWNING_TRANSACTION_REQUIRED');
36
+ }
37
+ try {
38
+ const collection = this.settings.connection.db.collection(this.settings.collectionName);
39
+ const options = {
40
+ session: session, maxTimeMS: this.settings.maxOperationTimeMs,
41
+ };
42
+ // Validate the actual owning MongoClient before allowing a subject callback to write anything.
43
+ await collection.findOne({ _id: { $in: [] } }, options);
44
+ if (await this.settings.lockSubject(Object.freeze({
45
+ subjectId: record.subjectId, sessionId: record.sessionId, familyId: record.familyId,
46
+ authorizationVersion: record.authorizationVersion,
47
+ }), session) !== true) {
48
+ throw this.error('SUBJECT_NOT_ELIGIBLE');
49
+ }
50
+ const result = await collection.updateOne({
51
+ subjectId: record.subjectId, sessionId: record.sessionId, familyId: record.familyId,
52
+ authorizationVersion: record.authorizationVersion, accessTokenHash: record.accessTokenHash,
53
+ accessExpiresAt: record.accessExpiresAt, revision: record.revision, generation: record.generation,
54
+ state: account_session_state_type_enum_1.DyNTS_AccountSessionState_Type.active, revokedAt: '', revocationReason: '',
55
+ $expr: { $gt: [
56
+ { $convert: { input: '$accessExpiresAt', to: 'date', onError: null, onNull: null } }, '$$NOW',
57
+ ] },
58
+ }, { $inc: { revision: 1 } }, options);
59
+ if (result.modifiedCount !== 1) {
60
+ throw this.error('SESSION_NOT_ELIGIBLE');
61
+ }
62
+ return true;
63
+ }
64
+ catch (error) {
65
+ if (error instanceof mongoose_1.mongo.MongoError && error.hasErrorLabel('TransientTransactionError')) {
66
+ const retryable = new mongoose_1.mongo.MongoError('DyNTS|ACCOUNT_SESSION_TRANSACTION|FAILED');
67
+ retryable.addErrorLabel('TransientTransactionError');
68
+ throw retryable;
69
+ }
70
+ if (error instanceof Error && this.ownedErrors.has(error)) {
71
+ throw error;
72
+ }
73
+ throw this.error('FAILED');
74
+ }
75
+ }
76
+ /** Fails closed on malformed persisted authority and safe-integer overflow before any subject mutation. */
77
+ assertRecord(record) {
78
+ if (!record || ![record.subjectId, record.sessionId, record.familyId].every((id) => (typeof id === 'string' && id.length > 0 && id.length <= 256 && !id.includes('\0'))) || ![record.revision, record.generation, record.authorizationVersion].every((value) => (Number.isSafeInteger(value) && value >= 0)) || record.revision >= Number.MAX_SAFE_INTEGER || record.state !== account_session_state_type_enum_1.DyNTS_AccountSessionState_Type.active
79
+ || record.revokedAt !== '' || record.revocationReason !== ''
80
+ || typeof record.accessTokenHash !== 'string' || !/^[a-f0-9]{64}$/u.test(record.accessTokenHash)
81
+ || typeof record.accessExpiresAt !== 'string'
82
+ || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(record.accessExpiresAt)
83
+ || !Number.isFinite(Date.parse(record.accessExpiresAt))
84
+ || new Date(record.accessExpiresAt).toISOString() !== record.accessExpiresAt) {
85
+ throw this.error('RECORD_INVALID');
86
+ }
87
+ }
88
+ /** Retains stable failure categories without account IDs, hashes, commands or callback diagnostics. */
89
+ error(code) {
90
+ const error = new Error(`DyNTS|ACCOUNT_SESSION_TRANSACTION|${code}`);
91
+ this.ownedErrors.add(error);
92
+ return error;
93
+ }
94
+ }
95
+ exports.DyNTS_AccountSessionTransaction_MongoStore = DyNTS_AccountSessionTransaction_MongoStore;
96
+ //# sourceMappingURL=account-session-transaction.mongo-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-session-transaction.mongo-store.js","sourceRoot":"","sources":["../../../src/_modules/account-security/account-session-transaction.mongo-store.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { DyNTS_AccountSessionClaims_Interface } from './_models/account-session-claims.interface';
2
2
  import { DyNTS_AccountSessionContext_Interface } from './_models/account-session-context.interface';
3
+ import { DyNTS_AccountSessionRecord_Interface } from './_models/account-session-record.interface';
3
4
  import { DyNTS_AccountSessionSettings_Interface } from './_models/account-session-settings.interface';
4
5
  import { DyNTS_AccountSessionTokenPair_Interface } from './_models/account-session-token-pair.interface';
5
6
  import { DyNTS_AccountSessionView_Interface } from './_models/account-session-view.interface';
@@ -19,6 +20,17 @@ export declare class DyNTS_AccountSession_ControlService {
19
20
  issueSession(subjectId: string, authorizationVersion: number, context: DyNTS_AccountSessionContext_Interface): Promise<DyNTS_AccountSessionTokenPair_Interface>;
20
21
  /** Resolves an opaque access token through the server-side active-session record. */
21
22
  authenticateAccessToken(accessToken: string): Promise<DyNTS_AccountSessionClaims_Interface>;
23
+ /**
24
+ * Reauthenticates the actual access credential and fences its exact record in the caller's business transaction.
25
+ * The callback must write-fence both the subject authorization version and session, returning true only on success.
26
+ * Use the shared Mongo transaction store; propagate failures and keep every protected write in that transaction.
27
+ * This is opt-in: ordinary authentication retains its existing read-only behavior.
28
+ */
29
+ authenticateAccessTokenForMutation(accessToken: string, lockSession: (record: Readonly<DyNTS_AccountSessionRecord_Interface>) => Promise<boolean>): Promise<DyNTS_AccountSessionClaims_Interface>;
30
+ /** Resolves the existing token/hash contract once, before either read-only or write-fenced authentication. */
31
+ private authenticateSessionRecord;
32
+ /** Keeps the public claims projection identical for both authentication modes; no hashes leave this boundary. */
33
+ private toClaims;
22
34
  /** Rotates a one-time refresh token; replay revokes the complete token family. */
23
35
  rotateRefreshToken(refreshToken: string, context: DyNTS_AccountSessionContext_Interface): Promise<DyNTS_AccountSessionTokenPair_Interface>;
24
36
  /** Revokes one server-side session. */
@@ -1 +1 @@
1
- {"version":3,"file":"account-session.control-service.d.ts","sourceRoot":"","sources":["../../../src/_modules/account-security/account-session.control-service.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,oCAAoC,EAAE,MAAM,4CAA4C,CAAC;AAClG,OAAO,EAAE,qCAAqC,EAAE,MAAM,6CAA6C,CAAC;AAEpG,OAAO,EAAE,sCAAsC,EAAE,MAAM,8CAA8C,CAAC;AACtG,OAAO,EAAE,uCAAuC,EAAE,MAAM,gDAAgD,CAAC;AACzG,OAAO,EAAE,kCAAkC,EAAE,MAAM,0CAA0C,CAAC;AAc9F;;GAEG;AACH,qBAAa,mCAAmC;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;IAChE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IAEnC,8EAA8E;gBAClE,GAAG,EAAE,sCAAsC;IAUvD,qFAAqF;IACxE,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,oBAAoB,EAAE,MAAM,EAC5B,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,uCAAuC,CAAC;IAkCnD,qFAAqF;IACxE,uBAAuB,CAClC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,oCAAoC,CAAC;IA8BhD,kFAAkF;IACrE,kBAAkB,CAC7B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,uCAAuC,CAAC;IAiFnD,uCAAuC;IAC1B,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhF,sDAAsD;IACzC,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3F,mEAAmE;IACtD,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,kCAAkC,EAAE,CAAC;IAmBlG,OAAO,CAAC,cAAc;IAoDtB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,iBAAiB;CAS1B"}
1
+ {"version":3,"file":"account-session.control-service.d.ts","sourceRoot":"","sources":["../../../src/_modules/account-security/account-session.control-service.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,oCAAoC,EAAE,MAAM,4CAA4C,CAAC;AAClG,OAAO,EAAE,qCAAqC,EAAE,MAAM,6CAA6C,CAAC;AACpG,OAAO,EAAE,oCAAoC,EAAE,MAAM,4CAA4C,CAAC;AAClG,OAAO,EAAE,sCAAsC,EAAE,MAAM,8CAA8C,CAAC;AACtG,OAAO,EAAE,uCAAuC,EAAE,MAAM,gDAAgD,CAAC;AACzG,OAAO,EAAE,kCAAkC,EAAE,MAAM,0CAA0C,CAAC;AAc9F;;GAEG;AACH,qBAAa,mCAAmC;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;IAChE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IAEnC,8EAA8E;gBAClE,GAAG,EAAE,sCAAsC;IAUvD,qFAAqF;IACxE,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,oBAAoB,EAAE,MAAM,EAC5B,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,uCAAuC,CAAC;IAkCnD,qFAAqF;IACxE,uBAAuB,CAClC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,oCAAoC,CAAC;IAIhD;;;;;OAKG;IACU,kCAAkC,CAC7C,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,oCAAoC,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,GACxF,OAAO,CAAC,oCAAoC,CAAC;IAgBhD,8GAA8G;YAChG,yBAAyB;IAyBvC,iHAAiH;IACjH,OAAO,CAAC,QAAQ;IAOhB,kFAAkF;IACrE,kBAAkB,CAC7B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,qCAAqC,GAC7C,OAAO,CAAC,uCAAuC,CAAC;IAiFnD,uCAAuC;IAC1B,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhF,sDAAsD;IACzC,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3F,mEAAmE;IACtD,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,kCAAkC,EAAE,CAAC;IAmBlG,OAAO,CAAC,cAAc;IAoDtB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,iBAAiB;CAS1B"}
@@ -60,6 +60,29 @@ class DyNTS_AccountSession_ControlService {
60
60
  }
61
61
  /** Resolves an opaque access token through the server-side active-session record. */
62
62
  async authenticateAccessToken(accessToken) {
63
+ return this.toClaims(await this.authenticateSessionRecord(accessToken));
64
+ }
65
+ /**
66
+ * Reauthenticates the actual access credential and fences its exact record in the caller's business transaction.
67
+ * The callback must write-fence both the subject authorization version and session, returning true only on success.
68
+ * Use the shared Mongo transaction store; propagate failures and keep every protected write in that transaction.
69
+ * This is opt-in: ordinary authentication retains its existing read-only behavior.
70
+ */
71
+ async authenticateAccessTokenForMutation(accessToken, lockSession) {
72
+ if (typeof lockSession !== 'function') {
73
+ throw this.buildUnauthorized('SESSION_MUTATION_FENCE_REQUIRED');
74
+ }
75
+ const record = await this.authenticateSessionRecord(accessToken);
76
+ const snapshot = Object.freeze({
77
+ ...record, context: Object.freeze({ ...record.context }),
78
+ });
79
+ if (await lockSession(snapshot) !== true) {
80
+ throw this.buildUnauthorized('SESSION_MUTATION_NOT_AUTHORIZED');
81
+ }
82
+ return this.toClaims(snapshot);
83
+ }
84
+ /** Resolves the existing token/hash contract once, before either read-only or write-fenced authentication. */
85
+ async authenticateSessionRecord(accessToken) {
63
86
  if (!accessToken || accessToken.length > 512) {
64
87
  throw this.buildUnauthorized('ACCESS_TOKEN_INVALID');
65
88
  }
@@ -75,10 +98,12 @@ class DyNTS_AccountSession_ControlService {
75
98
  || session.authorizationVersion < 0) {
76
99
  throw this.buildUnauthorized('ACCESS_TOKEN_INVALID');
77
100
  }
101
+ return session;
102
+ }
103
+ /** Keeps the public claims projection identical for both authentication modes; no hashes leave this boundary. */
104
+ toClaims(session) {
78
105
  return {
79
- subjectId: session.subjectId,
80
- sessionId: session.sessionId,
81
- familyId: session.familyId,
106
+ subjectId: session.subjectId, sessionId: session.sessionId, familyId: session.familyId,
82
107
  authorizationVersion: session.authorizationVersion,
83
108
  };
84
109
  }