Skip to content

@lastshotlabs/slingshot-push

npm install @lastshotlabs/slingshot-push

Build a deterministic provider idempotency key for a given delivery attempt.

The same (deliveryId, attempt) pair always produces the same string. Pass this value to upstream provider APIs that accept an idempotency token so retries within the same attempt do not produce duplicate sends.

function buildProviderIdempotencyKey(deliveryId: string, attempt: number): string

Source: packages/slingshot-push/src/lib/idempotency.ts

Compile declarative formatter templates into a runtime formatter table.

function compilePushFormatters(templates: Partial<Record<string, PushFormatterTemplate>> = {},): CompiledPushFormatterTable

Source: packages/slingshot-push/src/formatter.ts

Create a notifications delivery adapter backed by the push router.

function createPushDeliveryAdapter(opts: { router: PushRouter; formatters: CompiledPushFormatterTable; skipSources?: string[]; defaults?: NotificationDefaults; /** * Per-call override forwarded into `router.sendToUser`. When omitted, the * router falls back to its construction-time default. */ providerTimeoutMs?: number; }): DeliveryAdapter

Source: packages/slingshot-push/src/deliveryAdapter.ts

Create the multi-provider push package.

Validates rawConfig via pushPluginConfigSchema, mounts the four push entities (subscriptions, topics, topic memberships, deliveries) through the declarative package authoring path, wires Web Push / APNS / FCM providers, mounts the bespoke topic-subscribe / unsubscribe / ack routes, and registers a delivery adapter with slingshot-notifications when present.

Cross-package consumers resolve the runtime via PushRuntimeCap and the aggregated health snapshot via PushHealthCap.

function createPushPackage(rawConfig: PushPluginConfig): SlingshotPackageDefinition

Source: packages/slingshot-push/src/plugin.ts

Create the push router used for user and topic fan-out.

function createPushRouter(options: { providers: Readonly<Partial<Record<PushPlatform, PushProvider>>>; repos: PushRouterRepos; retries?: { maxAttempts?: number; initialDelayMs?: number; maxDelayMs?: number }; bus?: DynamicBus; /** Maximum milliseconds for a single provider.send() call before it is treated as transient failure. Default: 30000. */ providerTimeoutMs?: number; /** Subscriptions per topic-fan-out batch. Default: 1000. */ topicFanoutBatchSize?: number; /** Max concurrent in-flight batches before back-pressure kicks in. Default: 10. */ topicFanoutMaxPending?: number; /** * Optional metrics sink. When provided, the router records per-send * counters/timings, topic fan-out counters, subscription-cleanup counters, * and per-provider circuit-breaker / consecutive-failure gauges so * operators can wire ad-hoc dashboards without parsing logs. Defaults to * a no-op emitter. */ metrics?: MetricsEmitter; /** * Maximum subscriptions that may receive a single topic publish before the * router emits `push:topic.fanout.truncated`, returns a partial result, and * stops scheduling further batches. Default: 10000. P-PUSH-11. */ topicMaxRecipients?: number; /** * Router-level circuit breaker threshold — consecutive total-fan-out * failures (every subscription in a sendToUser/sendToUsers/publishTopic * returned allFailed) before the breaker opens and short-circuits * subsequent sends. Default: 10. Set to 0 to disable the router-level * breaker. */ routerCircuitBreakerThreshold?: number; /** * Router-level circuit breaker cooldown in ms before admitting a * half-open probe after the breaker opens. Default: 30000. */ routerCircuitBreakerCooldownMs?: number; }): PushRouter

Source: packages/slingshot-push/src/router.ts

Derive a deterministic UUID v4-shaped string from an arbitrary key.

Hashes the input with SHA-256, then reformats the first 16 bytes into the canonical 8-4-4-4-12 hex layout, setting the version (4) and variant (RFC 4122) bits. The output is byte-stable for a given input — useful for headers like APNs apns-id that require a UUID but where idempotency derives from a caller-controlled token.

function deriveUuidV4FromKey(key: string): string

Source: packages/slingshot-push/src/lib/idempotency.ts

Provider-owned package contract for slingshot-push.

Source: packages/slingshot-push/src/public.ts

Capability for reading the aggregated push health snapshot.

Consumers resolve via ctx.capabilities.require(PushHealthCap)() and receive a PushPluginHealth representing provider and router state at call time.

Source: packages/slingshot-push/src/public.ts

Config schema for createPushPackage().

FieldDescription
androidService-account private key used to authenticate with Firebase.
enabledPlatformsPlatforms this plugin should deliver to. One or more of: web, ios, android.
iosDefault iOS app bundle identifier used when a notification does not provide one. Omit to require bundle IDs per target.’, ), defaultEnvironment: z .enum([‘sandbox’, ‘production’]) .optional() .describe( ‘Default APNS environment. One of: sandbox, production. Omit to use the provider default.’, ), }) .optional() .describe(‘iOS push configuration for APNS delivery. Omit when iOS push is not enabled.
notificationsDefault notification icon URL. Omit to send no default icon.
webWeb push configuration for browser clients. Omit when web push is not enabled.

Source: packages/slingshot-push/src/types/config.ts

Capability handle for the push notifications runtime.

Cross-package consumers (notably slingshot-chat for formatter registration) resolve it through ctx.capabilities.require(PushRuntimeCap).

Source: packages/slingshot-push/src/public.ts

Entity definition for one delivery attempt against one subscription.

Source: packages/slingshot-push/src/entities/pushDelivery.ts

Store-type keyed factories for PushDelivery.

Source: packages/slingshot-push/src/entities/factories.ts

Generated operations for push delivery lifecycle transitions.

Source: packages/slingshot-push/src/entities/pushDelivery.ts

Capability handle for the push formatter registry.

Cross-package consumers (notably slingshot-chat and slingshot-community during their setupPost hooks) resolve it via ctx.capabilities.require(PushFormatterRegistryCap) to install per-source formatters without reaching into push’s full runtime state.

Source: packages/slingshot-push/src/public.ts

Entity definition for persisted device subscriptions across all platforms.

Source: packages/slingshot-push/src/entities/pushSubscription.ts

Store-type keyed factories for PushSubscription.

Source: packages/slingshot-push/src/entities/factories.ts

Generated operations for subscription upsert, lookup, and touch flows.

Source: packages/slingshot-push/src/entities/pushSubscription.ts

Entity definition for named push topics.

Source: packages/slingshot-push/src/entities/pushTopic.ts

Store-type keyed factories for PushTopic.

Source: packages/slingshot-push/src/entities/factories.ts

Entity definition linking subscriptions to topics.

Source: packages/slingshot-push/src/entities/pushTopicMembership.ts

Store-type keyed factories for PushTopicMembership.

Source: packages/slingshot-push/src/entities/factories.ts

Generated operations for topic membership fan-out and cleanup.

Source: packages/slingshot-push/src/entities/pushTopicMembership.ts

Generated operations for ensuring and resolving topics by name.

Source: packages/slingshot-push/src/entities/pushTopic.ts

Thrown when the APNS provider encounters a delivery failure that cannot be attributed to a subscription-level issue (invalidToken, payloadTooLarge).

Source: packages/slingshot-push/src/errors.ts

Error thrown by FcmAccessTokenProvider.getToken() when the OAuth token exchange returns an HTTP error. statusCode is set when the failure was an HTTP response (vs. a network/parse error) so callers can distinguish permanent auth failures (401/403) from transient ones (5xx, network).

Source: packages/slingshot-push/src/providers/fcm.ts

Thrown when the push router encounters a routing-level failure (e.g., circuit breaker open, all providers unreachable, invalid router state).

Source: packages/slingshot-push/src/errors.ts

Thrown when a topic fan-out operation fails due to a routing-level issue (e.g., topic resolution failure, membership enumeration error).

Source: packages/slingshot-push/src/errors.ts

Thrown when the Web Push provider encounters a delivery failure that cannot be attributed to a subscription-level issue (invalidToken, payloadTooLarge).

Source: packages/slingshot-push/src/errors.ts

Compiled formatter registry used by the push delivery adapter.

Source: packages/slingshot-push/src/state.ts

Minimal FCM service-account fields required by the HTTP v1 provider.

Source: packages/slingshot-push/src/types/config.ts

Default values applied by the notifications delivery adapter.

Source: packages/slingshot-push/src/types/models.ts

Delivery-attempt record for one notification sent to one subscription.

Source: packages/slingshot-push/src/types/models.ts

Minimum surface peer plugins (community, chat) need from the push runtime to install per-source formatters. Intentionally narrower than the full PushPluginState so consumers don’t pull in router / providers.

Source: packages/slingshot-push/src/public.ts

Declarative formatter template.

Source: packages/slingshot-push/src/types/config.ts

Normalized push payload delivered across all providers.

Source: packages/slingshot-push/src/types/models.ts

Aggregated health snapshot for slingshot-push.

status is derived from the underlying signals:

  • 'unhealthy' when any provider’s circuit breaker is open, or when the router-level breaker is open.
  • 'degraded' when any provider’s circuit is half-open, any provider has accumulated consecutiveFailures > 0, or the router-level breaker is half-open.
  • 'healthy' otherwise.

Source: packages/slingshot-push/src/public.ts

Runtime state published by createPushPackage().

Source: packages/slingshot-push/src/state.ts

Provider contract implemented by Web Push, APNS, and FCM adapters.

Source: packages/slingshot-push/src/providers/provider.ts

Per-provider observability snapshot. Cross-package consumers should read the aggregated push health via PushHealthCap; this provider-internal getHealth() hook is what the package uses to populate that capability.

Implementations must keep this cheap (no I/O) — it is read from a health endpoint and may be polled.

Source: packages/slingshot-push/src/providers/provider.ts

Router API used for user fan-out and topic publishes.

Source: packages/slingshot-push/src/router.ts

Repository bundle required by the push router.

Source: packages/slingshot-push/src/router.ts

Normalized provider send result consumed by createPushRouter().

Source: packages/slingshot-push/src/types/models.ts

Result of a router fan-out call.

The router does not throw when every provider fails — see README “All-providers-fail contract”. Callers can detect total failure via allFailed without inspecting the bus.

  • delivered — number of subscriptions successfully sent (provider returned ok: true).
  • attempted — number of subscriptions for which delivery was attempted (i.e. had a matching provider configured for the platform). Subscriptions skipped because no provider is wired for their platform are not counted.
  • allFailedtrue iff attempted > 0 && delivered === 0. false when at least one subscription was delivered or when no subscription was even attempted.

Source: packages/slingshot-push/src/router.ts

Persisted push-subscription record.

Source: packages/slingshot-push/src/types/models.ts

Named push topic for multi-device fan-out.

Source: packages/slingshot-push/src/types/models.ts

Membership record linking a subscription to a topic.

Source: packages/slingshot-push/src/types/models.ts

APNS auth input accepted by the push package config.

Source: packages/slingshot-push/src/types/config.ts

Platform-specific credential payload stored on a push subscription.

Source: packages/slingshot-push/src/types/models.ts

Imperative formatter escape hatch used after config compilation.

Source: packages/slingshot-push/src/types/config.ts

Supported push delivery platforms.

Source: packages/slingshot-push/src/types/models.ts

Validated and transformed push plugin configuration produced by pushPluginConfigSchema.

Source: packages/slingshot-push/src/types/config.ts

Bespoke routes owned by the push plugin.

Source: packages/slingshot-push/src/types/config.ts