@orangecheck/me-client 0.28.0 → 0.30.0

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/README.md CHANGED
@@ -4,9 +4,9 @@
4
4
  > Hand-written prose below is the high-level overview; the docs site is the source of truth for every export, type, and signature.
5
5
 
6
6
 
7
- Client for [me.ochk.io](https://me.ochk.io). Popup sign-in for any site, framework-agnostic server-side verification, session lifecycle hooks, payment authorization, webhook signature verification, the canonical billable-event taxonomy as TypeScript types. `OcSignInButton` rides the family cookie, so it works only on orangecheck's own sites; anywhere else, sign people in with `signInWithOc()` from `/popup`.
7
+ Client for [me.ochk.io](https://me.ochk.io). Popup sign-in for any site, framework-agnostic server-side verification, session lifecycle hooks, payment authorization, webhook signature verification, the canonical billable-event taxonomy as TypeScript types. Sign people in with `signInWithOc()` from `/popup`; the deprecated `OcSignInButton` rides the family cookie and works only on orangecheck's own sites.
8
8
 
9
- > You pay for sessions and actions, not for clicks.
9
+ > Sign-in is free. Paying your users is optional: always, in promos you schedule, or never.
10
10
 
11
11
  ## Three entry points, three audiences
12
12
 
@@ -73,6 +73,24 @@ export default withOcAuth(handler, {
73
73
 
74
74
  Or set it in code with `requireBond: { minSats: 100_000, minDays: 30, maxAgeSecs: 3600 }`. ochk.io re-checks the coin when its last check is over ten minutes old; `maxAgeSecs` refuses a claim checked longer ago than you accept. From 0.28.0, an account below the floor gets `403 { ok: false, reason: 'bond_required', need: { min_sats, min_days }, have: { sats_floor, days_floor } | null, back_url }`: link the person to `back_url` to back their account. If the project's setting can't be read and never has been, the request gets `503 { reason: 'bond_policy_unavailable' }` rather than being let through unchecked. `readBondClaim(session)` and `bondMeets(session, { minSats, minDays, maxAgeSecs })` are exported for your own checks.
75
75
 
76
+ ## Pay your users, when you choose to
77
+
78
+ Paying the people who use your app is optional. In your project's dashboard you turn it on, schedule promos ("Launch week", Oct 20 to 27), or leave it off. While a pay period runs, each event you send earns the person their share and takes its fee from your balance. Outside every period an event earns and costs nothing, and me.ochk.io records nothing, so you can fire events from code that runs all the time:
79
+
80
+ ```ts
81
+ const res = await oc.event.fire({
82
+ project_key: 'pk_live_yourcompany',
83
+ subtype: 'account_creation',
84
+ signingSecret: process.env.OC_SIGNING_SECRET,
85
+ accountId: didOc,
86
+ });
87
+ if (!res.earned) {
88
+ // res.reason === 'not_paying'; res.next_pay_period says when paying starts, if scheduled
89
+ }
90
+ ```
91
+
92
+ `fireBatch` answers `not_paying` per event. `GET /api/integrator/config` publishes the project's `pay_periods`, past ones included, and `payingAt(periods, date)` tells you whether a project pays at a moment. Pass them to `oc.event.verify(envelope, config, amount, { payPeriods })` to flag a receipt billed outside every period.
93
+
76
94
  ## Session lifecycle
77
95
 
78
96
  Sessions are the billable atom for me.ochk.io: your server fires one `session_creation` event per real session with `oc.event.fire`. `oc.session.create` opens a session and records no charge, and a signin within a still-valid session is **free**. Site declares the policy at integration time; the OC verifier enforces it both client-side and server-side.
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { v as verifyActivityAttestation, r as refreshEnvelopeJwks } from './identity-1VYMOhzV.mjs';
2
2
  export { A as ActivityAttestation, a as ActivityAttestationBundle, b as ActivityVerifyCheck, c as ActivityVerifyResult, V as VerifyActivityOptions, i as identity } from './identity-1VYMOhzV.mjs';
3
- import { E as EventKey, B as BillableEvent, I as IntegratorPriceConfig, S as SessionPolicy, a as Session, T as TelemetryEvent, b as SignInOptions, P as PaymentAuthorizeOptions, c as PaymentResult, V as ValidationResult, f as fromTemplate, g as getArchetypeTemplate, A as ArchetypeTemplate, F as Federation } from './integrator-BVzzkZ6l.mjs';
3
+ import { B as BillableEvent, E as EventKey, I as IntegratorPriceConfig, S as SessionPolicy, a as Session, T as TelemetryEvent, b as SignInOptions, P as PaymentAuthorizeOptions, c as PaymentResult, V as ValidationResult, f as fromTemplate, g as getArchetypeTemplate, A as ArchetypeTemplate, F as Federation } from './integrator-BVzzkZ6l.mjs';
4
4
  export { d as ALL_EVENT_SUBTYPES, e as ARCHETYPE_TEMPLATES, h as AgentClassOverride, i as AttestTier, C as ClassASubtype, j as ClassBSubtype, k as ClassCSubtype, l as ComputedFees, D as DropCadence, m as DropClosedWebhookPayload, n as DropResponseBlock, o as DropScheduleSummary, p as EVENT_SUBTYPES, q as EventClass, r as EventSubtype, s as EventSubtypeMetadata, t as FederationStatus, u as IntegratorArchetype, v as IntegratorEventConfig, M as MAX_DROP_WINDOW_DAYS, w as MIN_INTEGRATOR_PRICE_SATS, x as PLATFORM_FEE_POLICY, y as SigningMethod, z as SiteFeeShape, G as SystemWebhookPayload, W as WebhookHeaders, H as WebhookPayload, J as computeFees, K as subtypesForClass, L as validateIntegratorConfig } from './integrator-BVzzkZ6l.mjs';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
  import * as React from 'react';
@@ -79,6 +79,21 @@ declare const webhook: {
79
79
  fetchJwks: typeof fetchJwksForce;
80
80
  };
81
81
 
82
+ interface PayPeriod {
83
+ id: string;
84
+ name: string;
85
+ starts_at: string;
86
+ ends_at: string | null;
87
+ }
88
+ type PayingState = {
89
+ paying: true;
90
+ period: PayPeriod;
91
+ } | {
92
+ paying: false;
93
+ next: PayPeriod | null;
94
+ };
95
+ declare function payingAt(periods: readonly PayPeriod[], at?: Date): PayingState;
96
+
82
97
  interface FireEventOptions {
83
98
  project_key: string;
84
99
  subtype: EventKey;
@@ -87,11 +102,27 @@ interface FireEventOptions {
87
102
  metadata?: Record<string, unknown>;
88
103
  is_agent?: boolean;
89
104
  signingSecret?: string;
105
+ accountId?: string;
90
106
  userAddress?: string;
91
107
  bearerToken?: string;
92
108
  idempotencyKey?: string;
93
109
  }
94
- declare function fire(options: FireEventOptions): Promise<BillableEvent>;
110
+ type FireEventResult = {
111
+ ok: true;
112
+ earned: true;
113
+ event: BillableEvent;
114
+ webhooks_fired: number;
115
+ escrow_mode: 'simulation' | 'live';
116
+ idempotent_replay?: boolean;
117
+ simulation_mode_note?: string;
118
+ } | {
119
+ ok: true;
120
+ earned: false;
121
+ reason: 'not_paying';
122
+ detail: string;
123
+ next_pay_period: PayPeriod | null;
124
+ };
125
+ declare function fire(options: FireEventOptions): Promise<FireEventResult>;
95
126
  interface BatchEventInput {
96
127
  subtype: EventKey;
97
128
  payment_amount_sats?: number;
@@ -112,6 +143,9 @@ type BatchEventResult = {
112
143
  index: number;
113
144
  status: 'rejected';
114
145
  reason: string;
146
+ } | {
147
+ index: number;
148
+ status: 'not_paying';
115
149
  };
116
150
  interface FireBatchOptions {
117
151
  project_key: string;
@@ -122,6 +156,7 @@ interface FireBatchOptions {
122
156
  interface FireBatchResponse {
123
157
  ok: boolean;
124
158
  results: BatchEventResult[];
159
+ next_pay_period?: PayPeriod | null;
125
160
  escrow_mode: 'simulation' | 'live';
126
161
  simulation_mode_note?: string;
127
162
  }
@@ -129,7 +164,7 @@ declare function fireBatch(options: FireBatchOptions): Promise<FireBatchResponse
129
164
  interface VerifyEventResult {
130
165
  ok: boolean;
131
166
  issues: Array<{
132
- field: 'gross_fee_sats' | 'platform_fee_sats' | 'user_earned_sats' | 'site_rebate_sats' | 'subtype_disabled' | 'subtype_unconfigured' | 'percent_amount_missing';
167
+ field: 'gross_fee_sats' | 'platform_fee_sats' | 'user_earned_sats' | 'site_rebate_sats' | 'subtype_disabled' | 'subtype_unconfigured' | 'percent_amount_missing' | 'outside_pay_period';
133
168
  expected: number | null;
134
169
  actual: number | null;
135
170
  message: string;
@@ -141,7 +176,9 @@ interface VerifyEventResult {
141
176
  site_rebate_sats: number;
142
177
  } | null;
143
178
  }
144
- declare function verify(envelope: BillableEvent, config: IntegratorPriceConfig, payment_amount_sats?: number): VerifyEventResult;
179
+ declare function verify(envelope: BillableEvent, config: IntegratorPriceConfig, payment_amount_sats?: number, opts?: {
180
+ payPeriods?: readonly PayPeriod[];
181
+ }): VerifyEventResult;
145
182
  declare const event: {
146
183
  fire: typeof fire;
147
184
  fireBatch: typeof fireBatch;
@@ -224,9 +261,11 @@ declare const oc: {
224
261
  authorize: (opts: PaymentAuthorizeOptions) => Promise<PaymentResult>;
225
262
  };
226
263
  event: {
227
- fire: (options: FireEventOptions) => Promise<BillableEvent>;
264
+ fire: (options: FireEventOptions) => Promise<FireEventResult>;
228
265
  fireBatch: (options: FireBatchOptions) => Promise<FireBatchResponse>;
229
- verify: (envelope: BillableEvent, config: IntegratorPriceConfig, payment_amount_sats?: number) => VerifyEventResult;
266
+ verify: (envelope: BillableEvent, config: IntegratorPriceConfig, payment_amount_sats?: number, opts?: {
267
+ payPeriods?: readonly PayPeriod[];
268
+ }) => VerifyEventResult;
230
269
  };
231
270
  config: {
232
271
  validate: (cfg: IntegratorPriceConfig) => ValidationResult;
@@ -258,4 +297,4 @@ declare const oc: {
258
297
  };
259
298
  };
260
299
 
261
- export { ArchetypeTemplate, BillableEvent, EventKey, type FamilyScopesOptions, type FamilyScopesResult, type FamilyVerb, Federation, type FireEventOptions, type GrantedOptions, type GrantedResult, IntegratorPriceConfig, MeClientError, type OcPublicJwk, OcSignInButton, type OcSignInButtonProps, PaymentAuthorizeOptions, PaymentResult, type RequestOptions, type Scope, Session, SessionPolicy, SignInOptions, TelemetryEvent, type TrustAttestationCount, ValidationResult, type VerifyEventResult, type VerifyOptions, type VerifyResult, type WithRateLimitRetryOptions, clearBearerToken, config, fromTemplate as configFromTemplate, event, family, federations, getArchetypeTemplate, getBearerToken, getOrigin, oc, onTelemetry, parseTrustAttestationCount, payment, refreshEnvelopeJwks, scope, session, setBearerToken, setOrigin, verifyActivityAttestation, webhook, withRateLimitRetry };
300
+ export { ArchetypeTemplate, type BatchEventResult, BillableEvent, EventKey, type FamilyScopesOptions, type FamilyScopesResult, type FamilyVerb, Federation, type FireBatchResponse, type FireEventOptions, type FireEventResult, type GrantedOptions, type GrantedResult, IntegratorPriceConfig, MeClientError, type OcPublicJwk, OcSignInButton, type OcSignInButtonProps, type PayPeriod, type PayingState, PaymentAuthorizeOptions, PaymentResult, type RequestOptions, type Scope, Session, SessionPolicy, SignInOptions, TelemetryEvent, type TrustAttestationCount, ValidationResult, type VerifyEventResult, type VerifyOptions, type VerifyResult, type WithRateLimitRetryOptions, clearBearerToken, config, fromTemplate as configFromTemplate, event, family, federations, getArchetypeTemplate, getBearerToken, getOrigin, oc, onTelemetry, parseTrustAttestationCount, payingAt, payment, refreshEnvelopeJwks, scope, session, setBearerToken, setOrigin, verifyActivityAttestation, webhook, withRateLimitRetry };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { v as verifyActivityAttestation, r as refreshEnvelopeJwks } from './identity-1VYMOhzV.js';
2
2
  export { A as ActivityAttestation, a as ActivityAttestationBundle, b as ActivityVerifyCheck, c as ActivityVerifyResult, V as VerifyActivityOptions, i as identity } from './identity-1VYMOhzV.js';
3
- import { E as EventKey, B as BillableEvent, I as IntegratorPriceConfig, S as SessionPolicy, a as Session, T as TelemetryEvent, b as SignInOptions, P as PaymentAuthorizeOptions, c as PaymentResult, V as ValidationResult, f as fromTemplate, g as getArchetypeTemplate, A as ArchetypeTemplate, F as Federation } from './integrator-BVzzkZ6l.js';
3
+ import { B as BillableEvent, E as EventKey, I as IntegratorPriceConfig, S as SessionPolicy, a as Session, T as TelemetryEvent, b as SignInOptions, P as PaymentAuthorizeOptions, c as PaymentResult, V as ValidationResult, f as fromTemplate, g as getArchetypeTemplate, A as ArchetypeTemplate, F as Federation } from './integrator-BVzzkZ6l.js';
4
4
  export { d as ALL_EVENT_SUBTYPES, e as ARCHETYPE_TEMPLATES, h as AgentClassOverride, i as AttestTier, C as ClassASubtype, j as ClassBSubtype, k as ClassCSubtype, l as ComputedFees, D as DropCadence, m as DropClosedWebhookPayload, n as DropResponseBlock, o as DropScheduleSummary, p as EVENT_SUBTYPES, q as EventClass, r as EventSubtype, s as EventSubtypeMetadata, t as FederationStatus, u as IntegratorArchetype, v as IntegratorEventConfig, M as MAX_DROP_WINDOW_DAYS, w as MIN_INTEGRATOR_PRICE_SATS, x as PLATFORM_FEE_POLICY, y as SigningMethod, z as SiteFeeShape, G as SystemWebhookPayload, W as WebhookHeaders, H as WebhookPayload, J as computeFees, K as subtypesForClass, L as validateIntegratorConfig } from './integrator-BVzzkZ6l.js';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
  import * as React from 'react';
@@ -79,6 +79,21 @@ declare const webhook: {
79
79
  fetchJwks: typeof fetchJwksForce;
80
80
  };
81
81
 
82
+ interface PayPeriod {
83
+ id: string;
84
+ name: string;
85
+ starts_at: string;
86
+ ends_at: string | null;
87
+ }
88
+ type PayingState = {
89
+ paying: true;
90
+ period: PayPeriod;
91
+ } | {
92
+ paying: false;
93
+ next: PayPeriod | null;
94
+ };
95
+ declare function payingAt(periods: readonly PayPeriod[], at?: Date): PayingState;
96
+
82
97
  interface FireEventOptions {
83
98
  project_key: string;
84
99
  subtype: EventKey;
@@ -87,11 +102,27 @@ interface FireEventOptions {
87
102
  metadata?: Record<string, unknown>;
88
103
  is_agent?: boolean;
89
104
  signingSecret?: string;
105
+ accountId?: string;
90
106
  userAddress?: string;
91
107
  bearerToken?: string;
92
108
  idempotencyKey?: string;
93
109
  }
94
- declare function fire(options: FireEventOptions): Promise<BillableEvent>;
110
+ type FireEventResult = {
111
+ ok: true;
112
+ earned: true;
113
+ event: BillableEvent;
114
+ webhooks_fired: number;
115
+ escrow_mode: 'simulation' | 'live';
116
+ idempotent_replay?: boolean;
117
+ simulation_mode_note?: string;
118
+ } | {
119
+ ok: true;
120
+ earned: false;
121
+ reason: 'not_paying';
122
+ detail: string;
123
+ next_pay_period: PayPeriod | null;
124
+ };
125
+ declare function fire(options: FireEventOptions): Promise<FireEventResult>;
95
126
  interface BatchEventInput {
96
127
  subtype: EventKey;
97
128
  payment_amount_sats?: number;
@@ -112,6 +143,9 @@ type BatchEventResult = {
112
143
  index: number;
113
144
  status: 'rejected';
114
145
  reason: string;
146
+ } | {
147
+ index: number;
148
+ status: 'not_paying';
115
149
  };
116
150
  interface FireBatchOptions {
117
151
  project_key: string;
@@ -122,6 +156,7 @@ interface FireBatchOptions {
122
156
  interface FireBatchResponse {
123
157
  ok: boolean;
124
158
  results: BatchEventResult[];
159
+ next_pay_period?: PayPeriod | null;
125
160
  escrow_mode: 'simulation' | 'live';
126
161
  simulation_mode_note?: string;
127
162
  }
@@ -129,7 +164,7 @@ declare function fireBatch(options: FireBatchOptions): Promise<FireBatchResponse
129
164
  interface VerifyEventResult {
130
165
  ok: boolean;
131
166
  issues: Array<{
132
- field: 'gross_fee_sats' | 'platform_fee_sats' | 'user_earned_sats' | 'site_rebate_sats' | 'subtype_disabled' | 'subtype_unconfigured' | 'percent_amount_missing';
167
+ field: 'gross_fee_sats' | 'platform_fee_sats' | 'user_earned_sats' | 'site_rebate_sats' | 'subtype_disabled' | 'subtype_unconfigured' | 'percent_amount_missing' | 'outside_pay_period';
133
168
  expected: number | null;
134
169
  actual: number | null;
135
170
  message: string;
@@ -141,7 +176,9 @@ interface VerifyEventResult {
141
176
  site_rebate_sats: number;
142
177
  } | null;
143
178
  }
144
- declare function verify(envelope: BillableEvent, config: IntegratorPriceConfig, payment_amount_sats?: number): VerifyEventResult;
179
+ declare function verify(envelope: BillableEvent, config: IntegratorPriceConfig, payment_amount_sats?: number, opts?: {
180
+ payPeriods?: readonly PayPeriod[];
181
+ }): VerifyEventResult;
145
182
  declare const event: {
146
183
  fire: typeof fire;
147
184
  fireBatch: typeof fireBatch;
@@ -224,9 +261,11 @@ declare const oc: {
224
261
  authorize: (opts: PaymentAuthorizeOptions) => Promise<PaymentResult>;
225
262
  };
226
263
  event: {
227
- fire: (options: FireEventOptions) => Promise<BillableEvent>;
264
+ fire: (options: FireEventOptions) => Promise<FireEventResult>;
228
265
  fireBatch: (options: FireBatchOptions) => Promise<FireBatchResponse>;
229
- verify: (envelope: BillableEvent, config: IntegratorPriceConfig, payment_amount_sats?: number) => VerifyEventResult;
266
+ verify: (envelope: BillableEvent, config: IntegratorPriceConfig, payment_amount_sats?: number, opts?: {
267
+ payPeriods?: readonly PayPeriod[];
268
+ }) => VerifyEventResult;
230
269
  };
231
270
  config: {
232
271
  validate: (cfg: IntegratorPriceConfig) => ValidationResult;
@@ -258,4 +297,4 @@ declare const oc: {
258
297
  };
259
298
  };
260
299
 
261
- export { ArchetypeTemplate, BillableEvent, EventKey, type FamilyScopesOptions, type FamilyScopesResult, type FamilyVerb, Federation, type FireEventOptions, type GrantedOptions, type GrantedResult, IntegratorPriceConfig, MeClientError, type OcPublicJwk, OcSignInButton, type OcSignInButtonProps, PaymentAuthorizeOptions, PaymentResult, type RequestOptions, type Scope, Session, SessionPolicy, SignInOptions, TelemetryEvent, type TrustAttestationCount, ValidationResult, type VerifyEventResult, type VerifyOptions, type VerifyResult, type WithRateLimitRetryOptions, clearBearerToken, config, fromTemplate as configFromTemplate, event, family, federations, getArchetypeTemplate, getBearerToken, getOrigin, oc, onTelemetry, parseTrustAttestationCount, payment, refreshEnvelopeJwks, scope, session, setBearerToken, setOrigin, verifyActivityAttestation, webhook, withRateLimitRetry };
300
+ export { ArchetypeTemplate, type BatchEventResult, BillableEvent, EventKey, type FamilyScopesOptions, type FamilyScopesResult, type FamilyVerb, Federation, type FireBatchResponse, type FireEventOptions, type FireEventResult, type GrantedOptions, type GrantedResult, IntegratorPriceConfig, MeClientError, type OcPublicJwk, OcSignInButton, type OcSignInButtonProps, type PayPeriod, type PayingState, PaymentAuthorizeOptions, PaymentResult, type RequestOptions, type Scope, Session, SessionPolicy, SignInOptions, TelemetryEvent, type TrustAttestationCount, ValidationResult, type VerifyEventResult, type VerifyOptions, type VerifyResult, type WithRateLimitRetryOptions, clearBearerToken, config, fromTemplate as configFromTemplate, event, family, federations, getArchetypeTemplate, getBearerToken, getOrigin, oc, onTelemetry, parseTrustAttestationCount, payingAt, payment, refreshEnvelopeJwks, scope, session, setBearerToken, setOrigin, verifyActivityAttestation, webhook, withRateLimitRetry };
package/dist/index.js CHANGED
@@ -339,6 +339,18 @@ function validateIntegratorConfig(cfg) {
339
339
  return { ok: errors.length === 0, errors };
340
340
  }
341
341
 
342
+ // src/pay-periods.ts
343
+ var ms = (iso) => Date.parse(iso);
344
+ function payingAt(periods, at = /* @__PURE__ */ new Date()) {
345
+ const t = at.getTime();
346
+ const current = periods.find(
347
+ (p) => ms(p.starts_at) <= t && (p.ends_at === null || t < ms(p.ends_at))
348
+ );
349
+ if (current) return { paying: true, period: current };
350
+ const next = periods.filter((p) => ms(p.starts_at) > t).sort((a, b) => ms(a.starts_at) - ms(b.starts_at))[0];
351
+ return { paying: false, next: next ?? null };
352
+ }
353
+
342
354
  // src/event.ts
343
355
  async function hmacSha256Hex(secret, message) {
344
356
  const enc = new TextEncoder();
@@ -364,9 +376,13 @@ async function fire(options) {
364
376
  if (!options.subtype) {
365
377
  throw new Error("event.fire requires subtype");
366
378
  }
367
- if (options.userAddress && !options.signingSecret) {
379
+ if (options.accountId !== void 0 && options.userAddress !== void 0 && options.accountId !== options.userAddress) {
380
+ throw new Error("event.fire: accountId and userAddress name different earners");
381
+ }
382
+ const earner = options.accountId ?? options.userAddress;
383
+ if (earner && !options.signingSecret) {
368
384
  throw new Error(
369
- "event.fire: userAddress names who earns, so it requires signingSecret \u2014 the signature over the request body is what authorises that earner. Without the secret, pass bearerToken (or rely on the oc_session cookie) and the caller earns instead."
385
+ "event.fire: accountId names who earns, so it requires signingSecret \u2014 the signature over the request body is what authorises that earner. Without the secret, pass bearerToken (or rely on the oc_session cookie) and the caller earns instead."
370
386
  );
371
387
  }
372
388
  const requestBody = {
@@ -378,7 +394,7 @@ async function fire(options) {
378
394
  if (options.action_label !== void 0) requestBody.action_label = options.action_label;
379
395
  if (options.metadata !== void 0) requestBody.metadata = options.metadata;
380
396
  if (options.is_agent !== void 0) requestBody.is_agent = options.is_agent;
381
- if (options.userAddress !== void 0) requestBody.user_address = options.userAddress;
397
+ if (earner !== void 0) requestBody.user_address = earner;
382
398
  const headers = {};
383
399
  if (options.idempotencyKey) headers["idempotency-key"] = options.idempotencyKey;
384
400
  if (options.signingSecret) {
@@ -421,14 +437,23 @@ async function fireBatch(options) {
421
437
  bearerToken: options.bearerToken
422
438
  });
423
439
  }
424
- function verify(envelope, config2, payment_amount_sats) {
440
+ function verify(envelope, config2, payment_amount_sats, opts = {}) {
425
441
  const issues = [];
442
+ if (opts.payPeriods && !payingAt(opts.payPeriods, new Date(envelope.occurred_at)).paying) {
443
+ issues.push({
444
+ field: "outside_pay_period",
445
+ expected: null,
446
+ actual: null,
447
+ message: `billed at ${envelope.occurred_at}, when ${config2.project_key} wasn't paying its users`
448
+ });
449
+ }
426
450
  const eventCfg = config2.events[envelope.subtype];
427
451
  if (!eventCfg) {
428
452
  return {
429
453
  ok: false,
430
454
  expected: null,
431
455
  issues: [
456
+ ...issues,
432
457
  {
433
458
  field: "subtype_unconfigured",
434
459
  expected: null,
@@ -443,6 +468,7 @@ function verify(envelope, config2, payment_amount_sats) {
443
468
  ok: false,
444
469
  expected: null,
445
470
  issues: [
471
+ ...issues,
446
472
  {
447
473
  field: "subtype_disabled",
448
474
  expected: null,
@@ -457,6 +483,7 @@ function verify(envelope, config2, payment_amount_sats) {
457
483
  ok: false,
458
484
  expected: null,
459
485
  issues: [
486
+ ...issues,
460
487
  {
461
488
  field: "percent_amount_missing",
462
489
  expected: null,
@@ -1574,6 +1601,7 @@ exports.identity = identity;
1574
1601
  exports.oc = oc;
1575
1602
  exports.onTelemetry = onTelemetry;
1576
1603
  exports.parseTrustAttestationCount = parseTrustAttestationCount;
1604
+ exports.payingAt = payingAt;
1577
1605
  exports.payment = payment;
1578
1606
  exports.refreshEnvelopeJwks = refreshEnvelopeJwks;
1579
1607
  exports.scope = scope;