@adaptic/backend-legacy 0.0.83 → 0.0.85

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 (42) hide show
  1. package/esm/plugins/http-status-mapper.d.ts +33 -0
  2. package/esm/plugins/http-status-mapper.d.ts.map +1 -0
  3. package/esm/plugins/http-status-mapper.js.map +1 -0
  4. package/esm/plugins/http-status-mapper.mjs +87 -0
  5. package/esm/plugins/index.d.ts +1 -0
  6. package/esm/plugins/index.d.ts.map +1 -1
  7. package/esm/plugins/index.js.map +1 -1
  8. package/esm/plugins/index.mjs +1 -0
  9. package/helpers/deep-merge.cjs +33 -0
  10. package/helpers/deep-merge.d.ts +15 -0
  11. package/helpers/deep-merge.d.ts.map +1 -0
  12. package/helpers/deep-merge.js.map +1 -0
  13. package/helpers/effective-llm-config.cjs +24 -0
  14. package/helpers/effective-llm-config.d.ts +28 -0
  15. package/helpers/effective-llm-config.d.ts.map +1 -0
  16. package/helpers/effective-llm-config.js.map +1 -0
  17. package/helpers/effective-policy.cjs +130 -0
  18. package/helpers/effective-policy.d.ts +70 -0
  19. package/helpers/effective-policy.d.ts.map +1 -0
  20. package/helpers/effective-policy.js.map +1 -0
  21. package/helpers/kms-envelope.cjs +53 -0
  22. package/helpers/kms-envelope.d.ts +36 -0
  23. package/helpers/kms-envelope.d.ts.map +1 -0
  24. package/helpers/kms-envelope.js.map +1 -0
  25. package/helpers/kms-envelope.kms-adapter.cjs +25 -0
  26. package/helpers/kms-envelope.kms-adapter.d.ts +14 -0
  27. package/helpers/kms-envelope.kms-adapter.d.ts.map +1 -0
  28. package/helpers/kms-envelope.kms-adapter.js.map +1 -0
  29. package/package.json +3 -1
  30. package/server.cjs +13 -2
  31. package/types/llm-configuration.cjs +18 -0
  32. package/types/llm-configuration.d.ts +42 -0
  33. package/types/llm-configuration.d.ts.map +1 -0
  34. package/types/llm-configuration.js.map +1 -0
  35. package/types/policy-overlay.cjs +3 -0
  36. package/types/policy-overlay.d.ts +40 -0
  37. package/types/policy-overlay.d.ts.map +1 -0
  38. package/types/policy-overlay.js.map +1 -0
  39. package/types/trading-policy.cjs +70 -0
  40. package/types/trading-policy.d.ts +119 -0
  41. package/types/trading-policy.d.ts.map +1 -0
  42. package/types/trading-policy.js.map +1 -0
@@ -0,0 +1,33 @@
1
+ /**
2
+ * HTTP Status Mapper Plugin for Apollo Server 5.
3
+ *
4
+ * Maps well-known GraphQL error codes to their semantically-correct HTTP
5
+ * status codes. Apollo Server 5 defaults to HTTP 500 for any error thrown
6
+ * inside the `context` function (wrapped as ContextFunctionError) and to
7
+ * HTTP 200 for errors thrown inside resolvers — neither default is correct
8
+ * for an authentication failure, and the 500 default actively harms
9
+ * consumers: Apollo Client's observable pipeline crashes on a 5xx response
10
+ * with a GraphQL-shaped body (`Cannot read properties of undefined (reading
11
+ * 'write')`), so the awaited `client.query(...)` Promise neither resolves
12
+ * nor rejects. Downstream `try/catch` blocks never run, and any UI that
13
+ * gates rendering on a `setIsLoading(false)` in `finally` is locked into a
14
+ * permanent loading state.
15
+ *
16
+ * This plugin runs in `willSendResponse` and inspects every GraphQL error in
17
+ * the final response body. If any error carries `extensions.code` in the
18
+ * lookup table below, the response's HTTP status is upgraded accordingly.
19
+ * Doing it here (rather than at each throw site) means we get the same
20
+ * mapping whether the error originated in a context function, a resolver,
21
+ * an `AuthChecker`, or a directive — and a future code path that throws
22
+ * UNAUTHENTICATED cannot accidentally regress to a 500.
23
+ *
24
+ * Mapping policy:
25
+ * UNAUTHENTICATED → 401 (most common; the bug above)
26
+ * FORBIDDEN → 403 (AuthChecker rejections per CORTEX-P0-001)
27
+ * BAD_USER_INPUT → 400 (GraphQL validation already handles syntax; this
28
+ * covers semantic input rejection from validators)
29
+ * Anything else → unchanged (200 for in-body errors, 500 for fatal)
30
+ */
31
+ import type { ApolloServerPlugin } from '@apollo/server';
32
+ export declare function createHttpStatusMapperPlugin<TContext extends object = object>(): ApolloServerPlugin<TContext>;
33
+ //# sourceMappingURL=http-status-mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-status-mapper.d.ts","sourceRoot":"","sources":["../../../src/plugins/http-status-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAGnB,MAAM,gBAAgB,CAAC;AAgCxB,wBAAgB,4BAA4B,CAC1C,QAAQ,SAAS,MAAM,GAAG,MAAM,KAC7B,kBAAkB,CAAC,QAAQ,CAAC,CA2BhC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-status-mapper.js","sourceRoot":"","sources":["../../../src/plugins/http-status-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AASH,MAAM,mBAAmB,GAA2B;IAClD,eAAe,EAAE,GAAG;IACpB,SAAS,EAAE,GAAG;IACd,cAAc,EAAE,GAAG;CACpB,CAAC;AAEF;;;;;GAKG;AACH,SAAS,gBAAgB,CACvB,MAAwC;IAExC,IAAI,IAAwB,CAAC;IAC7B,MAAM,QAAQ,GAA2B,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;IACpE,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC;QAClC,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,SAAS;QACvC,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM;YAAE,SAAS;QACtB,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAC1E,IAAI,GAAG,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,4BAA4B;IAG1C,OAAO;QACL,KAAK,CAAC,eAAe;YACnB,OAAO;gBACL,KAAK,CAAC,gBAAgB,CACpB,cAA+D;oBAE/D,MAAM,EAAE,QAAQ,EAAE,GAAG,cAAc,CAAC;oBACpC,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;oBAC1B,kEAAkE;oBAClE,iEAAiE;oBACjE,4DAA4D;oBAC5D,8DAA8D;oBAC9D,UAAU;oBACV,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;wBAAE,OAAO;oBACnC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;oBACxC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;wBAAE,OAAO;oBAC3C,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;oBACxC,IAAI,MAAM,KAAK,SAAS;wBAAE,OAAO;oBACjC,4DAA4D;oBAC5D,+DAA+D;oBAC/D,qEAAqE;oBACrE,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;gBAChC,CAAC;aACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * HTTP Status Mapper Plugin for Apollo Server 5.
3
+ *
4
+ * Maps well-known GraphQL error codes to their semantically-correct HTTP
5
+ * status codes. Apollo Server 5 defaults to HTTP 500 for any error thrown
6
+ * inside the `context` function (wrapped as ContextFunctionError) and to
7
+ * HTTP 200 for errors thrown inside resolvers — neither default is correct
8
+ * for an authentication failure, and the 500 default actively harms
9
+ * consumers: Apollo Client's observable pipeline crashes on a 5xx response
10
+ * with a GraphQL-shaped body (`Cannot read properties of undefined (reading
11
+ * 'write')`), so the awaited `client.query(...)` Promise neither resolves
12
+ * nor rejects. Downstream `try/catch` blocks never run, and any UI that
13
+ * gates rendering on a `setIsLoading(false)` in `finally` is locked into a
14
+ * permanent loading state.
15
+ *
16
+ * This plugin runs in `willSendResponse` and inspects every GraphQL error in
17
+ * the final response body. If any error carries `extensions.code` in the
18
+ * lookup table below, the response's HTTP status is upgraded accordingly.
19
+ * Doing it here (rather than at each throw site) means we get the same
20
+ * mapping whether the error originated in a context function, a resolver,
21
+ * an `AuthChecker`, or a directive — and a future code path that throws
22
+ * UNAUTHENTICATED cannot accidentally regress to a 500.
23
+ *
24
+ * Mapping policy:
25
+ * UNAUTHENTICATED → 401 (most common; the bug above)
26
+ * FORBIDDEN → 403 (AuthChecker rejections per CORTEX-P0-001)
27
+ * BAD_USER_INPUT → 400 (GraphQL validation already handles syntax; this
28
+ * covers semantic input rejection from validators)
29
+ * Anything else → unchanged (200 for in-body errors, 500 for fatal)
30
+ */
31
+ const CODE_TO_HTTP_STATUS = {
32
+ UNAUTHENTICATED: 401,
33
+ FORBIDDEN: 403,
34
+ BAD_USER_INPUT: 400,
35
+ };
36
+ /**
37
+ * Returns the highest-priority HTTP status implied by the GraphQL errors in
38
+ * the response, or undefined if no mapping applies. Priority order: 401 over
39
+ * 403 over 400 — auth failures trump everything else because they're the
40
+ * primary signal a client needs to refresh its token / reauthenticate.
41
+ */
42
+ function deriveHttpStatus(errors) {
43
+ let best;
44
+ const priority = { 401: 3, 403: 2, 400: 1 };
45
+ for (const err of errors) {
46
+ const code = err.extensions?.code;
47
+ if (typeof code !== 'string')
48
+ continue;
49
+ const status = CODE_TO_HTTP_STATUS[code];
50
+ if (!status)
51
+ continue;
52
+ if (best === undefined || (priority[status] ?? 0) > (priority[best] ?? 0)) {
53
+ best = status;
54
+ }
55
+ }
56
+ return best;
57
+ }
58
+ export function createHttpStatusMapperPlugin() {
59
+ return {
60
+ async requestDidStart() {
61
+ return {
62
+ async willSendResponse(requestContext) {
63
+ const { response } = requestContext;
64
+ const { body } = response;
65
+ // Only the `single` response kind carries a single `errors` array
66
+ // we can inspect synchronously. Incremental delivery (`@defer` /
67
+ // `@stream`) uses `incremental` and would require per-chunk
68
+ // mapping; we don't use those features yet, so this is a safe
69
+ // narrow.
70
+ if (body.kind !== 'single')
71
+ return;
72
+ const errors = body.singleResult.errors;
73
+ if (!errors || errors.length === 0)
74
+ return;
75
+ const status = deriveHttpStatus(errors);
76
+ if (status === undefined)
77
+ return;
78
+ // Apollo Server only sets `http.status` for fatal errors by
79
+ // default; assigning here overrides that. The `http` object is
80
+ // always present on the response when reached via expressMiddleware.
81
+ response.http.status = status;
82
+ },
83
+ };
84
+ },
85
+ };
86
+ }
87
+ //# sourceMappingURL=http-status-mapper.js.map
@@ -5,4 +5,5 @@
5
5
  */
6
6
  export { queryDepthLimiterPlugin } from './query-depth-limiter';
7
7
  export { createErrorSanitizer, formatError } from './error-sanitizer';
8
+ export { createHttpStatusMapperPlugin } from './http-status-mapper';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC"}
@@ -5,4 +5,5 @@
5
5
  */
6
6
  export { queryDepthLimiterPlugin } from './query-depth-limiter.mjs';
7
7
  export { createErrorSanitizer, formatError } from './error-sanitizer.mjs';
8
+ export { createHttpStatusMapperPlugin } from './http-status-mapper.mjs';
8
9
  //# sourceMappingURL=index.js.map
@@ -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.85",
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",
package/server.cjs CHANGED
@@ -22,6 +22,7 @@ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
22
22
  const auth_1 = require("./middleware/auth.cjs");
23
23
  const audit_logger_1 = require("./middleware/audit-logger.cjs");
24
24
  const jwtConfig_1 = require("./config/jwtConfig.cjs");
25
+ const http_status_mapper_1 = require("./plugins/http-status-mapper.cjs");
25
26
  const prismaClient_1 = __importDefault(require("./prismaClient.cjs"));
26
27
  const health_1 = require("./health.cjs");
27
28
  const child_process_1 = require("child_process");
@@ -70,6 +71,7 @@ const startServer = async () => {
70
71
  plugins: [
71
72
  (0, drainHttpServer_1.ApolloServerPluginDrainHttpServer)({ httpServer }),
72
73
  (0, audit_logger_1.createAuditLogPlugin)(),
74
+ (0, http_status_mapper_1.createHttpStatusMapperPlugin)(),
73
75
  ],
74
76
  formatError: (err) => {
75
77
  var _a;
@@ -136,8 +138,17 @@ const startServer = async () => {
136
138
  // Health check endpoint - mounted before Apollo middleware so it's not behind GraphQL or auth
137
139
  app.use((0, health_1.createHealthRouter)());
138
140
  // Configure CORS with allowed origins
139
- const defaultOrigins = ['http://localhost:3000', 'http://localhost:3001', 'http://localhost:4000', 'https://adaptic.ai', 'https://api.adaptic.ai', 'https://os.adaptic.ai'];
140
- const envOrigins = process.env.ALLOWED_ORIGINS ? process.env.ALLOWED_ORIGINS.split(',').map(o => o.trim()) : [];
141
+ const defaultOrigins = [
142
+ 'http://localhost:3000',
143
+ 'http://localhost:3001',
144
+ 'http://localhost:4000',
145
+ 'https://adaptic.ai',
146
+ 'https://api.adaptic.ai',
147
+ 'https://os.adaptic.ai',
148
+ ];
149
+ const envOrigins = process.env.ALLOWED_ORIGINS
150
+ ? process.env.ALLOWED_ORIGINS.split(',').map((o) => o.trim())
151
+ : [];
141
152
  const allowedOrigins = [...new Set([...defaultOrigins, ...envOrigins])];
142
153
  const corsOptions = {
143
154
  origin: (origin, callback) => {
@@ -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"}