@sincpro/mobile 0.3.1 → 0.4.2

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 (100) hide show
  1. package/README.md +234 -2
  2. package/dist/entrypoints/cron/EBuiltinCron.d.ts +4 -0
  3. package/dist/entrypoints/cron/EBuiltinCron.js +5 -0
  4. package/dist/entrypoints/cron/checkNetworkStatus.cron.js +2 -1
  5. package/dist/entrypoints/db/migrations.d.ts +3 -1
  6. package/dist/entrypoints/db/migrations.js +47 -0
  7. package/dist/entrypoints/queue/QueueProcessor.js +1 -25
  8. package/dist/entrypoints/queue/subscriber_filter.d.ts +9 -0
  9. package/dist/entrypoints/queue/subscriber_filter.js +25 -0
  10. package/dist/entrypoints/ui/common_provider.js +2 -2
  11. package/dist/framework/base_module.d.ts +1 -0
  12. package/dist/framework/base_module.js +6 -1
  13. package/dist/framework/createApp.d.ts +14 -0
  14. package/dist/framework/createApp.js +6 -0
  15. package/dist/framework/kernel.d.ts +2 -1
  16. package/dist/framework/kernel.js +8 -0
  17. package/dist/index.d.ts +7 -0
  18. package/dist/index.js +4 -0
  19. package/dist/infrastructure/context_manager/context.d.ts +16 -0
  20. package/dist/infrastructure/context_manager/context.js +37 -0
  21. package/dist/infrastructure/context_manager/context_api.d.ts +28 -0
  22. package/dist/infrastructure/context_manager/context_api.js +55 -0
  23. package/dist/infrastructure/context_manager/context_key.d.ts +15 -0
  24. package/dist/infrastructure/context_manager/context_key.js +3 -0
  25. package/dist/infrastructure/context_manager/context_manager_facade.d.ts +107 -0
  26. package/dist/infrastructure/context_manager/context_manager_facade.js +113 -0
  27. package/dist/infrastructure/context_manager/decorators/propagate_context.d.ts +24 -0
  28. package/dist/infrastructure/context_manager/decorators/propagate_context.js +52 -0
  29. package/dist/infrastructure/context_manager/decorators/with_context.d.ts +34 -0
  30. package/dist/infrastructure/context_manager/decorators/with_context.js +44 -0
  31. package/dist/infrastructure/context_manager/index.d.ts +11 -0
  32. package/dist/infrastructure/context_manager/index.js +12 -0
  33. package/dist/infrastructure/context_manager/managed_context.d.ts +87 -0
  34. package/dist/infrastructure/context_manager/managed_context.js +144 -0
  35. package/dist/infrastructure/context_manager/stack_context_manager.d.ts +39 -0
  36. package/dist/infrastructure/context_manager/stack_context_manager.js +56 -0
  37. package/dist/infrastructure/database/connector.js +10 -1
  38. package/dist/infrastructure/interceptor/index.d.ts +4 -0
  39. package/dist/infrastructure/interceptor/index.js +2 -0
  40. package/dist/infrastructure/interceptor/intercept.d.ts +57 -0
  41. package/dist/infrastructure/interceptor/intercept.js +112 -0
  42. package/dist/infrastructure/interceptor/logging_hooks.d.ts +22 -0
  43. package/dist/infrastructure/interceptor/logging_hooks.js +27 -0
  44. package/dist/infrastructure/logger.d.ts +11 -16
  45. package/dist/infrastructure/logger.js +61 -18
  46. package/dist/infrastructure/telemetry/buffer_registry.d.ts +15 -0
  47. package/dist/infrastructure/telemetry/buffer_registry.js +26 -0
  48. package/dist/infrastructure/telemetry/connectivity_state.d.ts +20 -0
  49. package/dist/infrastructure/telemetry/connectivity_state.js +28 -0
  50. package/dist/infrastructure/telemetry/context_keys.d.ts +7 -0
  51. package/dist/infrastructure/telemetry/context_keys.js +7 -0
  52. package/dist/infrastructure/telemetry/fetch_with_timeout.d.ts +8 -0
  53. package/dist/infrastructure/telemetry/fetch_with_timeout.js +17 -0
  54. package/dist/infrastructure/telemetry/flush_telemetry.d.ts +40 -0
  55. package/dist/infrastructure/telemetry/flush_telemetry.js +72 -0
  56. package/dist/infrastructure/telemetry/index.d.ts +17 -0
  57. package/dist/infrastructure/telemetry/index.js +17 -0
  58. package/dist/infrastructure/telemetry/init_telemetry.d.ts +21 -0
  59. package/dist/infrastructure/telemetry/init_telemetry.js +85 -0
  60. package/dist/infrastructure/telemetry/logging/flush_job.d.ts +44 -0
  61. package/dist/infrastructure/telemetry/logging/flush_job.js +69 -0
  62. package/dist/infrastructure/telemetry/logging/log_queue_repository.d.ts +76 -0
  63. package/dist/infrastructure/telemetry/logging/log_queue_repository.js +147 -0
  64. package/dist/infrastructure/telemetry/logging/loki_client.d.ts +32 -0
  65. package/dist/infrastructure/telemetry/logging/loki_client.js +118 -0
  66. package/dist/infrastructure/telemetry/logging/loki_registry.d.ts +12 -0
  67. package/dist/infrastructure/telemetry/logging/loki_registry.js +17 -0
  68. package/dist/infrastructure/telemetry/telemetry_flush_worker.d.ts +35 -0
  69. package/dist/infrastructure/telemetry/telemetry_flush_worker.js +66 -0
  70. package/dist/infrastructure/telemetry/telemetry_signal.d.ts +18 -0
  71. package/dist/infrastructure/telemetry/telemetry_signal.js +33 -0
  72. package/dist/infrastructure/telemetry/tracing/active_span.d.ts +22 -0
  73. package/dist/infrastructure/telemetry/tracing/active_span.js +40 -0
  74. package/dist/infrastructure/telemetry/tracing/otlp_client.d.ts +13 -0
  75. package/dist/infrastructure/telemetry/tracing/otlp_client.js +34 -0
  76. package/dist/infrastructure/telemetry/tracing/otlp_serializer.d.ts +67 -0
  77. package/dist/infrastructure/telemetry/tracing/otlp_serializer.js +101 -0
  78. package/dist/infrastructure/telemetry/tracing/span_flush_job.d.ts +25 -0
  79. package/dist/infrastructure/telemetry/tracing/span_flush_job.js +42 -0
  80. package/dist/infrastructure/telemetry/tracing/span_queue_repository.d.ts +82 -0
  81. package/dist/infrastructure/telemetry/tracing/span_queue_repository.js +134 -0
  82. package/dist/infrastructure/telemetry/tracing/span_sampler.d.ts +40 -0
  83. package/dist/infrastructure/telemetry/tracing/span_sampler.js +75 -0
  84. package/dist/infrastructure/telemetry/tracing/span_serializer.d.ts +48 -0
  85. package/dist/infrastructure/telemetry/tracing/span_serializer.js +36 -0
  86. package/dist/infrastructure/telemetry/tracing/sqlite_span_exporter.d.ts +26 -0
  87. package/dist/infrastructure/telemetry/tracing/sqlite_span_exporter.js +47 -0
  88. package/dist/infrastructure/telemetry/tracing/tracer.d.ts +22 -0
  89. package/dist/infrastructure/telemetry/tracing/tracer.js +45 -0
  90. package/dist/infrastructure/telemetry/tracing/tracing_hooks.d.ts +10 -0
  91. package/dist/infrastructure/telemetry/tracing/tracing_hooks.js +59 -0
  92. package/dist/infrastructure/telemetry/tracing_facade.d.ts +50 -0
  93. package/dist/infrastructure/telemetry/tracing_facade.js +139 -0
  94. package/dist/infrastructure/telemetry/types.d.ts +120 -0
  95. package/dist/infrastructure/telemetry/types.js +1 -0
  96. package/dist/infrastructure/workers/CronWorker.d.ts +10 -2
  97. package/dist/infrastructure/workers/CronWorker.js +18 -5
  98. package/dist/infrastructure/workers/index.d.ts +1 -1
  99. package/dist/ui/components/molecules/TimeZoneSelectorModal.js +7 -1
  100. package/package.json +17 -11
@@ -0,0 +1,28 @@
1
+ import { Context } from "./context";
2
+ import type { ContextKey } from "./context_key";
3
+ import { StackContextManager } from "./stack_context_manager";
4
+ /** Returns the context active in the current execution scope. */
5
+ export declare function getActiveContext(): Context;
6
+ /**
7
+ * Reads a value from the active context.
8
+ * Equivalent to getActiveContext().get(key).
9
+ */
10
+ export declare function getContext<T>(key: ContextKey<T>): T | undefined;
11
+ /**
12
+ * Runs fn within ctx as the active context.
13
+ *
14
+ * For async functions, ctx stays active until the returned Promise resolves or
15
+ * rejects — not just until the first await. This means nested calls at any
16
+ * point in the async chain see the correct context.
17
+ *
18
+ * For sync functions, ctx is active for the duration of the call.
19
+ */
20
+ export declare function runWithContext<T>(ctx: Context, fn: () => T): T;
21
+ /**
22
+ * Returns the underlying manager.
23
+ * Used by interceptor hooks (push/pop) and by adapters (e.g. OTel bridge).
24
+ * @internal
25
+ */
26
+ export declare function _getContextManager(): StackContextManager;
27
+ /** @internal — test use only */
28
+ export declare function _resetContextManager(): void;
@@ -0,0 +1,55 @@
1
+ import { StackContextManager } from "./stack_context_manager";
2
+ const _manager = new StackContextManager();
3
+ /** Returns the context active in the current execution scope. */
4
+ export function getActiveContext() {
5
+ return _manager.active();
6
+ }
7
+ /**
8
+ * Reads a value from the active context.
9
+ * Equivalent to getActiveContext().get(key).
10
+ */
11
+ export function getContext(key) {
12
+ return _manager.active().get(key);
13
+ }
14
+ /**
15
+ * Runs fn within ctx as the active context.
16
+ *
17
+ * For async functions, ctx stays active until the returned Promise resolves or
18
+ * rejects — not just until the first await. This means nested calls at any
19
+ * point in the async chain see the correct context.
20
+ *
21
+ * For sync functions, ctx is active for the duration of the call.
22
+ */
23
+ export function runWithContext(ctx, fn) {
24
+ _manager.push(ctx);
25
+ try {
26
+ const result = fn();
27
+ if (result instanceof Promise) {
28
+ return result.then((v) => {
29
+ _manager.pop();
30
+ return v;
31
+ }, (e) => {
32
+ _manager.pop();
33
+ throw e;
34
+ });
35
+ }
36
+ _manager.pop();
37
+ return result;
38
+ }
39
+ catch (e) {
40
+ _manager.pop();
41
+ throw e;
42
+ }
43
+ }
44
+ /**
45
+ * Returns the underlying manager.
46
+ * Used by interceptor hooks (push/pop) and by adapters (e.g. OTel bridge).
47
+ * @internal
48
+ */
49
+ export function _getContextManager() {
50
+ return _manager;
51
+ }
52
+ /** @internal — test use only */
53
+ export function _resetContextManager() {
54
+ _manager.reset();
55
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Opaque typed key for storing values in a Context.
3
+ *
4
+ * Two calls to createContextKey with the same description produce different
5
+ * keys — collision between modules is impossible even if they share names.
6
+ *
7
+ * _type_marker is a phantom field: it only exists in the TypeScript type
8
+ * system to carry T through inference. It is never assigned at runtime.
9
+ */
10
+ export type ContextKey<T> = {
11
+ readonly description: string;
12
+ readonly _symbol: symbol;
13
+ readonly _type_marker: T;
14
+ };
15
+ export declare function createContextKey<T>(description: string): ContextKey<T>;
@@ -0,0 +1,3 @@
1
+ export function createContextKey(description) {
2
+ return { description, _symbol: Symbol(description) };
3
+ }
@@ -0,0 +1,107 @@
1
+ import { Context } from "./context";
2
+ import type { ContextKey } from "./context_key";
3
+ import { createContextKey } from "./context_key";
4
+ import { PropagateContext } from "./decorators/propagate_context";
5
+ import { SetContext, WithContext } from "./decorators/with_context";
6
+ import { managed, ManagedContext } from "./managed_context";
7
+ export declare function run<T>(transform: (ctx: Context) => Context, fn: () => T | Promise<T>): T | Promise<T>;
8
+ export declare const ContextManager: {
9
+ /**
10
+ * Creates a typed key for storing values in the context.
11
+ * Each call produces a unique key — define it as a module-level constant.
12
+ * @example
13
+ * const TENANT_KEY = ContextManager.createKey<string>("tenant");
14
+ */
15
+ readonly createKey: typeof createContextKey;
16
+ /**
17
+ * Reads the value for a key from the active context.
18
+ * Returns undefined if the key was not set in the current stack.
19
+ */
20
+ readonly get: <T>(key: ContextKey<T>) => T | undefined;
21
+ /**
22
+ * Returns the full active Context (immutable snapshot).
23
+ */
24
+ readonly active: () => Context;
25
+ /**
26
+ * Runs fn within a transformed context.
27
+ * The original context is restored automatically on exit, even on error.
28
+ * @example
29
+ * await ContextManager.run(
30
+ * (ctx) => ctx.set(TENANT_KEY, "acme").set(USER_KEY, user),
31
+ * async () => processOrder(order),
32
+ * );
33
+ */
34
+ readonly run: typeof run;
35
+ /**
36
+ * Class decorator. Captures the active context at each method call site and
37
+ * ensures the method body runs within it. Useful for callbacks, event handlers,
38
+ * or any pattern where the method is invoked outside the original call stack.
39
+ * @example
40
+ * \@ContextManager.Propagate
41
+ * class BleNotificationHandler { ... }
42
+ */
43
+ readonly Propagate: typeof PropagateContext;
44
+ /**
45
+ * Method decorator. Enriches the active context before the method runs.
46
+ * Receives the current context and the instance (`self`), returns the new context.
47
+ * @example
48
+ * class BleOrchestrator {
49
+ * \@ContextManager.Enrich((ctx, self) =>
50
+ * ctx.set(DEVICE_KEY, (self as BleOrchestrator).activeDevice)
51
+ * )
52
+ * async startSession() { ... }
53
+ * }
54
+ */
55
+ readonly Enrich: typeof WithContext;
56
+ /**
57
+ * Shorthand for setting a single key before a method runs.
58
+ * @example
59
+ * \@ContextManager.Set(TENANT_KEY, "clinic-001")
60
+ * async handleRequest() { ... }
61
+ */
62
+ readonly Set: typeof SetContext;
63
+ /**
64
+ * Generator flavor — define acquire and release in one block, `yield` is the hand-off.
65
+ *
66
+ * Code before `yield` runs on enter; code after (or inside `catch`) runs on exit.
67
+ * Pass an optional `key` to also store the value under that key so nested
68
+ * code can read it via `ContextManager.get(key)`. Without a key, use `.get()`.
69
+ *
70
+ * @example
71
+ * // Auto key
72
+ * const dbSession = ContextManager.managed(async function* () {
73
+ * const session = await db.openSession();
74
+ * try { yield session; await session.commit(); }
75
+ * catch (e) { await session.rollback(); throw e; }
76
+ * });
77
+ * await dbSession.use(async () => { const s = dbSession.get()!; });
78
+ *
79
+ * @example
80
+ * // Shared key
81
+ * const SESSION_KEY = ContextManager.createKey<DbSession>("db.session");
82
+ * const dbSession = ContextManager.managed(async function* () {
83
+ * yield await db.openSession();
84
+ * }, SESSION_KEY);
85
+ * await dbSession.use(async () => { const s = ContextManager.get(SESSION_KEY)!; });
86
+ */
87
+ readonly managed: typeof managed;
88
+ /**
89
+ * Class flavor — extend and implement `open()` and `close()`.
90
+ *
91
+ * Familiar OOP shape; gives explicit types and IDE completion on each hook.
92
+ * The key is managed internally — read the value via `.get()`.
93
+ *
94
+ * @example
95
+ * class DbSessionContext extends ContextManager.ManagedContext<DbSession> {
96
+ * open() { return db.openSession(); }
97
+ * close(session, error?) { return error ? session.rollback() : session.commit(); }
98
+ * }
99
+ *
100
+ * const dbSession = new DbSessionContext();
101
+ * await dbSession.use(async () => {
102
+ * const session = dbSession.get()!;
103
+ * await session.insert(order);
104
+ * });
105
+ */
106
+ readonly ManagedContext: typeof ManagedContext;
107
+ };
@@ -0,0 +1,113 @@
1
+ import { getActiveContext, getContext, runWithContext } from "./context_api";
2
+ import { createContextKey } from "./context_key";
3
+ import { PropagateContext } from "./decorators/propagate_context";
4
+ import { SetContext, WithContext } from "./decorators/with_context";
5
+ import { managed, ManagedContext } from "./managed_context";
6
+ export function run(transform, fn) {
7
+ const ctx = transform(getActiveContext());
8
+ return runWithContext(ctx, fn);
9
+ }
10
+ export const ContextManager = {
11
+ /**
12
+ * Creates a typed key for storing values in the context.
13
+ * Each call produces a unique key — define it as a module-level constant.
14
+ * @example
15
+ * const TENANT_KEY = ContextManager.createKey<string>("tenant");
16
+ */
17
+ createKey: createContextKey,
18
+ /**
19
+ * Reads the value for a key from the active context.
20
+ * Returns undefined if the key was not set in the current stack.
21
+ */
22
+ get(key) {
23
+ return getContext(key);
24
+ },
25
+ /**
26
+ * Returns the full active Context (immutable snapshot).
27
+ */
28
+ active() {
29
+ return getActiveContext();
30
+ },
31
+ /**
32
+ * Runs fn within a transformed context.
33
+ * The original context is restored automatically on exit, even on error.
34
+ * @example
35
+ * await ContextManager.run(
36
+ * (ctx) => ctx.set(TENANT_KEY, "acme").set(USER_KEY, user),
37
+ * async () => processOrder(order),
38
+ * );
39
+ */
40
+ run,
41
+ /**
42
+ * Class decorator. Captures the active context at each method call site and
43
+ * ensures the method body runs within it. Useful for callbacks, event handlers,
44
+ * or any pattern where the method is invoked outside the original call stack.
45
+ * @example
46
+ * \@ContextManager.Propagate
47
+ * class BleNotificationHandler { ... }
48
+ */
49
+ Propagate: PropagateContext,
50
+ /**
51
+ * Method decorator. Enriches the active context before the method runs.
52
+ * Receives the current context and the instance (`self`), returns the new context.
53
+ * @example
54
+ * class BleOrchestrator {
55
+ * \@ContextManager.Enrich((ctx, self) =>
56
+ * ctx.set(DEVICE_KEY, (self as BleOrchestrator).activeDevice)
57
+ * )
58
+ * async startSession() { ... }
59
+ * }
60
+ */
61
+ Enrich: WithContext,
62
+ /**
63
+ * Shorthand for setting a single key before a method runs.
64
+ * @example
65
+ * \@ContextManager.Set(TENANT_KEY, "clinic-001")
66
+ * async handleRequest() { ... }
67
+ */
68
+ Set: SetContext,
69
+ /**
70
+ * Generator flavor — define acquire and release in one block, `yield` is the hand-off.
71
+ *
72
+ * Code before `yield` runs on enter; code after (or inside `catch`) runs on exit.
73
+ * Pass an optional `key` to also store the value under that key so nested
74
+ * code can read it via `ContextManager.get(key)`. Without a key, use `.get()`.
75
+ *
76
+ * @example
77
+ * // Auto key
78
+ * const dbSession = ContextManager.managed(async function* () {
79
+ * const session = await db.openSession();
80
+ * try { yield session; await session.commit(); }
81
+ * catch (e) { await session.rollback(); throw e; }
82
+ * });
83
+ * await dbSession.use(async () => { const s = dbSession.get()!; });
84
+ *
85
+ * @example
86
+ * // Shared key
87
+ * const SESSION_KEY = ContextManager.createKey<DbSession>("db.session");
88
+ * const dbSession = ContextManager.managed(async function* () {
89
+ * yield await db.openSession();
90
+ * }, SESSION_KEY);
91
+ * await dbSession.use(async () => { const s = ContextManager.get(SESSION_KEY)!; });
92
+ */
93
+ managed,
94
+ /**
95
+ * Class flavor — extend and implement `open()` and `close()`.
96
+ *
97
+ * Familiar OOP shape; gives explicit types and IDE completion on each hook.
98
+ * The key is managed internally — read the value via `.get()`.
99
+ *
100
+ * @example
101
+ * class DbSessionContext extends ContextManager.ManagedContext<DbSession> {
102
+ * open() { return db.openSession(); }
103
+ * close(session, error?) { return error ? session.rollback() : session.commit(); }
104
+ * }
105
+ *
106
+ * const dbSession = new DbSessionContext();
107
+ * await dbSession.use(async () => {
108
+ * const session = dbSession.get()!;
109
+ * await session.insert(order);
110
+ * });
111
+ */
112
+ ManagedContext,
113
+ };
@@ -0,0 +1,24 @@
1
+ type AnyClass = new (...args: never[]) => object;
2
+ /**
3
+ * Class decorator. Captures the active context at the moment each method is
4
+ * called and ensures the method body runs within that context.
5
+ *
6
+ * Useful for classes whose methods may be invoked from callbacks, event
7
+ * handlers, or fire-and-forget patterns where the caller's context would
8
+ * otherwise be lost by the time the method executes.
9
+ *
10
+ * For the common sequential-await pattern, context propagates automatically
11
+ * via the stack — @PropagateContext adds value mainly when methods are called
12
+ * outside of a runWithContext block or after a timer/event boundary.
13
+ *
14
+ * @example
15
+ * @PropagateContext
16
+ * class BleNotificationService {
17
+ * onHeartRateReading(value: number) {
18
+ * // context active when the listener was registered is visible here
19
+ * const device = getContext(DEVICE_KEY);
20
+ * }
21
+ * }
22
+ */
23
+ export declare function PropagateContext<T extends AnyClass>(target: T): T;
24
+ export {};
@@ -0,0 +1,52 @@
1
+ import { getActiveContext, runWithContext } from "../context_api";
2
+ const PROPAGATED = Symbol("sincpro.context.propagated");
3
+ /**
4
+ * Class decorator. Captures the active context at the moment each method is
5
+ * called and ensures the method body runs within that context.
6
+ *
7
+ * Useful for classes whose methods may be invoked from callbacks, event
8
+ * handlers, or fire-and-forget patterns where the caller's context would
9
+ * otherwise be lost by the time the method executes.
10
+ *
11
+ * For the common sequential-await pattern, context propagates automatically
12
+ * via the stack — @PropagateContext adds value mainly when methods are called
13
+ * outside of a runWithContext block or after a timer/event boundary.
14
+ *
15
+ * @example
16
+ * @PropagateContext
17
+ * class BleNotificationService {
18
+ * onHeartRateReading(value: number) {
19
+ * // context active when the listener was registered is visible here
20
+ * const device = getContext(DEVICE_KEY);
21
+ * }
22
+ * }
23
+ */
24
+ export function PropagateContext(target) {
25
+ if (target[PROPAGATED]) {
26
+ throw new Error(`PropagateContext: ${target.name} is already decorated`);
27
+ }
28
+ const prototype = target.prototype;
29
+ for (const key of Object.getOwnPropertyNames(prototype)) {
30
+ if (key === "constructor")
31
+ continue;
32
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, key);
33
+ if (!descriptor || typeof descriptor.value !== "function")
34
+ continue;
35
+ const original = descriptor.value;
36
+ descriptor.value = function (...args) {
37
+ const ctx = getActiveContext();
38
+ const result = runWithContext(ctx, () => original.apply(this, args));
39
+ if (result instanceof Promise) {
40
+ // Context was captured at call time (above). The Promise itself
41
+ // resolves outside the runWithContext scope — that is expected for
42
+ // the stack-based manager. Sequential awaits inside the method body
43
+ // already saw the correct context when they were initiated.
44
+ return result;
45
+ }
46
+ return result;
47
+ };
48
+ Object.defineProperty(prototype, key, descriptor);
49
+ }
50
+ Object.defineProperty(target, PROPAGATED, { value: true, enumerable: false });
51
+ return target;
52
+ }
@@ -0,0 +1,34 @@
1
+ import { Context } from "../context";
2
+ import type { ContextKey } from "../context_key";
3
+ /**
4
+ * Method decorator. Before calling the method, applies transform to the
5
+ * active context and runs the method within the resulting context.
6
+ *
7
+ * Useful when a method needs to enrich the context with values available
8
+ * on the instance (e.g. the current BLE device, the active session ID).
9
+ *
10
+ * transform receives the current active context and must return the new one.
11
+ * The instance (this) is passed as second argument so instance properties
12
+ * are accessible without closure hacks.
13
+ *
14
+ * @example
15
+ * class BleOrchestrator {
16
+ * private activeDevice: BleDevice;
17
+ *
18
+ * @WithContext((ctx, self) =>
19
+ * ctx.set(DEVICE_KEY, (self as BleOrchestrator).activeDevice)
20
+ * )
21
+ * async startSession() {
22
+ * // DEVICE_KEY is now in context for every nested call
23
+ * }
24
+ * }
25
+ */
26
+ export declare function WithContext(transform: (ctx: Context, self: unknown) => Context): MethodDecorator;
27
+ /**
28
+ * Shorthand for setting a single key before a method runs.
29
+ *
30
+ * @example
31
+ * @SetContext(TENANT_KEY, "clinic-001")
32
+ * async handleRequest() { ... }
33
+ */
34
+ export declare function SetContext<T>(key: ContextKey<T>, value: T): MethodDecorator;
@@ -0,0 +1,44 @@
1
+ import { getActiveContext, runWithContext } from "../context_api";
2
+ /**
3
+ * Method decorator. Before calling the method, applies transform to the
4
+ * active context and runs the method within the resulting context.
5
+ *
6
+ * Useful when a method needs to enrich the context with values available
7
+ * on the instance (e.g. the current BLE device, the active session ID).
8
+ *
9
+ * transform receives the current active context and must return the new one.
10
+ * The instance (this) is passed as second argument so instance properties
11
+ * are accessible without closure hacks.
12
+ *
13
+ * @example
14
+ * class BleOrchestrator {
15
+ * private activeDevice: BleDevice;
16
+ *
17
+ * @WithContext((ctx, self) =>
18
+ * ctx.set(DEVICE_KEY, (self as BleOrchestrator).activeDevice)
19
+ * )
20
+ * async startSession() {
21
+ * // DEVICE_KEY is now in context for every nested call
22
+ * }
23
+ * }
24
+ */
25
+ export function WithContext(transform) {
26
+ return function (_target, _key, descriptor) {
27
+ const original = descriptor.value;
28
+ descriptor.value = function (...args) {
29
+ const ctx = transform(getActiveContext(), this);
30
+ return runWithContext(ctx, () => original.apply(this, args));
31
+ };
32
+ return descriptor;
33
+ };
34
+ }
35
+ /**
36
+ * Shorthand for setting a single key before a method runs.
37
+ *
38
+ * @example
39
+ * @SetContext(TENANT_KEY, "clinic-001")
40
+ * async handleRequest() { ... }
41
+ */
42
+ export function SetContext(key, value) {
43
+ return WithContext((ctx) => ctx.set(key, value));
44
+ }
@@ -0,0 +1,11 @@
1
+ export { ContextManager } from "./context_manager_facade";
2
+ export { Context } from "./context";
3
+ export { getActiveContext, getContext, runWithContext } from "./context_api";
4
+ export type { ContextKey } from "./context_key";
5
+ export { createContextKey } from "./context_key";
6
+ export { PropagateContext } from "./decorators/propagate_context";
7
+ export { SetContext, WithContext } from "./decorators/with_context";
8
+ export type { ContextScope } from "./managed_context";
9
+ export { managed, ManagedContext } from "./managed_context";
10
+ export { _getContextManager, _resetContextManager } from "./context_api";
11
+ export { StackContextManager } from "./stack_context_manager";
@@ -0,0 +1,12 @@
1
+ // Main entry point — public facade for framework consumers
2
+ export { ContextManager } from "./context_manager_facade";
3
+ // Public API — safe for framework consumers
4
+ export { Context } from "./context";
5
+ export { getActiveContext, getContext, runWithContext } from "./context_api";
6
+ export { createContextKey } from "./context_key";
7
+ export { PropagateContext } from "./decorators/propagate_context";
8
+ export { SetContext, WithContext } from "./decorators/with_context";
9
+ export { managed, ManagedContext } from "./managed_context";
10
+ // Internal API — for framework adapters and tests only, not for app consumers
11
+ export { _getContextManager, _resetContextManager } from "./context_api";
12
+ export { StackContextManager } from "./stack_context_manager";
@@ -0,0 +1,87 @@
1
+ import type { ContextKey } from "./context_key";
2
+ /**
3
+ * Contract exposed by both managed context flavors.
4
+ *
5
+ * Acquire the resource, run a block with it in context, then release —
6
+ * all guaranteed even on error.
7
+ */
8
+ export interface ContextScope<T> {
9
+ /**
10
+ * Reads the current value from the active context.
11
+ * Returns `undefined` when called outside an active `use()` block.
12
+ *
13
+ * @example
14
+ * await dbSession.use(async () => {
15
+ * const session = dbSession.get(); // defined here
16
+ * });
17
+ * dbSession.get(); // undefined — outside the block
18
+ */
19
+ get(): T | undefined;
20
+ /**
21
+ * Acquires the resource, pushes it into context, calls `fn`, then releases.
22
+ * The resource is available via `.get()` (or the `fn` argument) throughout
23
+ * the call, including any nested async code on the same stack.
24
+ *
25
+ * @example
26
+ * await dbSession.use(async (session) => {
27
+ * await session.insert(order);
28
+ * });
29
+ */
30
+ use<R>(fn: (value: T) => R | Promise<R>): Promise<R>;
31
+ /**
32
+ * Method decorator. Wraps the decorated method in a `use()` call.
33
+ * The resource is acquired before the method runs and released after.
34
+ * Read the value inside the method via `.get()`.
35
+ *
36
+ * @example
37
+ * class OrderRepository {
38
+ * \@dbSession.inject
39
+ * async save(order: Order) {
40
+ * const session = dbSession.get()!;
41
+ * await session.insert(order);
42
+ * }
43
+ * }
44
+ */
45
+ inject: MethodDecorator;
46
+ }
47
+ export declare function managed<T>(factory: () => AsyncGenerator<T, void, unknown>, key?: ContextKey<T>): ContextScope<T>;
48
+ /**
49
+ * Class flavor — extend and implement `open()` and `close()`.
50
+ *
51
+ * Gives explicit method signatures and IDE completion on each lifecycle hook.
52
+ * The key is managed internally; read the value via `.get()` anywhere in the
53
+ * active stack.
54
+ *
55
+ * Optionally declare a `readonly key` to share the value under a known key,
56
+ * making it readable via `ContextManager.get(key)` from nested code.
57
+ *
58
+ * @example
59
+ * // Auto key — read via instance.get()
60
+ * class DbSessionContext extends ContextManager.ManagedContext<DbSession> {
61
+ * open() { return db.openSession(); }
62
+ * close(session, error?) { return error ? session.rollback() : session.commit(); }
63
+ * }
64
+ * const dbSession = new DbSessionContext();
65
+ * await dbSession.use(async () => {
66
+ * const session = dbSession.get()!;
67
+ * });
68
+ *
69
+ * @example
70
+ * // Shared key — readable via ContextManager.get(SESSION_KEY) from nested code
71
+ * const SESSION_KEY = ContextManager.createKey<DbSession>("db.session");
72
+ * class DbSessionContext extends ContextManager.ManagedContext<DbSession> {
73
+ * readonly key = SESSION_KEY;
74
+ * open() { return db.openSession(); }
75
+ * close(session, error?) { return error ? session.rollback() : session.commit(); }
76
+ * }
77
+ */
78
+ export declare abstract class ManagedContext<T> implements ContextScope<T> {
79
+ readonly key?: ContextKey<T>;
80
+ private _scope;
81
+ private _getScope;
82
+ abstract open(): T | Promise<T>;
83
+ abstract close(value: T, error?: unknown): void | Promise<void>;
84
+ get(): T | undefined;
85
+ use<R>(fn: (value: T) => R | Promise<R>): Promise<R>;
86
+ get inject(): MethodDecorator;
87
+ }