@munchi_oy/license-sdk 0.1.0 → 0.2.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 +5 -2
- package/dist/index.cjs +28 -4
- package/dist/index.d.cts +25 -15
- package/dist/index.d.ts +25 -15
- package/dist/index.js +28 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,8 @@ const license = new LicenseClient({
|
|
|
13
13
|
onError: (e) => logger.error(e, "license service unreachable"),
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
if (await license.can(venueId, "kiosk")) { /*
|
|
16
|
+
if (await license.can(venueId, "kiosk")) { /* may use it now */ }
|
|
17
|
+
if (await license.canView(venueId, "reports")) { /* may still see its data (read-only suspension) */ }
|
|
17
18
|
const kiosks = await license.limit(venueId, "kiosks"); // number, null = unlimited
|
|
18
19
|
const snapshot = await license.entitlements(venueId); // full snapshot, null = unknown venue
|
|
19
20
|
```
|
|
@@ -22,8 +23,10 @@ const snapshot = await license.entitlements(venueId); // full snapshot, null = u
|
|
|
22
23
|
|---|---|
|
|
23
24
|
| Cache per venue, then revalidate with ETag (usually a 304) | `cacheTtlMs` 60 s, and always when the snapshot's `validUntil` passes |
|
|
24
25
|
| Service unreachable | keeps the last snapshot for `maxStaleMs` (24 h); with nothing cached, `can()` allows |
|
|
26
|
+
| Venue unknown to the license service | allows, and calls `onDenied` with `unknown_venue` (never blocks a venue we forgot to set up) |
|
|
27
|
+
| Suspended | `can()` is false; `canView()` stays true for a `read_only` suspension, false for `off` |
|
|
25
28
|
| Request timeout / retries | `timeoutMs` 2 s, one retry on network errors and 5xx |
|
|
26
29
|
| Concurrent calls for one venue | share one request |
|
|
27
|
-
| `mode: "enforce"` | `can()` returns `false` for features the venue doesn't have |
|
|
30
|
+
| `mode: "enforce"` | `can()` returns `false` for features the venue doesn't have, or while it is suspended |
|
|
28
31
|
|
|
29
32
|
Call `invalidate(venueId)` when you receive a `license.changed` event.
|
package/dist/index.cjs
CHANGED
|
@@ -57,16 +57,40 @@ var LicenseClient = class {
|
|
|
57
57
|
if (cached && Date.now() - cached.checkedAt < this.options.maxStaleMs) return cached.snapshot;
|
|
58
58
|
return void 0;
|
|
59
59
|
}
|
|
60
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* May the venue use the feature now (create orders, take payments…)? False while suspended.
|
|
62
|
+
* Never blocks because of us: when the service is down, or doesn't know the venue yet
|
|
63
|
+
* (reported through `onDenied` as `unknown_venue`), it allows.
|
|
64
|
+
*/
|
|
61
65
|
async can(venueId, feature) {
|
|
66
|
+
return this.check(venueId, feature, false);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* May the venue still see the feature's existing data? Like `can()`, but also true during a
|
|
70
|
+
* `read_only` suspension, when nothing new is allowed but history stays visible.
|
|
71
|
+
*/
|
|
72
|
+
async canView(venueId, feature) {
|
|
73
|
+
return this.check(venueId, feature, true);
|
|
74
|
+
}
|
|
75
|
+
async check(venueId, feature, view) {
|
|
62
76
|
const snapshot = await this.entitlements(venueId);
|
|
63
77
|
if (snapshot === void 0) return true;
|
|
64
|
-
|
|
65
|
-
|
|
78
|
+
if (snapshot === null) {
|
|
79
|
+
this.options.onDenied?.({
|
|
80
|
+
venueId,
|
|
81
|
+
feature,
|
|
82
|
+
reason: "unknown_venue"
|
|
83
|
+
});
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
const readOnly = snapshot.suspension?.mode === "read_only";
|
|
87
|
+
const active = snapshot.state !== "suspended" || view && readOnly;
|
|
88
|
+
const licensed = snapshot.features.includes(feature);
|
|
89
|
+
if (licensed && active) return true;
|
|
66
90
|
this.options.onDenied?.({
|
|
67
91
|
venueId,
|
|
68
92
|
feature,
|
|
69
|
-
reason:
|
|
93
|
+
reason: licensed ? "suspended" : "not_licensed"
|
|
70
94
|
});
|
|
71
95
|
return this.options.mode === "report";
|
|
72
96
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
type ProductCode = string;
|
|
2
2
|
type FeatureCode = string;
|
|
3
|
-
interface Rate {
|
|
4
|
-
bps: number;
|
|
5
|
-
fixedMinor: number;
|
|
6
|
-
}
|
|
7
|
-
interface Rates {
|
|
8
|
-
pos: Rate;
|
|
9
|
-
online: Rate;
|
|
10
|
-
kiosk: Rate;
|
|
11
|
-
includeTips: boolean;
|
|
12
|
-
}
|
|
13
3
|
|
|
14
4
|
type LicenseState = "trial" | "active" | "grace" | "start" | "suspended" | "terminated" | "canceled";
|
|
15
5
|
type PaymentMethodStatus = "ok" | "missing" | "failing";
|
|
@@ -40,6 +30,18 @@ interface SnapshotItem {
|
|
|
40
30
|
priceSource: PriceSource;
|
|
41
31
|
}
|
|
42
32
|
type RateSource = "catalog" | "contract" | "license";
|
|
33
|
+
interface ChannelRate {
|
|
34
|
+
bps: number;
|
|
35
|
+
fixedMinor: number;
|
|
36
|
+
source: RateSource;
|
|
37
|
+
}
|
|
38
|
+
interface SnapshotRates {
|
|
39
|
+
/** `null` when card payments at the venue don't go through Munchi (`paymentsMode: "external"`). */
|
|
40
|
+
pos: ChannelRate | null;
|
|
41
|
+
kiosk: ChannelRate | null;
|
|
42
|
+
online: ChannelRate;
|
|
43
|
+
includeTips: boolean;
|
|
44
|
+
}
|
|
43
45
|
interface Snapshot {
|
|
44
46
|
schemaVersion: number;
|
|
45
47
|
v: number;
|
|
@@ -54,9 +56,7 @@ interface Snapshot {
|
|
|
54
56
|
items: SnapshotItem[];
|
|
55
57
|
features: FeatureCode[];
|
|
56
58
|
limits: Record<string, number | null>;
|
|
57
|
-
rates:
|
|
58
|
-
source: RateSource;
|
|
59
|
-
};
|
|
59
|
+
rates: SnapshotRates;
|
|
60
60
|
settings: Record<string, boolean>;
|
|
61
61
|
usage: Record<string, SnapshotUsage>;
|
|
62
62
|
paymentMethod: PaymentMethodStatus;
|
|
@@ -89,7 +89,7 @@ interface LicenseClientOptions {
|
|
|
89
89
|
interface DeniedEvent {
|
|
90
90
|
venueId: number;
|
|
91
91
|
feature: string;
|
|
92
|
-
reason: "not_licensed" | "unknown_venue";
|
|
92
|
+
reason: "not_licensed" | "suspended" | "unknown_venue";
|
|
93
93
|
}
|
|
94
94
|
declare class LicenseClient {
|
|
95
95
|
private readonly cache;
|
|
@@ -101,8 +101,18 @@ declare class LicenseClient {
|
|
|
101
101
|
* `undefined` means the service couldn't be reached and nothing usable is cached.
|
|
102
102
|
*/
|
|
103
103
|
entitlements(venueId: number): Promise<Snapshot | null | undefined>;
|
|
104
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* May the venue use the feature now (create orders, take payments…)? False while suspended.
|
|
106
|
+
* Never blocks because of us: when the service is down, or doesn't know the venue yet
|
|
107
|
+
* (reported through `onDenied` as `unknown_venue`), it allows.
|
|
108
|
+
*/
|
|
105
109
|
can(venueId: number, feature: string): Promise<boolean>;
|
|
110
|
+
/**
|
|
111
|
+
* May the venue still see the feature's existing data? Like `can()`, but also true during a
|
|
112
|
+
* `read_only` suspension, when nothing new is allowed but history stays visible.
|
|
113
|
+
*/
|
|
114
|
+
canView(venueId: number, feature: string): Promise<boolean>;
|
|
115
|
+
private check;
|
|
106
116
|
/** `null` = unlimited, `undefined` = no such limit or no snapshot. */
|
|
107
117
|
limit(venueId: number, key: string): Promise<number | null | undefined>;
|
|
108
118
|
/** Drop the cached snapshot, e.g. after a `license.changed` event. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
type ProductCode = string;
|
|
2
2
|
type FeatureCode = string;
|
|
3
|
-
interface Rate {
|
|
4
|
-
bps: number;
|
|
5
|
-
fixedMinor: number;
|
|
6
|
-
}
|
|
7
|
-
interface Rates {
|
|
8
|
-
pos: Rate;
|
|
9
|
-
online: Rate;
|
|
10
|
-
kiosk: Rate;
|
|
11
|
-
includeTips: boolean;
|
|
12
|
-
}
|
|
13
3
|
|
|
14
4
|
type LicenseState = "trial" | "active" | "grace" | "start" | "suspended" | "terminated" | "canceled";
|
|
15
5
|
type PaymentMethodStatus = "ok" | "missing" | "failing";
|
|
@@ -40,6 +30,18 @@ interface SnapshotItem {
|
|
|
40
30
|
priceSource: PriceSource;
|
|
41
31
|
}
|
|
42
32
|
type RateSource = "catalog" | "contract" | "license";
|
|
33
|
+
interface ChannelRate {
|
|
34
|
+
bps: number;
|
|
35
|
+
fixedMinor: number;
|
|
36
|
+
source: RateSource;
|
|
37
|
+
}
|
|
38
|
+
interface SnapshotRates {
|
|
39
|
+
/** `null` when card payments at the venue don't go through Munchi (`paymentsMode: "external"`). */
|
|
40
|
+
pos: ChannelRate | null;
|
|
41
|
+
kiosk: ChannelRate | null;
|
|
42
|
+
online: ChannelRate;
|
|
43
|
+
includeTips: boolean;
|
|
44
|
+
}
|
|
43
45
|
interface Snapshot {
|
|
44
46
|
schemaVersion: number;
|
|
45
47
|
v: number;
|
|
@@ -54,9 +56,7 @@ interface Snapshot {
|
|
|
54
56
|
items: SnapshotItem[];
|
|
55
57
|
features: FeatureCode[];
|
|
56
58
|
limits: Record<string, number | null>;
|
|
57
|
-
rates:
|
|
58
|
-
source: RateSource;
|
|
59
|
-
};
|
|
59
|
+
rates: SnapshotRates;
|
|
60
60
|
settings: Record<string, boolean>;
|
|
61
61
|
usage: Record<string, SnapshotUsage>;
|
|
62
62
|
paymentMethod: PaymentMethodStatus;
|
|
@@ -89,7 +89,7 @@ interface LicenseClientOptions {
|
|
|
89
89
|
interface DeniedEvent {
|
|
90
90
|
venueId: number;
|
|
91
91
|
feature: string;
|
|
92
|
-
reason: "not_licensed" | "unknown_venue";
|
|
92
|
+
reason: "not_licensed" | "suspended" | "unknown_venue";
|
|
93
93
|
}
|
|
94
94
|
declare class LicenseClient {
|
|
95
95
|
private readonly cache;
|
|
@@ -101,8 +101,18 @@ declare class LicenseClient {
|
|
|
101
101
|
* `undefined` means the service couldn't be reached and nothing usable is cached.
|
|
102
102
|
*/
|
|
103
103
|
entitlements(venueId: number): Promise<Snapshot | null | undefined>;
|
|
104
|
-
/**
|
|
104
|
+
/**
|
|
105
|
+
* May the venue use the feature now (create orders, take payments…)? False while suspended.
|
|
106
|
+
* Never blocks because of us: when the service is down, or doesn't know the venue yet
|
|
107
|
+
* (reported through `onDenied` as `unknown_venue`), it allows.
|
|
108
|
+
*/
|
|
105
109
|
can(venueId: number, feature: string): Promise<boolean>;
|
|
110
|
+
/**
|
|
111
|
+
* May the venue still see the feature's existing data? Like `can()`, but also true during a
|
|
112
|
+
* `read_only` suspension, when nothing new is allowed but history stays visible.
|
|
113
|
+
*/
|
|
114
|
+
canView(venueId: number, feature: string): Promise<boolean>;
|
|
115
|
+
private check;
|
|
106
116
|
/** `null` = unlimited, `undefined` = no such limit or no snapshot. */
|
|
107
117
|
limit(venueId: number, key: string): Promise<number | null | undefined>;
|
|
108
118
|
/** Drop the cached snapshot, e.g. after a `license.changed` event. */
|
package/dist/index.js
CHANGED
|
@@ -33,16 +33,40 @@ var LicenseClient = class {
|
|
|
33
33
|
if (cached && Date.now() - cached.checkedAt < this.options.maxStaleMs) return cached.snapshot;
|
|
34
34
|
return void 0;
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* May the venue use the feature now (create orders, take payments…)? False while suspended.
|
|
38
|
+
* Never blocks because of us: when the service is down, or doesn't know the venue yet
|
|
39
|
+
* (reported through `onDenied` as `unknown_venue`), it allows.
|
|
40
|
+
*/
|
|
37
41
|
async can(venueId, feature) {
|
|
42
|
+
return this.check(venueId, feature, false);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* May the venue still see the feature's existing data? Like `can()`, but also true during a
|
|
46
|
+
* `read_only` suspension, when nothing new is allowed but history stays visible.
|
|
47
|
+
*/
|
|
48
|
+
async canView(venueId, feature) {
|
|
49
|
+
return this.check(venueId, feature, true);
|
|
50
|
+
}
|
|
51
|
+
async check(venueId, feature, view) {
|
|
38
52
|
const snapshot = await this.entitlements(venueId);
|
|
39
53
|
if (snapshot === void 0) return true;
|
|
40
|
-
|
|
41
|
-
|
|
54
|
+
if (snapshot === null) {
|
|
55
|
+
this.options.onDenied?.({
|
|
56
|
+
venueId,
|
|
57
|
+
feature,
|
|
58
|
+
reason: "unknown_venue"
|
|
59
|
+
});
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
const readOnly = snapshot.suspension?.mode === "read_only";
|
|
63
|
+
const active = snapshot.state !== "suspended" || view && readOnly;
|
|
64
|
+
const licensed = snapshot.features.includes(feature);
|
|
65
|
+
if (licensed && active) return true;
|
|
42
66
|
this.options.onDenied?.({
|
|
43
67
|
venueId,
|
|
44
68
|
feature,
|
|
45
|
-
reason:
|
|
69
|
+
reason: licensed ? "suspended" : "not_licensed"
|
|
46
70
|
});
|
|
47
71
|
return this.options.mode === "report";
|
|
48
72
|
}
|
package/package.json
CHANGED