@sincpro/mobile 0.4.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.
@@ -0,0 +1,4 @@
1
+ export declare enum EBuiltinCron {
2
+ CHECK_NETWORK = "CHECK_NETWORK",
3
+ TELEMETRY_FLUSH = "TELEMETRY_FLUSH"
4
+ }
@@ -0,0 +1,5 @@
1
+ export var EBuiltinCron;
2
+ (function (EBuiltinCron) {
3
+ EBuiltinCron["CHECK_NETWORK"] = "CHECK_NETWORK";
4
+ EBuiltinCron["TELEMETRY_FLUSH"] = "TELEMETRY_FLUSH";
5
+ })(EBuiltinCron || (EBuiltinCron = {}));
@@ -1,3 +1,4 @@
1
+ import { EBuiltinCron } from "../../entrypoints/cron/EBuiltinCron";
1
2
  import { loggerCronJobs } from "../../infrastructure/logger";
2
3
  import { CronWorker } from "../../infrastructure/workers";
3
4
  import { networkUseCases } from "../../services/network.service";
@@ -6,5 +7,5 @@ async function checkNetworkStatus() {
6
7
  await networkUseCases.getNetworkStatus();
7
8
  loggerCronJobs.info("Finished checking network status");
8
9
  }
9
- const cronCheckNetworkStatus = new CronWorker("CHECK_NETWORK", checkNetworkStatus, 2.5);
10
+ const cronCheckNetworkStatus = new CronWorker(EBuiltinCron.CHECK_NETWORK, checkNetworkStatus, 2.5);
10
11
  export default cronCheckNetworkStatus;
@@ -155,23 +155,6 @@ async function createSpansQueueTable() {
155
155
  ON ${DATABASE_TABLES.SPANS_QUEUE}(trace_id);
156
156
  `);
157
157
  }
158
- // Adds events and links columns to spans_queue for existing installs.
159
- // Fresh installs get them from createSpansQueueTable above; ALTER TABLE is a
160
- // no-op on those (caught and ignored — duplicate column error is expected).
161
- async function addSpansQueueEventsLinks() {
162
- try {
163
- await DBCursor.execAsync(`ALTER TABLE ${DATABASE_TABLES.SPANS_QUEUE} ADD COLUMN events TEXT NOT NULL DEFAULT '[]'`);
164
- }
165
- catch {
166
- // column already exists on fresh installs
167
- }
168
- try {
169
- await DBCursor.execAsync(`ALTER TABLE ${DATABASE_TABLES.SPANS_QUEUE} ADD COLUMN links TEXT NOT NULL DEFAULT '[]'`);
170
- }
171
- catch {
172
- // column already exists on fresh installs
173
- }
174
- }
175
158
  const MIGRATIONS = [
176
159
  { name: DATABASE_TABLES.SETTINGS, migrationFn: createSettingsTable },
177
160
  { name: DATABASE_TABLES.EVENT_QUEUE, migrationFn: createEventQueueTable },
@@ -183,6 +166,5 @@ const MIGRATIONS = [
183
166
  },
184
167
  { name: DATABASE_TABLES.TELEMETRY_QUEUE, migrationFn: createTelemetryQueueTable },
185
168
  { name: DATABASE_TABLES.SPANS_QUEUE, migrationFn: createSpansQueueTable },
186
- { name: "spans_queue_v2_events_links", migrationFn: addSpansQueueEventsLinks },
187
169
  ];
188
170
  export default MIGRATIONS;
@@ -191,12 +191,12 @@ export function CommonProvider({ children, lightTheme, darkTheme }) {
191
191
  function handleCronStart(payload) {
192
192
  if (!payload || typeof payload !== "object" || !("task" in payload))
193
193
  return;
194
- const { task } = payload;
194
+ const { task, label } = payload;
195
195
  setCronTasks((prev) => {
196
196
  const next = new Map(prev);
197
197
  next.set(task, {
198
198
  id: task,
199
- label: task,
199
+ label: label ?? task,
200
200
  type: "cron",
201
201
  status: "running",
202
202
  startedAt: Date.now(),
@@ -1,4 +1,5 @@
1
1
  import type { TelemetryConfig } from "../infrastructure/telemetry";
2
+ import type { CronWorkerOpts } from "../infrastructure/workers";
2
3
  import type { DomainModule } from "./domain_module";
3
4
  import { Kernel } from "./kernel";
4
5
  export interface AppConfig {
@@ -8,5 +9,12 @@ export interface AppConfig {
8
9
  * after migrations complete — so the `telemetry_queue` table is guaranteed to exist.
9
10
  */
10
11
  telemetry?: TelemetryConfig;
12
+ /**
13
+ * Override display options for any cron by taskName.
14
+ * Useful for showing/hiding toasts on internal crons (CHECK_NETWORK, TELEMETRY_FLUSH, etc.).
15
+ * @example
16
+ * crons: { CHECK_NETWORK: { showToast: true, label: "Verificando conexión" } }
17
+ */
18
+ crons?: Record<string, Partial<CronWorkerOpts>>;
11
19
  }
12
20
  export declare function createApp(config?: AppConfig): Promise<Kernel>;
@@ -4,8 +4,10 @@ import { Kernel } from "./kernel";
4
4
  import { orchestrator } from "./orchestrator";
5
5
  export async function createApp(config = {}) {
6
6
  const kernel = new Kernel([baseModule, ...(config.domains ?? [])]);
7
+ if (config.crons)
8
+ kernel.applyCronConfig(config.crons);
7
9
  orchestrator.configure(kernel);
8
- await orchestrator.bootstrap(); // migrations run here — telemetry_queue is ready
10
+ await orchestrator.bootstrap();
9
11
  if (config.telemetry) {
10
12
  await initTelemetry(config.telemetry);
11
13
  }
@@ -1,6 +1,6 @@
1
1
  import type { IMigration } from "../domain/database";
2
2
  import type { Subscriber } from "../domain/event_sourcing";
3
- import type { CronWorker } from "../infrastructure/workers";
3
+ import type { CronWorker, CronWorkerOpts } from "../infrastructure/workers";
4
4
  import type { DomainModule } from "./domain_module";
5
5
  export declare class Kernel {
6
6
  private readonly modules;
@@ -12,6 +12,7 @@ export declare class Kernel {
12
12
  persistedTables(): string[];
13
13
  subscribersByKey(): Record<string, Subscriber[]>;
14
14
  cronsByKey(): Record<string, CronWorker[]>;
15
+ applyCronConfig(config: Record<string, Partial<CronWorkerOpts>>): void;
15
16
  runMigrations(): Promise<void>;
16
17
  bootstrap(): Promise<void>;
17
18
  restartDatabase(): Promise<void>;
@@ -36,6 +36,14 @@ export class Kernel {
36
36
  }
37
37
  return map;
38
38
  }
39
+ applyCronConfig(config) {
40
+ for (const crons of Object.values(this.cronsByKey())) {
41
+ for (const cron of crons) {
42
+ if (config[cron.taskName])
43
+ cron.configure(config[cron.taskName]);
44
+ }
45
+ }
46
+ }
39
47
  async runMigrations() {
40
48
  for (const { name, migrationFn } of this.migrations()) {
41
49
  logger.info(`Running migration: ${name}`);
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { EBuiltinCron } from "./entrypoints/cron/EBuiltinCron";
1
2
  export type { AppShellConfig } from "./entrypoints/ui/AppShell";
2
3
  export { createAppShell } from "./entrypoints/ui/AppShell";
3
4
  export type { TimezoneLocale } from "./entrypoints/ui/common_provider";
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export { EBuiltinCron } from "./entrypoints/cron/EBuiltinCron";
1
2
  export { createAppShell } from "./entrypoints/ui/AppShell";
2
3
  export { CommonProvider, useCommon } from "./entrypoints/ui/common_provider";
3
4
  export { ActiveDomainApp, DomainSwitcherProvider, useDomainSwitcher, } from "./entrypoints/ui/domain_switcher";
@@ -1,6 +1,7 @@
1
1
  import { InternetIsDownEvent, InternetIsUpEvent, } from "../../domain/connectivity/events";
2
+ import { EBuiltinCron } from "../../entrypoints/cron/EBuiltinCron";
2
3
  import { UIEventBus } from "../../infrastructure/ui/UIEventBus";
3
- import { CronWorker } from "../../infrastructure/workers/CronWorker";
4
+ import { CronWorker } from "../../infrastructure/workers";
4
5
  /** Default background-flush interval (minutes). ≥15 → real OS background task. */
5
6
  export const DEFAULT_BACKGROUND_INTERVAL_MIN = 15;
6
7
  /**
@@ -49,7 +50,7 @@ export class TelemetryFlushWorker {
49
50
  // offline backlog drains promptly when the OS runs the task.
50
51
  const intervalMin = this.opts.backgroundIntervalMin ?? DEFAULT_BACKGROUND_INTERVAL_MIN;
51
52
  if (intervalMin > 0) {
52
- this.cron = new CronWorker("TELEMETRY_FLUSH", () => this.flush.run({ resetBackoff: true }), intervalMin);
53
+ this.cron = new CronWorker(EBuiltinCron.TELEMETRY_FLUSH, () => this.flush.run({ resetBackoff: true }), intervalMin);
53
54
  this.cron.start().catch(() => { });
54
55
  }
55
56
  }
@@ -1,14 +1,22 @@
1
1
  export type CronJob = () => Promise<void>;
2
+ export interface CronWorkerOpts {
3
+ requiresAuth?: boolean;
4
+ label?: string;
5
+ showToast?: boolean;
6
+ }
2
7
  export declare class CronWorker {
3
8
  readonly taskName: string;
4
9
  private readonly job;
5
10
  private readonly intervalMin;
6
- readonly requiresAuth: boolean;
7
11
  private stopFn?;
8
12
  private isRegistering;
9
13
  private isExecuting;
10
14
  private registrationError?;
11
- constructor(taskName: string, job: CronJob, intervalMin?: number, requiresAuth?: boolean);
15
+ readonly requiresAuth: boolean;
16
+ label?: string;
17
+ private showToast;
18
+ constructor(taskName: string, job: CronJob, intervalMin?: number, opts?: CronWorkerOpts);
19
+ configure(opts: Partial<CronWorkerOpts>): void;
12
20
  /**
13
21
  * Registers a task with a specified interval and execution logic.
14
22
  * If the interval is less than 15 minutes, a repeating job is created using a defined stop function.
@@ -6,16 +6,26 @@ export class CronWorker {
6
6
  taskName;
7
7
  job;
8
8
  intervalMin;
9
- requiresAuth;
10
9
  stopFn;
11
10
  isRegistering = false;
12
11
  isExecuting = false;
13
12
  registrationError;
14
- constructor(taskName, job, intervalMin = 15, requiresAuth = false) {
13
+ requiresAuth;
14
+ label;
15
+ showToast;
16
+ constructor(taskName, job, intervalMin = 15, opts = {}) {
15
17
  this.taskName = taskName;
16
18
  this.job = job;
17
19
  this.intervalMin = intervalMin;
18
- this.requiresAuth = requiresAuth;
20
+ this.requiresAuth = opts.requiresAuth ?? false;
21
+ this.label = opts.label;
22
+ this.showToast = opts.showToast ?? false;
23
+ }
24
+ configure(opts) {
25
+ if (opts.label !== undefined)
26
+ this.label = opts.label;
27
+ if (opts.showToast !== undefined)
28
+ this.showToast = opts.showToast;
19
29
  }
20
30
  /**
21
31
  * Registers a task with a specified interval and execution logic.
@@ -106,7 +116,9 @@ export class CronWorker {
106
116
  async runWithEvents(job) {
107
117
  this.isExecuting = true;
108
118
  const startTime = Date.now();
109
- UIEventBus.emit("CRON_START", { task: this.taskName });
119
+ if (this.showToast) {
120
+ UIEventBus.emit("CRON_START", { task: this.taskName, label: this.label });
121
+ }
110
122
  try {
111
123
  await Promise.resolve(job());
112
124
  const duration = Date.now() - startTime;
@@ -119,7 +131,8 @@ export class CronWorker {
119
131
  }
120
132
  finally {
121
133
  this.isExecuting = false;
122
- UIEventBus.emit("CRON_END", { task: this.taskName });
134
+ if (this.showToast)
135
+ UIEventBus.emit("CRON_END", { task: this.taskName });
123
136
  }
124
137
  }
125
138
  /**
@@ -1,2 +1,2 @@
1
- export { CronJob, CronWorker } from "./CronWorker";
1
+ export { CronJob, CronWorker, CronWorkerOpts } from "./CronWorker";
2
2
  export { EventBus, EventName } from "./EventBus";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sincpro/mobile",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Sincpro Mobile framework core: offline-first infra (DB, queue/events, cron), DDD patterns, adapters, AppShell and module-driven composition for React Native",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -27,6 +27,7 @@
27
27
  "author": "Gutierrez, Andres <andres.gutierrez@sincpro.com.bo>",
28
28
  "license": "MIT",
29
29
  "dependencies": {
30
+ "@opentelemetry/api": "^1.9.0",
30
31
  "@opentelemetry/core": "^2.8.0",
31
32
  "@opentelemetry/resources": "^2.8.0",
32
33
  "@opentelemetry/sdk-trace-base": "^2.8.0",
@@ -39,7 +40,6 @@
39
40
  "uuid": "^13.0.0"
40
41
  },
41
42
  "peerDependencies": {
42
- "@opentelemetry/api": ">=1.3.0 <1.10.0",
43
43
  "@react-navigation/native": ">=7",
44
44
  "@react-navigation/native-stack": ">=7",
45
45
  "@sincpro/mobile-ui": "^0.7.2",