@venturekit-pro/billing 0.0.39 → 0.0.41
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 +24 -0
- package/dist/dunning/schedule.d.ts +86 -0
- package/dist/dunning/schedule.d.ts.map +1 -0
- package/dist/dunning/schedule.js +95 -0
- package/dist/dunning/schedule.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -89,6 +89,30 @@ the upgrade prompt and renders through `@venturekit/runtime`'s error boundary
|
|
|
89
89
|
without a runtime dependency. Call `entitlements.invalidate(tenantId)` after a
|
|
90
90
|
plan change.
|
|
91
91
|
|
|
92
|
+
## Dunning
|
|
93
|
+
|
|
94
|
+
Which payment reminder an unpaid invoice is due, for a cron to ask about every open
|
|
95
|
+
invoice. Pure and clock-free; the mail and the invoice model are yours.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { nextDunningStep, dunningScheduleRefusal } from '@venturekit-pro/billing';
|
|
99
|
+
|
|
100
|
+
const schedule = { enabled: true, offsetsDays: [-3, 7, 14, 30] }; // days from the due date
|
|
101
|
+
dunningScheduleRefusal(schedule.offsetsDays); // null, or why the setting is refused
|
|
102
|
+
|
|
103
|
+
const step = nextDunningStep({
|
|
104
|
+
dueDate: invoice.dueDate, // 'YYYY-MM-DD'
|
|
105
|
+
schedule,
|
|
106
|
+
sent: reminders.map((r) => ({ sentAtISO: r.sentAt, offsetDays: r.step })), // step null = sent by a person
|
|
107
|
+
today: todayIn(customer.timezone),
|
|
108
|
+
});
|
|
109
|
+
if (step !== null) await sendReminder(invoice, step); // and record { step } for next time
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The latest step whose day has come is due; each step goes once; steps skipped over
|
|
113
|
+
are gone (the schedule says *when to nudge*, not how many messages to catch up on);
|
|
114
|
+
and a reminder a person sent since the previous step covers the current one.
|
|
115
|
+
|
|
92
116
|
## Usage-to-Invoice Mapping
|
|
93
117
|
|
|
94
118
|
```typescript
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dunning schedule — when an unpaid invoice is due a payment reminder.
|
|
3
|
+
*
|
|
4
|
+
* Every product that invoices ends up chasing payment, and the rule is the same
|
|
5
|
+
* everywhere: a handful of **steps**, each a number of days from the due date
|
|
6
|
+
* (negative before it — "three days to go", positive after — "a week late"),
|
|
7
|
+
* each sent once, and never on top of a human who has already written. Payment
|
|
8
|
+
* processing, the mail itself and the invoice model are the app's; this module
|
|
9
|
+
* is only the decision, pure and clock-free, so a cron can ask it for every open
|
|
10
|
+
* invoice and a test can pin every edge.
|
|
11
|
+
*
|
|
12
|
+
* Three rules, in {@link nextDunningStep}:
|
|
13
|
+
*
|
|
14
|
+
* 1. **The latest step whose day has come is the candidate.** Steps skipped
|
|
15
|
+
* over — the cron was down, the schedule was edited — are gone: the schedule
|
|
16
|
+
* describes *when to nudge*, not a quota of messages to catch up on.
|
|
17
|
+
* 2. **Each step goes once.** A step the schedule already sent (or a later one:
|
|
18
|
+
* a step sent a day late is still that step) is not due again.
|
|
19
|
+
* 3. **Never over a person.** A reminder somebody sent by hand since the
|
|
20
|
+
* previous step's day has done that stretch's nudging; the step is skipped.
|
|
21
|
+
*
|
|
22
|
+
* Days are compared as `YYYY-MM-DD` strings in whatever zone the caller renders
|
|
23
|
+
* them in — the app decides what "today" is for its customers (their business
|
|
24
|
+
* zone, not the server's), and passes it in.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* const schedule = { enabled: true, offsetsDays: [-3, 7, 14, 30] };
|
|
29
|
+
* const step = nextDunningStep({
|
|
30
|
+
* dueDate: invoice.dueDate,
|
|
31
|
+
* schedule,
|
|
32
|
+
* sent: reminders.map((r) => ({ sentAtISO: r.sentAt, offsetDays: r.offsetDays })),
|
|
33
|
+
* today: todayIn('Africa/Casablanca'),
|
|
34
|
+
* });
|
|
35
|
+
* if (step !== null) await sendReminder(invoice, step);
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
/** The steps of a dunning schedule, in days from the invoice's due date. */
|
|
39
|
+
export interface DunningSchedule {
|
|
40
|
+
/** Off means no automatic reminder at all; by-hand reminders are unaffected. */
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
/** Days from the due date; negative is before it. Any order, duplicates ignored. */
|
|
43
|
+
offsetsDays: readonly number[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A reminder already sent about the invoice: when, and — for one the schedule
|
|
47
|
+
* sent — which step it was. `offsetDays: null` is a reminder a person sent.
|
|
48
|
+
*/
|
|
49
|
+
export interface DunningReminderSent {
|
|
50
|
+
sentAtISO: string;
|
|
51
|
+
offsetDays: number | null;
|
|
52
|
+
}
|
|
53
|
+
export interface NextDunningStepInput {
|
|
54
|
+
/** The invoice's due date: `YYYY-MM-DD`, or an ISO instant whose date part is used. */
|
|
55
|
+
dueDate: string;
|
|
56
|
+
schedule: DunningSchedule;
|
|
57
|
+
/** Every reminder already sent about this invoice, by the schedule or by hand. */
|
|
58
|
+
sent: readonly DunningReminderSent[];
|
|
59
|
+
/** Today, `YYYY-MM-DD`, in the zone the app chases in. */
|
|
60
|
+
today: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The bounds a schedule is kept within: a handful of steps, none absurdly far from
|
|
64
|
+
* the due date. Apps that expose the schedule as a setting apply the same bounds on
|
|
65
|
+
* the form ({@link dunningScheduleRefusal}).
|
|
66
|
+
*/
|
|
67
|
+
export declare const DUNNING_SCHEDULE_LIMITS: {
|
|
68
|
+
readonly maxSteps: 8;
|
|
69
|
+
readonly minOffsetDays: -60;
|
|
70
|
+
readonly maxOffsetDays: 365;
|
|
71
|
+
};
|
|
72
|
+
/** Why a schedule's steps are refused, or `null` when they are acceptable. */
|
|
73
|
+
export declare function dunningScheduleRefusal(offsetsDays: readonly number[]): string | null;
|
|
74
|
+
/** The steps as the schedule applies them: distinct, ascending. */
|
|
75
|
+
export declare function normalizeDunningSteps(offsetsDays: readonly number[]): number[];
|
|
76
|
+
/** The `YYYY-MM-DD` part of a date or instant. */
|
|
77
|
+
export declare function dayOf(dateOrInstant: string): string;
|
|
78
|
+
/** `YYYY-MM-DD` moved by `days`, computed in UTC so the calendar arithmetic is zone-free. */
|
|
79
|
+
export declare function addDays(day: string, days: number): string;
|
|
80
|
+
/**
|
|
81
|
+
* The step due today for an invoice, or `null` — see the module note for the
|
|
82
|
+
* three rules. The invoice's own state (paid, void, draft) is the caller's to
|
|
83
|
+
* check first: this decides *which* reminder, not *whether* the invoice is owed.
|
|
84
|
+
*/
|
|
85
|
+
export declare function nextDunningStep({ dueDate, schedule, sent, today }: NextDunningStepInput): number | null;
|
|
86
|
+
//# sourceMappingURL=schedule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../../src/dunning/schedule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,OAAO,EAAE,OAAO,CAAC;IACjB,oFAAoF;IACpF,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,eAAe,CAAC;IAC1B,kFAAkF;IAClF,IAAI,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACrC,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;;CAI1B,CAAC;AAEX,8EAA8E;AAC9E,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAQpF;AAED,mEAAmE;AACnE,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAE9E;AAED,kDAAkD;AAClD,wBAAgB,KAAK,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,6FAA6F;AAC7F,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,oBAAoB,GAAG,MAAM,GAAG,IAAI,CAcvG"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dunning schedule — when an unpaid invoice is due a payment reminder.
|
|
3
|
+
*
|
|
4
|
+
* Every product that invoices ends up chasing payment, and the rule is the same
|
|
5
|
+
* everywhere: a handful of **steps**, each a number of days from the due date
|
|
6
|
+
* (negative before it — "three days to go", positive after — "a week late"),
|
|
7
|
+
* each sent once, and never on top of a human who has already written. Payment
|
|
8
|
+
* processing, the mail itself and the invoice model are the app's; this module
|
|
9
|
+
* is only the decision, pure and clock-free, so a cron can ask it for every open
|
|
10
|
+
* invoice and a test can pin every edge.
|
|
11
|
+
*
|
|
12
|
+
* Three rules, in {@link nextDunningStep}:
|
|
13
|
+
*
|
|
14
|
+
* 1. **The latest step whose day has come is the candidate.** Steps skipped
|
|
15
|
+
* over — the cron was down, the schedule was edited — are gone: the schedule
|
|
16
|
+
* describes *when to nudge*, not a quota of messages to catch up on.
|
|
17
|
+
* 2. **Each step goes once.** A step the schedule already sent (or a later one:
|
|
18
|
+
* a step sent a day late is still that step) is not due again.
|
|
19
|
+
* 3. **Never over a person.** A reminder somebody sent by hand since the
|
|
20
|
+
* previous step's day has done that stretch's nudging; the step is skipped.
|
|
21
|
+
*
|
|
22
|
+
* Days are compared as `YYYY-MM-DD` strings in whatever zone the caller renders
|
|
23
|
+
* them in — the app decides what "today" is for its customers (their business
|
|
24
|
+
* zone, not the server's), and passes it in.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* const schedule = { enabled: true, offsetsDays: [-3, 7, 14, 30] };
|
|
29
|
+
* const step = nextDunningStep({
|
|
30
|
+
* dueDate: invoice.dueDate,
|
|
31
|
+
* schedule,
|
|
32
|
+
* sent: reminders.map((r) => ({ sentAtISO: r.sentAt, offsetDays: r.offsetDays })),
|
|
33
|
+
* today: todayIn('Africa/Casablanca'),
|
|
34
|
+
* });
|
|
35
|
+
* if (step !== null) await sendReminder(invoice, step);
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* The bounds a schedule is kept within: a handful of steps, none absurdly far from
|
|
40
|
+
* the due date. Apps that expose the schedule as a setting apply the same bounds on
|
|
41
|
+
* the form ({@link dunningScheduleRefusal}).
|
|
42
|
+
*/
|
|
43
|
+
export const DUNNING_SCHEDULE_LIMITS = {
|
|
44
|
+
maxSteps: 8,
|
|
45
|
+
minOffsetDays: -60,
|
|
46
|
+
maxOffsetDays: 365,
|
|
47
|
+
};
|
|
48
|
+
/** Why a schedule's steps are refused, or `null` when they are acceptable. */
|
|
49
|
+
export function dunningScheduleRefusal(offsetsDays) {
|
|
50
|
+
const { maxSteps, minOffsetDays, maxOffsetDays } = DUNNING_SCHEDULE_LIMITS;
|
|
51
|
+
if (offsetsDays.length > maxSteps)
|
|
52
|
+
return `At most ${maxSteps} reminder steps`;
|
|
53
|
+
if (offsetsDays.some((d) => !Number.isInteger(d) || d < minOffsetDays || d > maxOffsetDays)) {
|
|
54
|
+
return `Each reminder step is a whole number of days between ${minOffsetDays} and ${maxOffsetDays}`;
|
|
55
|
+
}
|
|
56
|
+
if (new Set(offsetsDays).size !== offsetsDays.length)
|
|
57
|
+
return 'Reminder steps must be distinct';
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/** The steps as the schedule applies them: distinct, ascending. */
|
|
61
|
+
export function normalizeDunningSteps(offsetsDays) {
|
|
62
|
+
return [...new Set(offsetsDays)].sort((a, b) => a - b);
|
|
63
|
+
}
|
|
64
|
+
/** The `YYYY-MM-DD` part of a date or instant. */
|
|
65
|
+
export function dayOf(dateOrInstant) {
|
|
66
|
+
return dateOrInstant.slice(0, 10);
|
|
67
|
+
}
|
|
68
|
+
/** `YYYY-MM-DD` moved by `days`, computed in UTC so the calendar arithmetic is zone-free. */
|
|
69
|
+
export function addDays(day, days) {
|
|
70
|
+
const d = new Date(`${day}T00:00:00Z`);
|
|
71
|
+
d.setUTCDate(d.getUTCDate() + days);
|
|
72
|
+
return d.toISOString().slice(0, 10);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The step due today for an invoice, or `null` — see the module note for the
|
|
76
|
+
* three rules. The invoice's own state (paid, void, draft) is the caller's to
|
|
77
|
+
* check first: this decides *which* reminder, not *whether* the invoice is owed.
|
|
78
|
+
*/
|
|
79
|
+
export function nextDunningStep({ dueDate, schedule, sent, today }) {
|
|
80
|
+
if (!schedule.enabled)
|
|
81
|
+
return null;
|
|
82
|
+
const steps = normalizeDunningSteps(schedule.offsetsDays);
|
|
83
|
+
const due = dayOf(dueDate);
|
|
84
|
+
const dayFor = (offset) => addDays(due, offset);
|
|
85
|
+
const index = steps.filter((offset) => dayFor(offset) <= today).length - 1;
|
|
86
|
+
if (index < 0)
|
|
87
|
+
return null;
|
|
88
|
+
const step = steps[index];
|
|
89
|
+
if (sent.some((r) => r.offsetDays !== null && r.offsetDays >= step))
|
|
90
|
+
return null;
|
|
91
|
+
const previousStepDay = index > 0 ? dayFor(steps[index - 1]) : null;
|
|
92
|
+
const byHandSince = sent.some((r) => r.offsetDays === null && (previousStepDay === null || dayOf(r.sentAtISO) > previousStepDay));
|
|
93
|
+
return byHandSince ? null : step;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../src/dunning/schedule.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,8 @@ export { createFeatureGate, } from './gating/feature-gate.js';
|
|
|
30
30
|
export type { FeatureCheckResult, FeatureGateOptions, } from './gating/feature-gate.js';
|
|
31
31
|
export { resolveEntitlements, createEntitlementsResolver, EntitlementError, } from './entitlements/entitlements.js';
|
|
32
32
|
export type { Entitlements, EntitlementOverrides, EntitlementErrorCode, EntitlementsResolver, EntitlementsResolverOptions, ResolvedFeature, LimitCheck, } from './entitlements/entitlements.js';
|
|
33
|
+
export { nextDunningStep, dunningScheduleRefusal, normalizeDunningSteps, DUNNING_SCHEDULE_LIMITS, } from './dunning/schedule.js';
|
|
34
|
+
export type { DunningSchedule, DunningReminderSent, NextDunningStepInput, } from './dunning/schedule.js';
|
|
33
35
|
/**
|
|
34
36
|
* Returns the path to the billing migration SQL file.
|
|
35
37
|
* Used by `vk migrate` to auto-create billing tables
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EACL,WAAW,EACX,eAAe,EACf,UAAU,EACV,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpE,OAAO,EACL,yBAAyB,EACzB,6BAA6B,EAC7B,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,eAAe,GAChB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EACL,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,YAAY,EACZ,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,WAAW,EACX,YAAY,EACZ,UAAU,GACX,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,gCAAgC,CAAC;AACxC,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,2BAA2B,EAC3B,eAAe,EACf,UAAU,GACX,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EACL,WAAW,EACX,eAAe,EACf,UAAU,EACV,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpE,OAAO,EACL,yBAAyB,EACzB,6BAA6B,EAC7B,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,eAAe,GAChB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EACL,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,YAAY,EACZ,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,WAAW,EACX,YAAY,EACZ,UAAU,GACX,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,gCAAgC,CAAC;AACxC,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,2BAA2B,EAC3B,eAAe,EACf,UAAU,GACX,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAE/B;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAGhD"}
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,8 @@ export { createUsageTracker, createMemoryUsageStore, } from './usage/tracker.js'
|
|
|
33
33
|
export { createFeatureGate, } from './gating/feature-gate.js';
|
|
34
34
|
// Entitlements (plan + overrides → what a tenant may do, HTTP-mapped refusals)
|
|
35
35
|
export { resolveEntitlements, createEntitlementsResolver, EntitlementError, } from './entitlements/entitlements.js';
|
|
36
|
+
// Dunning (which payment reminder an unpaid invoice is due — pure, for a cron)
|
|
37
|
+
export { nextDunningStep, dunningScheduleRefusal, normalizeDunningSteps, DUNNING_SCHEDULE_LIMITS, } from './dunning/schedule.js';
|
|
36
38
|
/**
|
|
37
39
|
* Returns the path to the billing migration SQL file.
|
|
38
40
|
* Used by `vk migrate` to auto-create billing tables
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,QAAQ;AACR,cAAc,kBAAkB,CAAC;AAEjC,0BAA0B;AAC1B,OAAO,EACL,WAAW,EACX,eAAe,EACf,UAAU,EACV,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAG1B,0BAA0B;AAC1B,OAAO,EACL,yBAAyB,EACzB,6BAA6B,EAC7B,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AAOpC,qBAAqB;AACrB,OAAO,EACL,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAMjC,iBAAiB;AACjB,OAAO,EACL,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAO5B,iBAAiB;AACjB,OAAO,EACL,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAMlC,+EAA+E;AAC/E,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,gCAAgC,CAAC;AAWxC;;;;GAIG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AAC5C,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,QAAQ;AACR,cAAc,kBAAkB,CAAC;AAEjC,0BAA0B;AAC1B,OAAO,EACL,WAAW,EACX,eAAe,EACf,UAAU,EACV,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAG1B,0BAA0B;AAC1B,OAAO,EACL,yBAAyB,EACzB,6BAA6B,EAC7B,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AAOpC,qBAAqB;AACrB,OAAO,EACL,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAMjC,iBAAiB;AACjB,OAAO,EACL,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAO5B,iBAAiB;AACjB,OAAO,EACL,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAMlC,+EAA+E;AAC/E,OAAO,EACL,mBAAmB,EACnB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,gCAAgC,CAAC;AAWxC,+EAA+E;AAC/E,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAO/B;;;;GAIG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AAC5C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@venturekit-pro/billing",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.41",
|
|
4
4
|
"description": "Invoicing, plans, usage tracking, and feature gating for VentureKit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@venturekit/core": "0.0.
|
|
33
|
+
"@venturekit/core": "0.0.41"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^26.5.1",
|