@codixus/server 0.1.6 → 0.1.8

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.
package/dist/index.d.cts CHANGED
@@ -265,6 +265,37 @@ interface RestOptions {
265
265
  allowWrite?: (req: AuthenticatedRequest, doc: Record<string, unknown>, patch: Record<string, unknown>) => HookResult;
266
266
  }
267
267
 
268
+ type PushEventSource = "client" | "server" | "system";
269
+ type PushEventDoc = {
270
+ _id: string;
271
+ deviceId: string;
272
+ name: string;
273
+ properties?: Record<string, unknown>;
274
+ source: PushEventSource;
275
+ occurredAt: Date;
276
+ createdAt: Date;
277
+ idempotencyKey?: string;
278
+ journeyEnrollments?: Array<{
279
+ journeyId: string;
280
+ revision: number;
281
+ }>;
282
+ enrollmentStatus?: "pending" | "complete";
283
+ };
284
+ type PushEventTrackInput = {
285
+ deviceId: string;
286
+ name: string;
287
+ properties?: Record<string, unknown>;
288
+ source?: PushEventSource;
289
+ occurredAt?: Date;
290
+ idempotencyKey?: string;
291
+ usersCollection?: string;
292
+ };
293
+ type PushEventTrackResult = {
294
+ created: boolean;
295
+ eventId?: string;
296
+ ignored?: "USER_NOT_FOUND";
297
+ };
298
+
268
299
  type PushMessage = {
269
300
  token: string;
270
301
  title: string;
@@ -274,6 +305,7 @@ type PushMessage = {
274
305
  badge?: number;
275
306
  sound?: string;
276
307
  channelId?: string;
308
+ imageUrl?: string;
277
309
  };
278
310
  type PushTicket = {
279
311
  token: string;
@@ -286,6 +318,7 @@ type PushReceipt = {
286
318
  ticketId: string;
287
319
  status: "ok" | "error";
288
320
  errorCode?: string;
321
+ errorMessage?: string;
289
322
  };
290
323
  interface PushTransport {
291
324
  readonly name: string;
@@ -298,6 +331,11 @@ type PushSendInput = {
298
331
  body: string;
299
332
  data?: Record<string, unknown>;
300
333
  idempotencyKey?: string;
334
+ imageUrl?: string;
335
+ journeyId?: string;
336
+ journeyRevision?: number;
337
+ journeyStepId?: string;
338
+ isTest?: boolean;
301
339
  };
302
340
  type PushSendToInput = {
303
341
  filter: Record<string, unknown>;
@@ -305,6 +343,15 @@ type PushSendToInput = {
305
343
  body: string;
306
344
  data?: Record<string, unknown>;
307
345
  idempotencyKey?: string;
346
+ imageUrl?: string;
347
+ };
348
+ type PushSendResult = {
349
+ deviceId: string;
350
+ token?: string;
351
+ deliveryId?: string;
352
+ status: "submitted" | "failed" | "skipped";
353
+ errorCode?: string;
354
+ errorMessage?: string;
308
355
  };
309
356
  type PushDeviceDoc = {
310
357
  _id: string;
@@ -330,15 +377,142 @@ type PushDeliveryDoc = {
330
377
  title: string;
331
378
  body: string;
332
379
  data?: Record<string, unknown>;
333
- status: "submitted" | "failed" | "opened";
380
+ imageUrl?: string;
381
+ status: "sending" | "submitted" | "failed" | "opened";
334
382
  ticketId?: string;
335
383
  errorCode?: string;
384
+ errorMessage?: string;
336
385
  idempotencyKey: string;
337
386
  createdAt: Date;
338
387
  openedAt?: Date;
339
388
  receiptedAt?: Date;
389
+ updatedAt?: Date;
390
+ journeyId?: string;
391
+ journeyRevision?: number;
392
+ journeyStepId?: string;
393
+ isTest?: boolean;
340
394
  };
341
395
 
396
+ declare class PushService {
397
+ private transport;
398
+ private devicesCol;
399
+ private deliveriesCol;
400
+ constructor(db: Db, transport: PushTransport);
401
+ send(input: PushSendInput): Promise<PushSendResult[]>;
402
+ sendTo(input: PushSendToInput): Promise<PushSendResult[]>;
403
+ pollReceipts(): Promise<void>;
404
+ find(filter: Record<string, unknown>): Promise<PushDeviceDoc[]>;
405
+ }
406
+
407
+ type PushJourneyAudience = {
408
+ operator: "has_event" | "not_has_event";
409
+ eventName: string;
410
+ };
411
+ type PushJourneyStep = {
412
+ id: string;
413
+ offsetSeconds: number;
414
+ title: string;
415
+ body: string;
416
+ imageUrl?: string;
417
+ data?: Record<string, unknown>;
418
+ };
419
+ type PushJourneyDefinition = {
420
+ entryEvent: string;
421
+ audience?: PushJourneyAudience;
422
+ steps: PushJourneyStep[];
423
+ };
424
+ type PushJourneyStatus = "draft" | "live" | "paused";
425
+ type PushJourneyDoc = {
426
+ _id: string;
427
+ name: string;
428
+ status: PushJourneyStatus;
429
+ draft: PushJourneyDefinition;
430
+ revisionCounter: number;
431
+ liveRevision?: number;
432
+ liveEntryEvent?: string;
433
+ liveSince?: Date;
434
+ publishedAt?: Date;
435
+ createdAt: Date;
436
+ updatedAt: Date;
437
+ };
438
+ type PushJourneyRevisionDoc = {
439
+ _id: string;
440
+ journeyId: string;
441
+ revision: number;
442
+ name: string;
443
+ definition: PushJourneyDefinition;
444
+ publishedAt: Date;
445
+ };
446
+ type PushJourneyRunStatus = "active" | "paused" | "completed" | "exited" | "failed";
447
+ type PushJourneyRunDoc = {
448
+ _id: string;
449
+ journeyId: string;
450
+ revision: number;
451
+ eventId: string;
452
+ deviceId: string;
453
+ eventOccurredAt: Date;
454
+ status: PushJourneyRunStatus;
455
+ nextStepIndex: number;
456
+ nextRunAt: Date;
457
+ attempts: number;
458
+ lockedUntil?: Date;
459
+ lockToken?: string;
460
+ lastError?: string;
461
+ createdAt: Date;
462
+ updatedAt: Date;
463
+ completedAt?: Date;
464
+ };
465
+
466
+ declare class JourneyError extends Error {
467
+ readonly code: "NOT_FOUND" | "INVALID_STATE" | "INVALID_INPUT";
468
+ constructor(code: "NOT_FOUND" | "INVALID_STATE" | "INVALID_INPUT", message: string);
469
+ }
470
+ declare class JourneyService {
471
+ private readonly push;
472
+ private readonly journeys;
473
+ private readonly revisions;
474
+ private readonly runs;
475
+ private readonly events;
476
+ constructor(db: Db, push: PushService);
477
+ ensureIndexes(): Promise<void>;
478
+ create(input: {
479
+ name: string;
480
+ definition: PushJourneyDefinition;
481
+ }): Promise<PushJourneyDoc>;
482
+ list(): Promise<PushJourneyDoc[]>;
483
+ get(id: string): Promise<PushJourneyDoc | null>;
484
+ updateDraft(id: string, input: {
485
+ name?: string;
486
+ definition?: PushJourneyDefinition;
487
+ }): Promise<PushJourneyDoc>;
488
+ publish(id: string): Promise<PushJourneyDoc>;
489
+ pause(id: string): Promise<PushJourneyDoc>;
490
+ resume(id: string): Promise<PushJourneyDoc>;
491
+ enrollEvent(event: PushEventDoc): Promise<void>;
492
+ resolveEnrollments(eventName: string): Promise<Array<{
493
+ journeyId: string;
494
+ revision: number;
495
+ }>>;
496
+ processDue(options?: {
497
+ now?: Date;
498
+ limit?: number;
499
+ leaseMs?: number;
500
+ }): Promise<{
501
+ processed: number;
502
+ }>;
503
+ testSend(input: {
504
+ journeyId: string;
505
+ deviceId: string;
506
+ stepId: string;
507
+ }): Promise<PushSendResult[]>;
508
+ private processLockedRun;
509
+ private matchesAudience;
510
+ private retryRun;
511
+ private failRun;
512
+ private requireJourney;
513
+ }
514
+ declare function validateJourneyDefinition(input: PushJourneyDefinition): PushJourneyDefinition;
515
+
342
516
  interface CodixusServerConfig {
343
517
  mongoUri: string;
344
518
  jwtSecret: string;
@@ -350,6 +524,9 @@ interface CodixusServerConfig {
350
524
  push?: {
351
525
  transport: PushTransport;
352
526
  };
527
+ events?: {
528
+ usersCollection?: string;
529
+ };
353
530
  admin?: {
354
531
  token: string;
355
532
  };
@@ -391,10 +568,26 @@ declare class CodixusServer {
391
568
  };
392
569
  push?: {
393
570
  router: () => Router;
394
- send: (input: PushSendInput) => Promise<void>;
395
- sendTo: (input: PushSendToInput) => Promise<void>;
571
+ send: (input: PushSendInput) => Promise<PushSendResult[]>;
572
+ sendTo: (input: PushSendToInput) => Promise<PushSendResult[]>;
396
573
  pollReceipts: () => Promise<void>;
397
574
  find: (filter: Record<string, unknown>) => Promise<PushDeviceDoc[]>;
575
+ journeys: {
576
+ create: JourneyService["create"];
577
+ list: JourneyService["list"];
578
+ get: JourneyService["get"];
579
+ updateDraft: JourneyService["updateDraft"];
580
+ publish: JourneyService["publish"];
581
+ pause: JourneyService["pause"];
582
+ resume: JourneyService["resume"];
583
+ testSend: JourneyService["testSend"];
584
+ processDue: JourneyService["processDue"];
585
+ };
586
+ };
587
+ events: {
588
+ router: () => Router;
589
+ track: (input: PushEventTrackInput) => Promise<PushEventTrackResult>;
590
+ find: (filter: Record<string, unknown>) => Promise<PushEventDoc[]>;
398
591
  };
399
592
  admin?: {
400
593
  router: () => Router;
@@ -423,6 +616,11 @@ declare function validate<T extends z.ZodType>(schema: T): (req: Request, res: R
423
616
  declare function createExpoTransport(opts?: {
424
617
  accessToken?: string;
425
618
  fetchImpl?: typeof fetch;
619
+ sleepImpl?: (delayMs: number) => Promise<void>;
620
+ baseRetryDelayMs?: number;
621
+ maxAttempts?: number;
622
+ requestTimeoutMs?: number;
623
+ maxRetryDelayMs?: number;
426
624
  }): PushTransport;
427
625
 
428
- export { type AuthRouterConfig, type AuthenticatedRequest, CodixusServer, type CodixusServerConfig, type GuardOptions, Model, type ModelDefinition, type ModelType, type PushDeliveryDoc, type PushDeviceDoc, type PushMessage, type PushReceipt, type PushSendInput, type PushSendToInput, type PushTicket, type PushTransport, Query, type RateLimitConfig, RestErrorCode, type RestOptions, type SigningConfig, SubCollection, createExpoTransport, model, validate };
626
+ export { type AuthRouterConfig, type AuthenticatedRequest, CodixusServer, type CodixusServerConfig, type GuardOptions, JourneyError, Model, type ModelDefinition, type ModelType, type PushDeliveryDoc, type PushDeviceDoc, type PushEventDoc, type PushEventSource, type PushEventTrackInput, type PushEventTrackResult, type PushJourneyAudience, type PushJourneyDefinition, type PushJourneyDoc, type PushJourneyRevisionDoc, type PushJourneyRunDoc, type PushJourneyRunStatus, type PushJourneyStatus, type PushJourneyStep, type PushMessage, type PushReceipt, type PushSendInput, type PushSendResult, type PushSendToInput, type PushTicket, type PushTransport, Query, type RateLimitConfig, RestErrorCode, type RestOptions, type SigningConfig, SubCollection, createExpoTransport, model, validate, validateJourneyDefinition };
package/dist/index.d.ts CHANGED
@@ -265,6 +265,37 @@ interface RestOptions {
265
265
  allowWrite?: (req: AuthenticatedRequest, doc: Record<string, unknown>, patch: Record<string, unknown>) => HookResult;
266
266
  }
267
267
 
268
+ type PushEventSource = "client" | "server" | "system";
269
+ type PushEventDoc = {
270
+ _id: string;
271
+ deviceId: string;
272
+ name: string;
273
+ properties?: Record<string, unknown>;
274
+ source: PushEventSource;
275
+ occurredAt: Date;
276
+ createdAt: Date;
277
+ idempotencyKey?: string;
278
+ journeyEnrollments?: Array<{
279
+ journeyId: string;
280
+ revision: number;
281
+ }>;
282
+ enrollmentStatus?: "pending" | "complete";
283
+ };
284
+ type PushEventTrackInput = {
285
+ deviceId: string;
286
+ name: string;
287
+ properties?: Record<string, unknown>;
288
+ source?: PushEventSource;
289
+ occurredAt?: Date;
290
+ idempotencyKey?: string;
291
+ usersCollection?: string;
292
+ };
293
+ type PushEventTrackResult = {
294
+ created: boolean;
295
+ eventId?: string;
296
+ ignored?: "USER_NOT_FOUND";
297
+ };
298
+
268
299
  type PushMessage = {
269
300
  token: string;
270
301
  title: string;
@@ -274,6 +305,7 @@ type PushMessage = {
274
305
  badge?: number;
275
306
  sound?: string;
276
307
  channelId?: string;
308
+ imageUrl?: string;
277
309
  };
278
310
  type PushTicket = {
279
311
  token: string;
@@ -286,6 +318,7 @@ type PushReceipt = {
286
318
  ticketId: string;
287
319
  status: "ok" | "error";
288
320
  errorCode?: string;
321
+ errorMessage?: string;
289
322
  };
290
323
  interface PushTransport {
291
324
  readonly name: string;
@@ -298,6 +331,11 @@ type PushSendInput = {
298
331
  body: string;
299
332
  data?: Record<string, unknown>;
300
333
  idempotencyKey?: string;
334
+ imageUrl?: string;
335
+ journeyId?: string;
336
+ journeyRevision?: number;
337
+ journeyStepId?: string;
338
+ isTest?: boolean;
301
339
  };
302
340
  type PushSendToInput = {
303
341
  filter: Record<string, unknown>;
@@ -305,6 +343,15 @@ type PushSendToInput = {
305
343
  body: string;
306
344
  data?: Record<string, unknown>;
307
345
  idempotencyKey?: string;
346
+ imageUrl?: string;
347
+ };
348
+ type PushSendResult = {
349
+ deviceId: string;
350
+ token?: string;
351
+ deliveryId?: string;
352
+ status: "submitted" | "failed" | "skipped";
353
+ errorCode?: string;
354
+ errorMessage?: string;
308
355
  };
309
356
  type PushDeviceDoc = {
310
357
  _id: string;
@@ -330,15 +377,142 @@ type PushDeliveryDoc = {
330
377
  title: string;
331
378
  body: string;
332
379
  data?: Record<string, unknown>;
333
- status: "submitted" | "failed" | "opened";
380
+ imageUrl?: string;
381
+ status: "sending" | "submitted" | "failed" | "opened";
334
382
  ticketId?: string;
335
383
  errorCode?: string;
384
+ errorMessage?: string;
336
385
  idempotencyKey: string;
337
386
  createdAt: Date;
338
387
  openedAt?: Date;
339
388
  receiptedAt?: Date;
389
+ updatedAt?: Date;
390
+ journeyId?: string;
391
+ journeyRevision?: number;
392
+ journeyStepId?: string;
393
+ isTest?: boolean;
340
394
  };
341
395
 
396
+ declare class PushService {
397
+ private transport;
398
+ private devicesCol;
399
+ private deliveriesCol;
400
+ constructor(db: Db, transport: PushTransport);
401
+ send(input: PushSendInput): Promise<PushSendResult[]>;
402
+ sendTo(input: PushSendToInput): Promise<PushSendResult[]>;
403
+ pollReceipts(): Promise<void>;
404
+ find(filter: Record<string, unknown>): Promise<PushDeviceDoc[]>;
405
+ }
406
+
407
+ type PushJourneyAudience = {
408
+ operator: "has_event" | "not_has_event";
409
+ eventName: string;
410
+ };
411
+ type PushJourneyStep = {
412
+ id: string;
413
+ offsetSeconds: number;
414
+ title: string;
415
+ body: string;
416
+ imageUrl?: string;
417
+ data?: Record<string, unknown>;
418
+ };
419
+ type PushJourneyDefinition = {
420
+ entryEvent: string;
421
+ audience?: PushJourneyAudience;
422
+ steps: PushJourneyStep[];
423
+ };
424
+ type PushJourneyStatus = "draft" | "live" | "paused";
425
+ type PushJourneyDoc = {
426
+ _id: string;
427
+ name: string;
428
+ status: PushJourneyStatus;
429
+ draft: PushJourneyDefinition;
430
+ revisionCounter: number;
431
+ liveRevision?: number;
432
+ liveEntryEvent?: string;
433
+ liveSince?: Date;
434
+ publishedAt?: Date;
435
+ createdAt: Date;
436
+ updatedAt: Date;
437
+ };
438
+ type PushJourneyRevisionDoc = {
439
+ _id: string;
440
+ journeyId: string;
441
+ revision: number;
442
+ name: string;
443
+ definition: PushJourneyDefinition;
444
+ publishedAt: Date;
445
+ };
446
+ type PushJourneyRunStatus = "active" | "paused" | "completed" | "exited" | "failed";
447
+ type PushJourneyRunDoc = {
448
+ _id: string;
449
+ journeyId: string;
450
+ revision: number;
451
+ eventId: string;
452
+ deviceId: string;
453
+ eventOccurredAt: Date;
454
+ status: PushJourneyRunStatus;
455
+ nextStepIndex: number;
456
+ nextRunAt: Date;
457
+ attempts: number;
458
+ lockedUntil?: Date;
459
+ lockToken?: string;
460
+ lastError?: string;
461
+ createdAt: Date;
462
+ updatedAt: Date;
463
+ completedAt?: Date;
464
+ };
465
+
466
+ declare class JourneyError extends Error {
467
+ readonly code: "NOT_FOUND" | "INVALID_STATE" | "INVALID_INPUT";
468
+ constructor(code: "NOT_FOUND" | "INVALID_STATE" | "INVALID_INPUT", message: string);
469
+ }
470
+ declare class JourneyService {
471
+ private readonly push;
472
+ private readonly journeys;
473
+ private readonly revisions;
474
+ private readonly runs;
475
+ private readonly events;
476
+ constructor(db: Db, push: PushService);
477
+ ensureIndexes(): Promise<void>;
478
+ create(input: {
479
+ name: string;
480
+ definition: PushJourneyDefinition;
481
+ }): Promise<PushJourneyDoc>;
482
+ list(): Promise<PushJourneyDoc[]>;
483
+ get(id: string): Promise<PushJourneyDoc | null>;
484
+ updateDraft(id: string, input: {
485
+ name?: string;
486
+ definition?: PushJourneyDefinition;
487
+ }): Promise<PushJourneyDoc>;
488
+ publish(id: string): Promise<PushJourneyDoc>;
489
+ pause(id: string): Promise<PushJourneyDoc>;
490
+ resume(id: string): Promise<PushJourneyDoc>;
491
+ enrollEvent(event: PushEventDoc): Promise<void>;
492
+ resolveEnrollments(eventName: string): Promise<Array<{
493
+ journeyId: string;
494
+ revision: number;
495
+ }>>;
496
+ processDue(options?: {
497
+ now?: Date;
498
+ limit?: number;
499
+ leaseMs?: number;
500
+ }): Promise<{
501
+ processed: number;
502
+ }>;
503
+ testSend(input: {
504
+ journeyId: string;
505
+ deviceId: string;
506
+ stepId: string;
507
+ }): Promise<PushSendResult[]>;
508
+ private processLockedRun;
509
+ private matchesAudience;
510
+ private retryRun;
511
+ private failRun;
512
+ private requireJourney;
513
+ }
514
+ declare function validateJourneyDefinition(input: PushJourneyDefinition): PushJourneyDefinition;
515
+
342
516
  interface CodixusServerConfig {
343
517
  mongoUri: string;
344
518
  jwtSecret: string;
@@ -350,6 +524,9 @@ interface CodixusServerConfig {
350
524
  push?: {
351
525
  transport: PushTransport;
352
526
  };
527
+ events?: {
528
+ usersCollection?: string;
529
+ };
353
530
  admin?: {
354
531
  token: string;
355
532
  };
@@ -391,10 +568,26 @@ declare class CodixusServer {
391
568
  };
392
569
  push?: {
393
570
  router: () => Router;
394
- send: (input: PushSendInput) => Promise<void>;
395
- sendTo: (input: PushSendToInput) => Promise<void>;
571
+ send: (input: PushSendInput) => Promise<PushSendResult[]>;
572
+ sendTo: (input: PushSendToInput) => Promise<PushSendResult[]>;
396
573
  pollReceipts: () => Promise<void>;
397
574
  find: (filter: Record<string, unknown>) => Promise<PushDeviceDoc[]>;
575
+ journeys: {
576
+ create: JourneyService["create"];
577
+ list: JourneyService["list"];
578
+ get: JourneyService["get"];
579
+ updateDraft: JourneyService["updateDraft"];
580
+ publish: JourneyService["publish"];
581
+ pause: JourneyService["pause"];
582
+ resume: JourneyService["resume"];
583
+ testSend: JourneyService["testSend"];
584
+ processDue: JourneyService["processDue"];
585
+ };
586
+ };
587
+ events: {
588
+ router: () => Router;
589
+ track: (input: PushEventTrackInput) => Promise<PushEventTrackResult>;
590
+ find: (filter: Record<string, unknown>) => Promise<PushEventDoc[]>;
398
591
  };
399
592
  admin?: {
400
593
  router: () => Router;
@@ -423,6 +616,11 @@ declare function validate<T extends z.ZodType>(schema: T): (req: Request, res: R
423
616
  declare function createExpoTransport(opts?: {
424
617
  accessToken?: string;
425
618
  fetchImpl?: typeof fetch;
619
+ sleepImpl?: (delayMs: number) => Promise<void>;
620
+ baseRetryDelayMs?: number;
621
+ maxAttempts?: number;
622
+ requestTimeoutMs?: number;
623
+ maxRetryDelayMs?: number;
426
624
  }): PushTransport;
427
625
 
428
- export { type AuthRouterConfig, type AuthenticatedRequest, CodixusServer, type CodixusServerConfig, type GuardOptions, Model, type ModelDefinition, type ModelType, type PushDeliveryDoc, type PushDeviceDoc, type PushMessage, type PushReceipt, type PushSendInput, type PushSendToInput, type PushTicket, type PushTransport, Query, type RateLimitConfig, RestErrorCode, type RestOptions, type SigningConfig, SubCollection, createExpoTransport, model, validate };
626
+ export { type AuthRouterConfig, type AuthenticatedRequest, CodixusServer, type CodixusServerConfig, type GuardOptions, JourneyError, Model, type ModelDefinition, type ModelType, type PushDeliveryDoc, type PushDeviceDoc, type PushEventDoc, type PushEventSource, type PushEventTrackInput, type PushEventTrackResult, type PushJourneyAudience, type PushJourneyDefinition, type PushJourneyDoc, type PushJourneyRevisionDoc, type PushJourneyRunDoc, type PushJourneyRunStatus, type PushJourneyStatus, type PushJourneyStep, type PushMessage, type PushReceipt, type PushSendInput, type PushSendResult, type PushSendToInput, type PushTicket, type PushTransport, Query, type RateLimitConfig, RestErrorCode, type RestOptions, type SigningConfig, SubCollection, createExpoTransport, model, validate, validateJourneyDefinition };