@adaptic/backend-legacy 0.0.83 → 0.0.84

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.
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deepMerge = void 0;
4
+ const isPlainObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
5
+ /**
6
+ * Pure, non-mutating deep merge.
7
+ * - Plain objects merge recursively.
8
+ * - Arrays and scalars: right side replaces.
9
+ * - `undefined` on the right is treated as absent (left value retained).
10
+ * - `null` on the right overrides to null.
11
+ *
12
+ * Used by effectivePolicy() and effectiveLlmConfig() to deep-merge
13
+ * Organization → Fund → BrokerageAccount policy layers per charter §2.2.
14
+ * Consumers must use this helper; do not re-implement merge semantics.
15
+ */
16
+ const deepMerge = (left, right) => {
17
+ const out = { ...left };
18
+ for (const key of Object.keys(right)) {
19
+ const rv = right[key];
20
+ if (rv === undefined)
21
+ continue;
22
+ const lv = out[key];
23
+ if (isPlainObject(lv) && isPlainObject(rv)) {
24
+ out[key] = (0, exports.deepMerge)(lv, rv);
25
+ }
26
+ else {
27
+ out[key] = rv;
28
+ }
29
+ }
30
+ return out;
31
+ };
32
+ exports.deepMerge = deepMerge;
33
+ //# sourceMappingURL=deep-merge.js.map
@@ -0,0 +1,15 @@
1
+ type Plain = Record<string, unknown>;
2
+ /**
3
+ * Pure, non-mutating deep merge.
4
+ * - Plain objects merge recursively.
5
+ * - Arrays and scalars: right side replaces.
6
+ * - `undefined` on the right is treated as absent (left value retained).
7
+ * - `null` on the right overrides to null.
8
+ *
9
+ * Used by effectivePolicy() and effectiveLlmConfig() to deep-merge
10
+ * Organization → Fund → BrokerageAccount policy layers per charter §2.2.
11
+ * Consumers must use this helper; do not re-implement merge semantics.
12
+ */
13
+ export declare const deepMerge: <T extends Plain, U extends Plain>(left: T, right: U) => T & U;
14
+ export {};
15
+ //# sourceMappingURL=deep-merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep-merge.d.ts","sourceRoot":"","sources":["../../src/helpers/deep-merge.ts"],"names":[],"mappings":"AAAA,KAAK,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAKrC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,KAAK,EAAE,CAAC,SAAS,KAAK,EACxD,MAAM,CAAC,EACP,OAAO,CAAC,KACP,CAAC,GAAG,CAaN,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep-merge.js","sourceRoot":"","sources":["../../src/helpers/deep-merge.ts"],"names":[],"mappings":";;;AAEA,MAAM,aAAa,GAAG,CAAC,CAAU,EAAc,EAAE,CAC/C,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAE3D;;;;;;;;;;GAUG;AACI,MAAM,SAAS,GAAG,CACvB,IAAO,EACP,KAAQ,EACD,EAAE;IACT,MAAM,GAAG,GAAU,EAAE,GAAG,IAAI,EAAE,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,EAAE,KAAK,SAAS;YAAE,SAAS;QAC/B,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACpB,IAAI,aAAa,CAAC,EAAE,CAAC,IAAI,aAAa,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,GAAG,CAAC,GAAG,IAAA,iBAAS,EAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,GAAY,CAAC;AACtB,CAAC,CAAC;AAhBW,QAAA,SAAS,aAgBpB"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.effectiveLlmConfig = effectiveLlmConfig;
4
+ const deep_merge_1 = require("./deep-merge.cjs");
5
+ const llm_configuration_1 = require("../types/llm-configuration.cjs");
6
+ /**
7
+ * Deep-merges DEFAULT_LLM_CONFIGURATION → Org.llmDefaults →
8
+ * Fund.llmOverrides into a single frozen `LlmConfigurationJson`.
9
+ *
10
+ * `apiKeys.<provider>` values are EncryptedApiKey envelopes; this
11
+ * helper does NOT decrypt. Use `decryptApiKey()` from
12
+ * `helpers/kms-envelope` with appropriate role gating per spec §4.3.
13
+ */
14
+ function effectiveLlmConfig(fund) {
15
+ let cfg = { ...llm_configuration_1.DEFAULT_LLM_CONFIGURATION };
16
+ if (fund.organization.llmDefaults) {
17
+ cfg = (0, deep_merge_1.deepMerge)(cfg, fund.organization.llmDefaults);
18
+ }
19
+ if (fund.llmOverrides) {
20
+ cfg = (0, deep_merge_1.deepMerge)(cfg, fund.llmOverrides);
21
+ }
22
+ return Object.freeze(cfg);
23
+ }
24
+ //# sourceMappingURL=effective-llm-config.js.map
@@ -0,0 +1,28 @@
1
+ import { type LlmConfigurationJson } from '../types/llm-configuration';
2
+ /**
3
+ * The relation shape `effectiveLlmConfig()` requires.
4
+ *
5
+ * Note: there is no overlay tier (LLM config is not event-driven).
6
+ * Precedence is a two-level chain.
7
+ */
8
+ interface FundWithLlmContext {
9
+ id: string;
10
+ llmOverrides: LlmConfigurationJson | null;
11
+ organization: {
12
+ id: string;
13
+ llmDefaults: LlmConfigurationJson | null;
14
+ };
15
+ }
16
+ /**
17
+ * Deep-merges DEFAULT_LLM_CONFIGURATION → Org.llmDefaults →
18
+ * Fund.llmOverrides into a single frozen `LlmConfigurationJson`.
19
+ *
20
+ * `apiKeys.<provider>` values are EncryptedApiKey envelopes; this
21
+ * helper does NOT decrypt. Use `decryptApiKey()` from
22
+ * `helpers/kms-envelope` with appropriate role gating per spec §4.3.
23
+ */
24
+ export declare function effectiveLlmConfig(fund: FundWithLlmContext): Required<Omit<LlmConfigurationJson, 'apiKeys'>> & {
25
+ apiKeys: NonNullable<LlmConfigurationJson['apiKeys']>;
26
+ };
27
+ export {};
28
+ //# sourceMappingURL=effective-llm-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effective-llm-config.d.ts","sourceRoot":"","sources":["../../src/helpers/effective-llm-config.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,4BAA4B,CAAC;AAEpC;;;;;GAKG;AACH,UAAU,kBAAkB;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,YAAY,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,oBAAoB,GAAG,IAAI,CAAA;KAAE,CAAC;CACxE;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,GAAG,QAAQ,CACpE,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,CACtC,GAAG;IACF,OAAO,EAAE,WAAW,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC,CAAC;CACvD,CAeA"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effective-llm-config.js","sourceRoot":"","sources":["../../src/helpers/effective-llm-config.ts"],"names":[],"mappings":";;AA0BA,gDAmBC;AA7CD,6CAAyC;AACzC,kEAGoC;AAcpC;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAAC,IAAwB;IAKzD,IAAI,GAAG,GAAyB,EAAE,GAAG,6CAAyB,EAAE,CAAC;IACjE,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;QAClC,GAAG,GAAG,IAAA,sBAAS,EACb,GAA8B,EAC9B,IAAI,CAAC,YAAY,CAAC,WAAsC,CACjC,CAAC;IAC5B,CAAC;IACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,GAAG,GAAG,IAAA,sBAAS,EACb,GAA8B,EAC9B,IAAI,CAAC,YAAuC,CACrB,CAAC;IAC5B,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAA0C,CAAC;AACrE,CAAC"}
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.brokerageAccountWithPolicyContextSelectionSet = exports.EffectivePolicyContextError = void 0;
4
+ exports.effectivePolicy = effectivePolicy;
5
+ const deep_merge_1 = require("./deep-merge.cjs");
6
+ const trading_policy_1 = require("../types/trading-policy.cjs");
7
+ /**
8
+ * Thrown when a caller invokes effectivePolicy() with a
9
+ * BrokerageAccount whose required relations (`fund.organization`,
10
+ * `fund.policyOverlays`) were not loaded by the selection set. We do
11
+ * not silently fall back to defaults — silent fall-back hides bugs.
12
+ */
13
+ class EffectivePolicyContextError extends Error {
14
+ constructor(field) {
15
+ super(`effectivePolicy(): missing relation \`${field}\`. ` +
16
+ `Fetch with brokerageAccountWithPolicyContextSelectionSet ` +
17
+ `(see @adaptic/backend-legacy docs).`);
18
+ this.name = 'EffectivePolicyContextError';
19
+ }
20
+ }
21
+ exports.EffectivePolicyContextError = EffectivePolicyContextError;
22
+ /**
23
+ * The 14 BrokerageAccount column fields preserved per charter §2.2.
24
+ * Read directly from the entity, not from the JSON merge.
25
+ */
26
+ const BA_COLUMN_FIELDS = [
27
+ 'enablePortfolioTrailingStop',
28
+ 'portfolioTrailPercent',
29
+ 'portfolioProfitThresholdPercent',
30
+ 'reducedPortfolioTrailPercent',
31
+ 'defaultTrailingStopPercentage100',
32
+ 'firstTrailReductionThreshold100',
33
+ 'secondTrailReductionThreshold100',
34
+ 'firstReducedTrailPercentage100',
35
+ 'secondReducedTrailPercentage100',
36
+ 'minimumPriceChangePercent100',
37
+ 'cryptoTradingEnabled',
38
+ 'cryptoTradingPairs',
39
+ 'tradeAllocationPct',
40
+ 'cryptoTradeAllocationPct',
41
+ ];
42
+ const severityRank = {
43
+ LOW: 0,
44
+ MEDIUM: 1,
45
+ HIGH: 2,
46
+ CRITICAL: 3,
47
+ };
48
+ /**
49
+ * Canonical selection-set string for `adaptic.brokerageAccount.get(id, …)`.
50
+ * Loads fund + fund.organization + fund.policyOverlays in one query.
51
+ *
52
+ * Consumers should pass this verbatim to fetch a BrokerageAccount
53
+ * suitable for effectivePolicy().
54
+ */
55
+ exports.brokerageAccountWithPolicyContextSelectionSet = `
56
+ id
57
+ enablePortfolioTrailingStop
58
+ portfolioTrailPercent
59
+ portfolioProfitThresholdPercent
60
+ reducedPortfolioTrailPercent
61
+ defaultTrailingStopPercentage100
62
+ firstTrailReductionThreshold100
63
+ secondTrailReductionThreshold100
64
+ firstReducedTrailPercentage100
65
+ secondReducedTrailPercentage100
66
+ minimumPriceChangePercent100
67
+ cryptoTradingEnabled
68
+ cryptoTradingPairs
69
+ tradeAllocationPct
70
+ cryptoTradeAllocationPct
71
+ fund {
72
+ id
73
+ tradingOverrides
74
+ policyOverlays
75
+ organization { id tradingDefaults }
76
+ }
77
+ `;
78
+ /**
79
+ * Deep-merges DEFAULT_TRADING_POLICY → Org.tradingDefaults →
80
+ * Fund.tradingOverrides → active Fund.policyOverlays (severity-sorted)
81
+ * → 14 BrokerageAccount column fields into a single canonical
82
+ * `Required<TradingPolicyJson>` plus the 14 column overrides.
83
+ *
84
+ * Consumers MUST use this helper — do not re-implement the precedence
85
+ * chain. The result is frozen.
86
+ *
87
+ * @throws EffectivePolicyContextError if `fund.organization` or
88
+ * `fund.policyOverlays` is missing (selection-set bug).
89
+ */
90
+ function effectivePolicy(ba) {
91
+ var _a;
92
+ if (!ba.fund)
93
+ throw new EffectivePolicyContextError('fund');
94
+ if (!ba.fund.organization) {
95
+ throw new EffectivePolicyContextError('fund.organization');
96
+ }
97
+ if (ba.fund.policyOverlays === undefined) {
98
+ throw new EffectivePolicyContextError('fund.policyOverlays');
99
+ }
100
+ // 1) defaults
101
+ let policy = { ...trading_policy_1.DEFAULT_TRADING_POLICY };
102
+ // 2) Org defaults
103
+ if (ba.fund.organization.tradingDefaults) {
104
+ policy = (0, deep_merge_1.deepMerge)(policy, ba.fund.organization.tradingDefaults);
105
+ }
106
+ // 3) Fund overrides
107
+ if (ba.fund.tradingOverrides) {
108
+ policy = (0, deep_merge_1.deepMerge)(policy, ba.fund.tradingOverrides);
109
+ }
110
+ // 4) Active overlays (severity-sorted; CRITICAL last → highest precedence)
111
+ const now = new Date();
112
+ const active = ((_a = ba.fund.policyOverlays) !== null && _a !== void 0 ? _a : [])
113
+ .filter((o) => o.status === 'ACTIVE' &&
114
+ (o.expiresAt == null || new Date(o.expiresAt) > now))
115
+ .sort((a, b) => severityRank[a.severity] - severityRank[b.severity]);
116
+ for (const overlay of active) {
117
+ policy = (0, deep_merge_1.deepMerge)(policy, overlay.mutations);
118
+ }
119
+ // 5) BA column overrides (the 14 fields stay alongside the JSON)
120
+ const baCols = {};
121
+ for (const f of BA_COLUMN_FIELDS) {
122
+ baCols[f] = ba[f];
123
+ }
124
+ // 6) freeze and return
125
+ return Object.freeze({
126
+ ...policy,
127
+ ...baCols,
128
+ });
129
+ }
130
+ //# sourceMappingURL=effective-policy.js.map
@@ -0,0 +1,70 @@
1
+ import { type TradingPolicyJson } from '../types/trading-policy';
2
+ import type { PolicyOverlayEntry } from '../types/policy-overlay';
3
+ /**
4
+ * Thrown when a caller invokes effectivePolicy() with a
5
+ * BrokerageAccount whose required relations (`fund.organization`,
6
+ * `fund.policyOverlays`) were not loaded by the selection set. We do
7
+ * not silently fall back to defaults — silent fall-back hides bugs.
8
+ */
9
+ export declare class EffectivePolicyContextError extends Error {
10
+ constructor(field: string);
11
+ }
12
+ /**
13
+ * The 14 BrokerageAccount column fields preserved per charter §2.2.
14
+ * Read directly from the entity, not from the JSON merge.
15
+ */
16
+ declare const BA_COLUMN_FIELDS: readonly ["enablePortfolioTrailingStop", "portfolioTrailPercent", "portfolioProfitThresholdPercent", "reducedPortfolioTrailPercent", "defaultTrailingStopPercentage100", "firstTrailReductionThreshold100", "secondTrailReductionThreshold100", "firstReducedTrailPercentage100", "secondReducedTrailPercentage100", "minimumPriceChangePercent100", "cryptoTradingEnabled", "cryptoTradingPairs", "tradeAllocationPct", "cryptoTradeAllocationPct"];
17
+ type BACol = (typeof BA_COLUMN_FIELDS)[number];
18
+ /**
19
+ * The relation shape effectivePolicy() requires. Consumers must fetch
20
+ * with the selection set below to populate these correctly.
21
+ */
22
+ export interface BrokerageAccountWithPolicyContext {
23
+ id: string;
24
+ enablePortfolioTrailingStop: boolean;
25
+ portfolioTrailPercent: number;
26
+ portfolioProfitThresholdPercent: number;
27
+ reducedPortfolioTrailPercent: number;
28
+ defaultTrailingStopPercentage100: number;
29
+ firstTrailReductionThreshold100: number;
30
+ secondTrailReductionThreshold100: number;
31
+ firstReducedTrailPercentage100: number;
32
+ secondReducedTrailPercentage100: number;
33
+ minimumPriceChangePercent100: number;
34
+ cryptoTradingEnabled: boolean;
35
+ cryptoTradingPairs: string[];
36
+ tradeAllocationPct: number;
37
+ cryptoTradeAllocationPct: number;
38
+ fund: {
39
+ id: string;
40
+ tradingOverrides: TradingPolicyJson | null;
41
+ policyOverlays: PolicyOverlayEntry[] | null;
42
+ organization: {
43
+ id: string;
44
+ tradingDefaults: TradingPolicyJson | null;
45
+ };
46
+ };
47
+ }
48
+ /**
49
+ * Canonical selection-set string for `adaptic.brokerageAccount.get(id, …)`.
50
+ * Loads fund + fund.organization + fund.policyOverlays in one query.
51
+ *
52
+ * Consumers should pass this verbatim to fetch a BrokerageAccount
53
+ * suitable for effectivePolicy().
54
+ */
55
+ export declare const brokerageAccountWithPolicyContextSelectionSet = "\n id\n enablePortfolioTrailingStop\n portfolioTrailPercent\n portfolioProfitThresholdPercent\n reducedPortfolioTrailPercent\n defaultTrailingStopPercentage100\n firstTrailReductionThreshold100\n secondTrailReductionThreshold100\n firstReducedTrailPercentage100\n secondReducedTrailPercentage100\n minimumPriceChangePercent100\n cryptoTradingEnabled\n cryptoTradingPairs\n tradeAllocationPct\n cryptoTradeAllocationPct\n fund {\n id\n tradingOverrides\n policyOverlays\n organization { id tradingDefaults }\n }\n";
56
+ /**
57
+ * Deep-merges DEFAULT_TRADING_POLICY → Org.tradingDefaults →
58
+ * Fund.tradingOverrides → active Fund.policyOverlays (severity-sorted)
59
+ * → 14 BrokerageAccount column fields into a single canonical
60
+ * `Required<TradingPolicyJson>` plus the 14 column overrides.
61
+ *
62
+ * Consumers MUST use this helper — do not re-implement the precedence
63
+ * chain. The result is frozen.
64
+ *
65
+ * @throws EffectivePolicyContextError if `fund.organization` or
66
+ * `fund.policyOverlays` is missing (selection-set bug).
67
+ */
68
+ export declare function effectivePolicy(ba: BrokerageAccountWithPolicyContext): Required<TradingPolicyJson> & Record<BACol, unknown>;
69
+ export {};
70
+ //# sourceMappingURL=effective-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effective-policy.d.ts","sourceRoot":"","sources":["../../src/helpers/effective-policy.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EACV,kBAAkB,EAEnB,MAAM,yBAAyB,CAAC;AAEjC;;;;;GAKG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;gBACxC,KAAK,EAAE,MAAM;CAQ1B;AAED;;;GAGG;AACH,QAAA,MAAM,gBAAgB,sbAeZ,CAAC;AAEX,KAAK,KAAK,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C;;;GAGG;AACH,MAAM,WAAW,iCAAiC;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B,EAAE,OAAO,CAAC;IACrC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,+BAA+B,EAAE,MAAM,CAAC;IACxC,4BAA4B,EAAE,MAAM,CAAC;IACrC,gCAAgC,EAAE,MAAM,CAAC;IACzC,+BAA+B,EAAE,MAAM,CAAC;IACxC,gCAAgC,EAAE,MAAM,CAAC;IACzC,8BAA8B,EAAE,MAAM,CAAC;IACvC,+BAA+B,EAAE,MAAM,CAAC;IACxC,4BAA4B,EAAE,MAAM,CAAC;IACrC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wBAAwB,EAAE,MAAM,CAAC;IACjC,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,gBAAgB,EAAE,iBAAiB,GAAG,IAAI,CAAC;QAC3C,cAAc,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAC;QAC5C,YAAY,EAAE;YACZ,EAAE,EAAE,MAAM,CAAC;YACX,eAAe,EAAE,iBAAiB,GAAG,IAAI,CAAC;SAC3C,CAAC;KACH,CAAC;CACH;AASD;;;;;;GAMG;AACH,eAAO,MAAM,6CAA6C,kiBAsBzD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,iCAAiC,GACpC,QAAQ,CAAC,iBAAiB,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAuDtD"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effective-policy.js","sourceRoot":"","sources":["../../src/helpers/effective-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decryptApiKey = exports.encryptApiKey = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const kms_envelope_kms_adapter_1 = require("./kms-envelope.kms-adapter.cjs");
6
+ const requireKeyId = () => {
7
+ const k = process.env.KMS_KEY_ID;
8
+ if (!k) {
9
+ throw new Error('KMS_KEY_ID env var is required for kms-envelope');
10
+ }
11
+ return k;
12
+ };
13
+ /**
14
+ * Encrypts plaintext under a fresh per-record DEK wrapped by the
15
+ * configured KMS CMK. Returns the on-disk envelope shape.
16
+ */
17
+ const encryptApiKey = async (plaintext) => {
18
+ const keyId = requireKeyId();
19
+ const dek = (0, node_crypto_1.randomBytes)(32); // 256-bit DEK
20
+ const iv = (0, node_crypto_1.randomBytes)(12); // 96-bit IV for GCM
21
+ const cipher = (0, node_crypto_1.createCipheriv)('aes-256-gcm', dek, iv);
22
+ const ct = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
23
+ const authTag = cipher.getAuthTag();
24
+ const wrapped = await (0, kms_envelope_kms_adapter_1.kmsWrap)(dek, keyId);
25
+ return {
26
+ ciphertext: ct.toString('base64'),
27
+ iv: iv.toString('base64'),
28
+ authTag: authTag.toString('base64'),
29
+ keyId,
30
+ wrappedDek: wrapped.toString('base64'),
31
+ algorithm: 'AES-256-GCM',
32
+ createdAt: new Date().toISOString(),
33
+ };
34
+ };
35
+ exports.encryptApiKey = encryptApiKey;
36
+ /**
37
+ * Decrypts an EncryptedApiKey envelope. Throws on tampering,
38
+ * unsupported algorithm, or KMS unwrap failure.
39
+ */
40
+ const decryptApiKey = async (env) => {
41
+ if (env.algorithm !== 'AES-256-GCM') {
42
+ throw new Error(`Unsupported algorithm: ${env.algorithm}`);
43
+ }
44
+ const dek = await (0, kms_envelope_kms_adapter_1.kmsUnwrap)(Buffer.from(env.wrappedDek, 'base64'), env.keyId);
45
+ const iv = Buffer.from(env.iv, 'base64');
46
+ const authTag = Buffer.from(env.authTag, 'base64');
47
+ const ct = Buffer.from(env.ciphertext, 'base64');
48
+ const decipher = (0, node_crypto_1.createDecipheriv)('aes-256-gcm', dek, iv);
49
+ decipher.setAuthTag(authTag);
50
+ return Buffer.concat([decipher.update(ct), decipher.final()]).toString('utf8');
51
+ };
52
+ exports.decryptApiKey = decryptApiKey;
53
+ //# sourceMappingURL=kms-envelope.js.map
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Envelope-encrypted secret at rest. Stored as a JSON value inside
3
+ * `Organization.llmDefaults.apiKeys.<provider>` and
4
+ * `Fund.llmOverrides.apiKeys.<provider>` per charter §2.4 F6 and
5
+ * spec §4.3.
6
+ *
7
+ * Algorithm: AES-256-GCM with per-record IV. The DEK is generated
8
+ * per-record and wrapped by a KMS-managed CMK identified by `keyId`.
9
+ */
10
+ export interface EncryptedApiKey {
11
+ /** base64-encoded AES-GCM ciphertext */
12
+ ciphertext: string;
13
+ /** base64-encoded 12-byte IV */
14
+ iv: string;
15
+ /** base64-encoded 16-byte GCM auth tag */
16
+ authTag: string;
17
+ /** KMS key id used to wrap the DEK */
18
+ keyId: string;
19
+ /** base64-encoded KMS-wrapped DEK */
20
+ wrappedDek: string;
21
+ /** Locked to AES-256-GCM for now; future schemas extend this union. */
22
+ algorithm: 'AES-256-GCM';
23
+ /** ISO-8601 timestamp of when this envelope was created. */
24
+ createdAt: string;
25
+ }
26
+ /**
27
+ * Encrypts plaintext under a fresh per-record DEK wrapped by the
28
+ * configured KMS CMK. Returns the on-disk envelope shape.
29
+ */
30
+ export declare const encryptApiKey: (plaintext: string) => Promise<EncryptedApiKey>;
31
+ /**
32
+ * Decrypts an EncryptedApiKey envelope. Throws on tampering,
33
+ * unsupported algorithm, or KMS unwrap failure.
34
+ */
35
+ export declare const decryptApiKey: (env: EncryptedApiKey) => Promise<string>;
36
+ //# sourceMappingURL=kms-envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kms-envelope.d.ts","sourceRoot":"","sources":["../../src/helpers/kms-envelope.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,SAAS,EAAE,aAAa,CAAC;IACzB,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;CACnB;AAUD;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,WAAW,MAAM,KAChB,OAAO,CAAC,eAAe,CAiBzB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAU,KAAK,eAAe,KAAG,OAAO,CAAC,MAAM,CAaxE,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kms-envelope.js","sourceRoot":"","sources":["../../src/helpers/kms-envelope.ts"],"names":[],"mappings":";;;AAAA,6CAA4E;AAC5E,yEAAgE;AA4BhE,MAAM,YAAY,GAAG,GAAW,EAAE;IAChC,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACjC,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF;;;GAGG;AACI,MAAM,aAAa,GAAG,KAAK,EAChC,SAAiB,EACS,EAAE;IAC5B,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,GAAG,GAAG,IAAA,yBAAW,EAAC,EAAE,CAAC,CAAC,CAAC,cAAc;IAC3C,MAAM,EAAE,GAAG,IAAA,yBAAW,EAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB;IAChD,MAAM,MAAM,GAAG,IAAA,4BAAc,EAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC7E,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,MAAM,IAAA,kCAAO,EAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC1C,OAAO;QACL,UAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACjC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACzB,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACnC,KAAK;QACL,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACtC,SAAS,EAAE,aAAa;QACxB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;AACJ,CAAC,CAAC;AAnBW,QAAA,aAAa,iBAmBxB;AAEF;;;GAGG;AACI,MAAM,aAAa,GAAG,KAAK,EAAE,GAAoB,EAAmB,EAAE;IAC3E,IAAI,GAAG,CAAC,SAAS,KAAK,aAAa,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,IAAA,oCAAS,EAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9E,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACnD,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,IAAA,8BAAgB,EAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAC1D,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CACpE,MAAM,CACP,CAAC;AACJ,CAAC,CAAC;AAbW,QAAA,aAAa,iBAaxB"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ /**
3
+ * KMS adapter — wraps/unwraps the per-record Data Encryption Key (DEK).
4
+ *
5
+ * Unit tests mock this module to provide deterministic wrap/unwrap.
6
+ * The runtime implementation should wire to AWS KMS via
7
+ * `@aws-sdk/client-kms` (or GCP KMS via `@google-cloud/kms`) and
8
+ * be replaced via a build-time alias or runtime injection.
9
+ *
10
+ * The default exports throw so unintended use in production surfaces
11
+ * an obvious error rather than silently returning plaintext-as-wrapped.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.kmsUnwrap = exports.kmsWrap = void 0;
15
+ const kmsWrap = async (_dek, _keyId) => {
16
+ throw new Error('kmsWrap not wired to a real KMS provider. Mock this module in tests, ' +
17
+ 'or wire to AWS KMS via @aws-sdk/client-kms (or GCP KMS via @google-cloud/kms).');
18
+ };
19
+ exports.kmsWrap = kmsWrap;
20
+ const kmsUnwrap = async (_wrapped, _keyId) => {
21
+ throw new Error('kmsUnwrap not wired to a real KMS provider. Mock this module in tests, ' +
22
+ 'or wire to AWS KMS via @aws-sdk/client-kms (or GCP KMS via @google-cloud/kms).');
23
+ };
24
+ exports.kmsUnwrap = kmsUnwrap;
25
+ //# sourceMappingURL=kms-envelope.kms-adapter.js.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * KMS adapter — wraps/unwraps the per-record Data Encryption Key (DEK).
3
+ *
4
+ * Unit tests mock this module to provide deterministic wrap/unwrap.
5
+ * The runtime implementation should wire to AWS KMS via
6
+ * `@aws-sdk/client-kms` (or GCP KMS via `@google-cloud/kms`) and
7
+ * be replaced via a build-time alias or runtime injection.
8
+ *
9
+ * The default exports throw so unintended use in production surfaces
10
+ * an obvious error rather than silently returning plaintext-as-wrapped.
11
+ */
12
+ export declare const kmsWrap: (_dek: Buffer, _keyId: string) => Promise<Buffer>;
13
+ export declare const kmsUnwrap: (_wrapped: Buffer, _keyId: string) => Promise<Buffer>;
14
+ //# sourceMappingURL=kms-envelope.kms-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kms-envelope.kms-adapter.d.ts","sourceRoot":"","sources":["../../src/helpers/kms-envelope.kms-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,OAAO,GAClB,MAAM,MAAM,EACZ,QAAQ,MAAM,KACb,OAAO,CAAC,MAAM,CAKhB,CAAC;AAEF,eAAO,MAAM,SAAS,GACpB,UAAU,MAAM,EAChB,QAAQ,MAAM,KACb,OAAO,CAAC,MAAM,CAKhB,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kms-envelope.kms-adapter.js","sourceRoot":"","sources":["../../src/helpers/kms-envelope.kms-adapter.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAEI,MAAM,OAAO,GAAG,KAAK,EAC1B,IAAY,EACZ,MAAc,EACG,EAAE;IACnB,MAAM,IAAI,KAAK,CACb,uEAAuE;QACrE,gFAAgF,CACnF,CAAC;AACJ,CAAC,CAAC;AARW,QAAA,OAAO,WAQlB;AAEK,MAAM,SAAS,GAAG,KAAK,EAC5B,QAAgB,EAChB,MAAc,EACG,EAAE;IACnB,MAAM,IAAI,KAAK,CACb,yEAAyE;QACvE,gFAAgF,CACnF,CAAC;AACJ,CAAC,CAAC;AARW,QAAA,SAAS,aAQpB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptic/backend-legacy",
3
- "version": "0.0.83",
3
+ "version": "0.0.84",
4
4
  "description": "Backend executable CRUD functions with dynamic variables construction, and type definitions for the Adaptic AI platform.",
5
5
  "type": "module",
6
6
  "types": "index.d.ts",
@@ -24,6 +24,8 @@
24
24
  "validators/",
25
25
  "config/",
26
26
  "middleware/",
27
+ "types/",
28
+ "helpers/",
27
29
  "*.d.ts",
28
30
  "*.js",
29
31
  "*.cjs",
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_LLM_CONFIGURATION = void 0;
4
+ /**
5
+ * Built-in safe defaults consumed by effectiveLlmConfig() as the
6
+ * lowest-precedence layer.
7
+ */
8
+ exports.DEFAULT_LLM_CONFIGURATION = {
9
+ defaultProvider: 'OPENAI',
10
+ miniProvider: 'OPENAI',
11
+ normalProvider: 'OPENAI',
12
+ advancedProvider: 'ANTHROPIC',
13
+ miniModel: 'gpt-5.5',
14
+ normalModel: 'gpt-5',
15
+ advancedModel: 'claude-opus-4-7',
16
+ apiKeys: {},
17
+ };
18
+ //# sourceMappingURL=llm-configuration.js.map
@@ -0,0 +1,42 @@
1
+ import type { EncryptedApiKey } from '../helpers/kms-envelope';
2
+ export type LlmProvider = 'OPENAI' | 'ANTHROPIC' | 'DEEPSEEK' | 'KIMI' | 'QWEN' | 'XAI' | 'GEMINI';
3
+ /**
4
+ * Canonical LlmConfigurationJson shape stored at:
5
+ * Organization.llmDefaults (org-wide defaults)
6
+ * Fund.llmOverrides (fund-level overrides)
7
+ *
8
+ * Read-time merging is precedence-ordered (charter §2.4 F6, spec §4.3):
9
+ * built-in DEFAULT_LLM_CONFIGURATION → Org.llmDefaults → Fund.llmOverrides
10
+ *
11
+ * Consumers MUST use `effectiveLlmConfig()` from
12
+ * `@adaptic/backend-legacy/helpers/effective-llm-config`.
13
+ *
14
+ * API keys (`apiKeys.<provider>`) are stored as EncryptedApiKey
15
+ * envelopes; encrypt/decrypt is gated by org-membership role per
16
+ * spec §4.3.
17
+ */
18
+ export interface LlmConfigurationJson {
19
+ /** Provider used when a tier-specific provider is unset. */
20
+ defaultProvider?: LlmProvider;
21
+ /** Per-tier provider overrides (null = inherit from defaultProvider). */
22
+ miniProvider?: LlmProvider;
23
+ normalProvider?: LlmProvider;
24
+ advancedProvider?: LlmProvider;
25
+ /** Per-tier model id strings (e.g. "gpt-5.5", "claude-opus-4-7"). */
26
+ miniModel?: string;
27
+ normalModel?: string;
28
+ advancedModel?: string;
29
+ /**
30
+ * Per-provider API keys, stored at rest as EncryptedApiKey envelopes.
31
+ * Plaintext only ever crosses the GraphQL mutation boundary.
32
+ */
33
+ apiKeys?: Partial<Record<Lowercase<LlmProvider>, EncryptedApiKey>>;
34
+ }
35
+ /**
36
+ * Built-in safe defaults consumed by effectiveLlmConfig() as the
37
+ * lowest-precedence layer.
38
+ */
39
+ export declare const DEFAULT_LLM_CONFIGURATION: Required<Omit<LlmConfigurationJson, 'apiKeys'>> & {
40
+ apiKeys: NonNullable<LlmConfigurationJson['apiKeys']>;
41
+ };
42
+ //# sourceMappingURL=llm-configuration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-configuration.d.ts","sourceRoot":"","sources":["../../src/types/llm-configuration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,WAAW,GACX,UAAU,GACV,MAAM,GACN,MAAM,GACN,KAAK,GACL,QAAQ,CAAC;AAEb;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,oBAAoB;IACnC,4DAA4D;IAC5D,eAAe,CAAC,EAAE,WAAW,CAAC;IAC9B,yEAAyE;IACzE,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,cAAc,CAAC,EAAE,WAAW,CAAC;IAC7B,gBAAgB,CAAC,EAAE,WAAW,CAAC;IAC/B,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;CACpE;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAC9C,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,CACtC,GAAG;IACF,OAAO,EAAE,WAAW,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC,CAAC;CAUvD,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-configuration.js","sourceRoot":"","sources":["../../src/types/llm-configuration.ts"],"names":[],"mappings":";;;AA4CA;;;GAGG;AACU,QAAA,yBAAyB,GAIlC;IACF,eAAe,EAAE,QAAQ;IACzB,YAAY,EAAE,QAAQ;IACtB,cAAc,EAAE,QAAQ;IACxB,gBAAgB,EAAE,WAAW;IAC7B,SAAS,EAAE,SAAS;IACpB,WAAW,EAAE,OAAO;IACpB,aAAa,EAAE,iBAAiB;IAChC,OAAO,EAAE,EAAE;CACZ,CAAC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=policy-overlay.js.map
@@ -0,0 +1,40 @@
1
+ import type { TradingPolicyJson } from './trading-policy';
2
+ export type OverlayType = 'RISK_GATE' | 'NEWS_GATE' | 'COMPLIANCE_GATE' | 'MANUAL_HALT' | 'CIRCUIT_BREAKER';
3
+ export type OverlaySeverity = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
4
+ export type OverlayStatus = 'ACTIVE' | 'EXPIRED' | 'DEACTIVATED';
5
+ /**
6
+ * Active and recent policy overlays stored on `Fund.policyOverlays`
7
+ * (Json[] column) per charter §2.4 F4 and spec §4.4.
8
+ *
9
+ * `effectivePolicy()` filters this list to entries where
10
+ * `status === 'ACTIVE' && (expiresAt == null || expiresAt > now)`,
11
+ * sorts by severity ascending (CRITICAL last → highest precedence),
12
+ * and deep-merges each overlay's `mutations` over the policy chain.
13
+ *
14
+ * On every status flip away from ACTIVE the engine archiver moves
15
+ * the entry to Tier-A `PolicyOverlayHistory` and removes it from this
16
+ * array atomically (one DB transaction). Steady-state size ≤ 20.
17
+ */
18
+ export interface PolicyOverlayEntry {
19
+ /** UUID for cross-referencing with Tier-A PolicyOverlayHistory. */
20
+ id: string;
21
+ overlayType: OverlayType;
22
+ /** Source service that activated this overlay (e.g. "engine.risk.var-breach"). */
23
+ source: string;
24
+ /** Human-readable reason; surfaced in alerts. */
25
+ reason: string;
26
+ severity: OverlaySeverity;
27
+ /** Policy paths to override while ACTIVE. */
28
+ mutations: Partial<TradingPolicyJson>;
29
+ status: OverlayStatus;
30
+ /** ISO-8601 activation timestamp. */
31
+ activatedAt: string;
32
+ /** ISO-8601 expiry timestamp; absence means "until manually deactivated". */
33
+ expiresAt?: string;
34
+ deactivatedAt?: string;
35
+ deactivatedBy?: string;
36
+ /** Correlation id linking this overlay to the event that triggered it. */
37
+ correlationId?: string;
38
+ triggerEventId?: string;
39
+ }
40
+ //# sourceMappingURL=policy-overlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-overlay.d.ts","sourceRoot":"","sources":["../../src/types/policy-overlay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,WAAW,GACX,iBAAiB,GACjB,aAAa,GACb,iBAAiB,CAAC;AAEtB,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAErE,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,aAAa,CAAC;AAEjE;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,WAAW,CAAC;IACzB,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,eAAe,CAAC;IAC1B,6CAA6C;IAC7C,SAAS,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACtC,MAAM,EAAE,aAAa,CAAC;IACtB,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-overlay.js","sourceRoot":"","sources":["../../src/types/policy-overlay.ts"],"names":[],"mappings":""}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_TRADING_POLICY = void 0;
4
+ /**
5
+ * Built-in safe defaults consumed by effectivePolicy() as the
6
+ * lowest-precedence layer. Tunings here are conservative and broadly
7
+ * safe; `@adaptic/utils` re-exports a more tuned variant for short-horizon
8
+ * day trading (see utils U1 plan).
9
+ */
10
+ exports.DEFAULT_TRADING_POLICY = {
11
+ autonomy: {
12
+ enableAutoEntry: false,
13
+ enableAutoExit: true,
14
+ enableAutoRebalance: false,
15
+ requireHumanApprovalAboveNotional: 100000,
16
+ },
17
+ risk: {
18
+ maxPortfolioVarPct: 0.05,
19
+ maxSinglePositionPct: 0.1,
20
+ maxSectorExposurePct: 0.3,
21
+ maxAssetClassPct: { equity: 1.0, crypto: 0.2, options: 0.2 },
22
+ minBuyingPowerReservePct: 0.05,
23
+ },
24
+ allocation: {
25
+ perTradeEquityPct: 0.05,
26
+ perTradeCryptoPct: 0.05,
27
+ perTradeOptionsPct: 0.02,
28
+ autoAllocation: true,
29
+ },
30
+ scalping: {
31
+ enableScalping: false,
32
+ maxConcurrentScalps: 0,
33
+ minHoldSeconds: 0,
34
+ maxHoldSeconds: 0,
35
+ profitTargetBps: 0,
36
+ stopLossBps: 0,
37
+ requireRSIConfirm: false,
38
+ requireMACDConfirm: false,
39
+ requireVolumeSurge: false,
40
+ cooldownAfterLossMs: 0,
41
+ cooldownAfterWinMs: 0,
42
+ maxScalpsPerSession: 0,
43
+ },
44
+ compliance: {
45
+ equityWashTradeCooldownMs: 0,
46
+ restrictedTickerOverrides: [],
47
+ requireAuditLogForAll: true,
48
+ },
49
+ assetClasses: { equity: true, crypto: false, options: false },
50
+ sentiment: {
51
+ minSentimentScoreToEnter: 0,
52
+ maxNegativeSentimentToHold: -0.5,
53
+ requireRecentNews: false,
54
+ newsLookbackMinutes: 1440,
55
+ },
56
+ backtest: {
57
+ defaultUniverse: [],
58
+ defaultPeriodDays: 30,
59
+ defaultStrategyId: '',
60
+ },
61
+ runtime: {
62
+ enginePersonalityProfile: 'balanced',
63
+ signalRoutingRules: null,
64
+ manualOverrideAllowlist: [],
65
+ riskOverrideJustifications: [],
66
+ enableShadowMode: false,
67
+ experimentBucket: null,
68
+ },
69
+ };
70
+ //# sourceMappingURL=trading-policy.js.map
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Canonical TradingPolicyJson shape stored at:
3
+ * Organization.tradingDefaults (org-wide defaults)
4
+ * Fund.tradingOverrides (fund-level overrides)
5
+ *
6
+ * Read-time merging is precedence-ordered (charter §2.2, spec §4.2.2):
7
+ * built-in DEFAULT_TRADING_POLICY → Org.tradingDefaults
8
+ * → Fund.tradingOverrides → active Fund.policyOverlays
9
+ * → 14 per-BrokerageAccount column overrides
10
+ *
11
+ * Consumers MUST use `effectivePolicy()` from
12
+ * `@adaptic/backend-legacy/helpers/effective-policy` — do NOT
13
+ * re-implement the precedence chain.
14
+ */
15
+ export interface TradingPolicyJson {
16
+ /** Autonomy — when the engine is allowed to act without human approval. */
17
+ autonomy?: {
18
+ enableAutoEntry?: boolean;
19
+ enableAutoExit?: boolean;
20
+ enableAutoRebalance?: boolean;
21
+ requireHumanApprovalAboveNotional?: number;
22
+ };
23
+ /** Risk caps applied per-strategy and per-portfolio. */
24
+ risk?: {
25
+ /** Maximum portfolio Value-at-Risk as a fraction (0..1). */
26
+ maxPortfolioVarPct?: number;
27
+ /** Maximum single-position weight as a fraction (0..1). */
28
+ maxSinglePositionPct?: number;
29
+ /** Maximum sector exposure as a fraction (0..1). */
30
+ maxSectorExposurePct?: number;
31
+ /** Per-asset-class caps as fractions of NAV. */
32
+ maxAssetClassPct?: {
33
+ equity?: number;
34
+ crypto?: number;
35
+ options?: number;
36
+ };
37
+ /** Minimum buying-power reserve as a fraction (0..1). */
38
+ minBuyingPowerReservePct?: number;
39
+ };
40
+ /** Per-trade allocation defaults (SR's tradeAllocationPct collapsed here). */
41
+ allocation?: {
42
+ perTradeEquityPct?: number;
43
+ perTradeCryptoPct?: number;
44
+ perTradeOptionsPct?: number;
45
+ autoAllocation?: boolean;
46
+ };
47
+ /** Scalping / intraday-specific policy (12 W3-3 fields from SR commit 10b63819d). */
48
+ scalping?: {
49
+ enableScalping?: boolean;
50
+ maxConcurrentScalps?: number;
51
+ minHoldSeconds?: number;
52
+ maxHoldSeconds?: number;
53
+ profitTargetBps?: number;
54
+ stopLossBps?: number;
55
+ requireRSIConfirm?: boolean;
56
+ requireMACDConfirm?: boolean;
57
+ requireVolumeSurge?: boolean;
58
+ cooldownAfterLossMs?: number;
59
+ cooldownAfterWinMs?: number;
60
+ maxScalpsPerSession?: number;
61
+ };
62
+ /** Compliance — FINRA / SEC operational rules. */
63
+ compliance?: {
64
+ /** FINRA 5210 wash-trade cooldown in milliseconds. */
65
+ equityWashTradeCooldownMs?: number;
66
+ /** Tickers explicitly excluded from autonomous trading. */
67
+ restrictedTickerOverrides?: string[];
68
+ /** Force AuditLog row creation on every order. */
69
+ requireAuditLogForAll?: boolean;
70
+ };
71
+ /** Asset-class enablement (defaults set in DEFAULT_TRADING_POLICY). */
72
+ assetClasses?: {
73
+ equity?: boolean;
74
+ crypto?: boolean;
75
+ options?: boolean;
76
+ };
77
+ /** Sentiment / news subscription policy (fund-scope per charter §2.4 F5). */
78
+ sentiment?: {
79
+ minSentimentScoreToEnter?: number;
80
+ maxNegativeSentimentToHold?: number;
81
+ requireRecentNews?: boolean;
82
+ newsLookbackMinutes?: number;
83
+ };
84
+ /** Backtest scope (fund-scope per charter §2.4 F7). */
85
+ backtest?: {
86
+ defaultUniverse?: string[];
87
+ defaultPeriodDays?: number;
88
+ defaultStrategyId?: string;
89
+ };
90
+ /**
91
+ * Engine runtime config (charter §2.4 F1/F8/F9 catch-all).
92
+ *
93
+ * Populated when sub-project 6 (engine port) has not yet committed
94
+ * to owning `EngineFundConfig` in Tier-A. Carries the 6 SR
95
+ * `TradingPolicy` policy-shape fields that have no canonical JSON
96
+ * home: enginePersonalityProfile, signalRoutingRules,
97
+ * manualOverrideAllowlist, riskOverrideJustifications,
98
+ * enableShadowMode, experimentBucket.
99
+ *
100
+ * If/when sub-project 6 promotes these to Tier-A, this group can be
101
+ * migrated out and removed.
102
+ */
103
+ runtime?: {
104
+ enginePersonalityProfile?: string;
105
+ signalRoutingRules?: unknown;
106
+ manualOverrideAllowlist?: string[];
107
+ riskOverrideJustifications?: unknown[];
108
+ enableShadowMode?: boolean;
109
+ experimentBucket?: string | null;
110
+ };
111
+ }
112
+ /**
113
+ * Built-in safe defaults consumed by effectivePolicy() as the
114
+ * lowest-precedence layer. Tunings here are conservative and broadly
115
+ * safe; `@adaptic/utils` re-exports a more tuned variant for short-horizon
116
+ * day trading (see utils U1 plan).
117
+ */
118
+ export declare const DEFAULT_TRADING_POLICY: Required<TradingPolicyJson>;
119
+ //# sourceMappingURL=trading-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trading-policy.d.ts","sourceRoot":"","sources":["../../src/types/trading-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trading-policy.js","sourceRoot":"","sources":["../../src/types/trading-policy.ts"],"names":[],"mappings":";;;AAwHA;;;;;GAKG;AACU,QAAA,sBAAsB,GAAgC;IACjE,QAAQ,EAAE;QACR,eAAe,EAAE,KAAK;QACtB,cAAc,EAAE,IAAI;QACpB,mBAAmB,EAAE,KAAK;QAC1B,iCAAiC,EAAE,MAAO;KAC3C;IACD,IAAI,EAAE;QACJ,kBAAkB,EAAE,IAAI;QACxB,oBAAoB,EAAE,GAAG;QACzB,oBAAoB,EAAE,GAAG;QACzB,gBAAgB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE;QAC5D,wBAAwB,EAAE,IAAI;KAC/B;IACD,UAAU,EAAE;QACV,iBAAiB,EAAE,IAAI;QACvB,iBAAiB,EAAE,IAAI;QACvB,kBAAkB,EAAE,IAAI;QACxB,cAAc,EAAE,IAAI;KACrB;IACD,QAAQ,EAAE;QACR,cAAc,EAAE,KAAK;QACrB,mBAAmB,EAAE,CAAC;QACtB,cAAc,EAAE,CAAC;QACjB,cAAc,EAAE,CAAC;QACjB,eAAe,EAAE,CAAC;QAClB,WAAW,EAAE,CAAC;QACd,iBAAiB,EAAE,KAAK;QACxB,kBAAkB,EAAE,KAAK;QACzB,kBAAkB,EAAE,KAAK;QACzB,mBAAmB,EAAE,CAAC;QACtB,kBAAkB,EAAE,CAAC;QACrB,mBAAmB,EAAE,CAAC;KACvB;IACD,UAAU,EAAE;QACV,yBAAyB,EAAE,CAAC;QAC5B,yBAAyB,EAAE,EAAE;QAC7B,qBAAqB,EAAE,IAAI;KAC5B;IACD,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE;IAC7D,SAAS,EAAE;QACT,wBAAwB,EAAE,CAAC;QAC3B,0BAA0B,EAAE,CAAC,GAAG;QAChC,iBAAiB,EAAE,KAAK;QACxB,mBAAmB,EAAE,IAAI;KAC1B;IACD,QAAQ,EAAE;QACR,eAAe,EAAE,EAAE;QACnB,iBAAiB,EAAE,EAAE;QACrB,iBAAiB,EAAE,EAAE;KACtB;IACD,OAAO,EAAE;QACP,wBAAwB,EAAE,UAAU;QACpC,kBAAkB,EAAE,IAAI;QACxB,uBAAuB,EAAE,EAAE;QAC3B,0BAA0B,EAAE,EAAE;QAC9B,gBAAgB,EAAE,KAAK;QACvB,gBAAgB,EAAE,IAAI;KACvB;CACF,CAAC"}