@schematichq/schematic-angular 1.4.0 → 1.6.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
|
@@ -202,6 +202,86 @@ export class EntitlementComponent {
|
|
|
202
202
|
|
|
203
203
|
*Note: `isPending$` checks if entitlement data has been loaded, typically via `identify`. It should be used to wrap flag and entitlement checks, but never the initial call to `identify`.*
|
|
204
204
|
|
|
205
|
+
For features metered by credit burndown, the emitted entitlement also carries the company's credit position:
|
|
206
|
+
|
|
207
|
+
| Property | Type | Description |
|
|
208
|
+
| --- | --- | --- |
|
|
209
|
+
| `creditId` | `string \| undefined` | The ID of the credit funding this feature |
|
|
210
|
+
| `creditSettled` | `number \| undefined` | The spendable balance, including any amount held by an open lease. This is the number to show end users |
|
|
211
|
+
| `creditRemaining` | `number \| undefined` | The balance available to fund new consumption, excluding any open lease hold |
|
|
212
|
+
| `creditReserved` | `number \| undefined` | The unspent amount held by an open credit lease, `0` when none is open |
|
|
213
|
+
|
|
214
|
+
All four are `undefined` when the feature is not credit-based.
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
@Component({
|
|
218
|
+
selector: "app-credit-feature",
|
|
219
|
+
standalone: true,
|
|
220
|
+
imports: [AsyncPipe],
|
|
221
|
+
template: `
|
|
222
|
+
@if (entitlement$ | async; as entitlement) {
|
|
223
|
+
@if (entitlement.value) {
|
|
224
|
+
<app-feature [creditsRemaining]="entitlement.creditSettled" />
|
|
225
|
+
} @else {
|
|
226
|
+
<app-out-of-credits />
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
`,
|
|
230
|
+
})
|
|
231
|
+
export class CreditFeatureComponent {
|
|
232
|
+
private schematic = inject(SchematicService);
|
|
233
|
+
entitlement$ = this.schematic.entitlement$("my-flag-key");
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
These values refresh with each flag check. For a balance that also updates on the credit partials arriving between checks, pipe `creditId` into [`creditBalance$`](#credit-balances) instead.
|
|
238
|
+
|
|
239
|
+
### Usage warnings
|
|
240
|
+
|
|
241
|
+
If a usage warning is configured on the entitlement, the emitted entitlement carries it as `warningTiers`, so you can warn a customer before they hit the limit rather than after:
|
|
242
|
+
|
|
243
|
+
| Property | Type | Description |
|
|
244
|
+
| --- | --- | --- |
|
|
245
|
+
| `warningTiers` | `WarningTier[] \| undefined` | The usage warning thresholds configured on the entitlement, each a `{ key, value }` pair in the entitlement's usage units. `undefined` when none are configured |
|
|
246
|
+
| `softLimit` | `number \| undefined` | For usage-based pricing, the soft limit for overage charges or the next tier boundary |
|
|
247
|
+
|
|
248
|
+
The dashboard writes a single tier under the key `default`.
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { Component, inject } from "@angular/core";
|
|
252
|
+
import { AsyncPipe } from "@angular/common";
|
|
253
|
+
import { map } from "rxjs";
|
|
254
|
+
import { SchematicService } from "@schematichq/schematic-angular";
|
|
255
|
+
|
|
256
|
+
@Component({
|
|
257
|
+
selector: "app-usage-warning",
|
|
258
|
+
standalone: true,
|
|
259
|
+
imports: [AsyncPipe],
|
|
260
|
+
template: `
|
|
261
|
+
@if (approachingLimit$ | async) {
|
|
262
|
+
<app-approaching-limit />
|
|
263
|
+
}
|
|
264
|
+
<app-feature />
|
|
265
|
+
`,
|
|
266
|
+
})
|
|
267
|
+
export class UsageWarningComponent {
|
|
268
|
+
private schematic = inject(SchematicService);
|
|
269
|
+
entitlement$ = this.schematic.entitlement$("my-flag-key");
|
|
270
|
+
approachingLimit$ = this.entitlement$.pipe(
|
|
271
|
+
map((entitlement) => {
|
|
272
|
+
const warning = entitlement.warningTiers?.find(
|
|
273
|
+
(tier) => tier.key === "default",
|
|
274
|
+
);
|
|
275
|
+
return (
|
|
276
|
+
typeof entitlement.featureUsage === "number" &&
|
|
277
|
+
typeof warning?.value === "number" &&
|
|
278
|
+
entitlement.featureUsage >= warning.value
|
|
279
|
+
);
|
|
280
|
+
}),
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
205
285
|
### Checking plans
|
|
206
286
|
|
|
207
287
|
Use `plan$` to get an Observable of the current plan information:
|
|
@@ -229,6 +309,73 @@ export class PlanComponent {
|
|
|
229
309
|
}
|
|
230
310
|
```
|
|
231
311
|
|
|
312
|
+
### Credit balances
|
|
313
|
+
|
|
314
|
+
Use `creditBalance$` to observe a company's credit balance. It is keyed by credit ID and emits as the balance changes over the DataStream:
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
import { Component, inject } from "@angular/core";
|
|
318
|
+
import { AsyncPipe } from "@angular/common";
|
|
319
|
+
import { SchematicService } from "@schematichq/schematic-angular";
|
|
320
|
+
|
|
321
|
+
@Component({
|
|
322
|
+
selector: "app-credit-meter",
|
|
323
|
+
standalone: true,
|
|
324
|
+
imports: [AsyncPipe],
|
|
325
|
+
template: `
|
|
326
|
+
@if (creditBalance$ | async; as credit) {
|
|
327
|
+
@if (credit.isLoading) {
|
|
328
|
+
<div>Loading…</div>
|
|
329
|
+
} @else {
|
|
330
|
+
<div>{{ credit.balance }} credits remaining</div>
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
`,
|
|
334
|
+
})
|
|
335
|
+
export class CreditMeterComponent {
|
|
336
|
+
private schematic = inject(SchematicService);
|
|
337
|
+
creditBalance$ = this.schematic.creditBalance$("credit-id");
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
`creditBalance$` emits an object with the following properties:
|
|
342
|
+
|
|
343
|
+
| Property | Type | Description |
|
|
344
|
+
| --- | --- | --- |
|
|
345
|
+
| `balance` | `number` | The spendable balance, or `0` while loading or when the company holds no balance in this credit |
|
|
346
|
+
| `isLoading` | `boolean` | `true` while the balance is still loading and no value has arrived yet |
|
|
347
|
+
|
|
348
|
+
It surfaces the `settled` (spendable) balance. The credit ID is available on a feature's entitlement, and `creditBalance$` accepts an Observable of credit IDs as well as a plain one, so you can pipe the entitlement straight in:
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
import { map } from "rxjs";
|
|
352
|
+
|
|
353
|
+
@Component({
|
|
354
|
+
selector: "app-credit-meter",
|
|
355
|
+
standalone: true,
|
|
356
|
+
imports: [AsyncPipe],
|
|
357
|
+
template: `
|
|
358
|
+
@if (creditBalance$ | async; as credit) {
|
|
359
|
+
@if (credit.isLoading) {
|
|
360
|
+
<div>Loading…</div>
|
|
361
|
+
} @else {
|
|
362
|
+
<div>{{ credit.balance }} credits remaining</div>
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
`,
|
|
366
|
+
})
|
|
367
|
+
export class CreditMeterComponent {
|
|
368
|
+
private schematic = inject(SchematicService);
|
|
369
|
+
creditBalance$ = this.schematic.creditBalance$(
|
|
370
|
+
this.schematic
|
|
371
|
+
.entitlement$("my-flag-key")
|
|
372
|
+
.pipe(map((entitlement) => entitlement.creditId)),
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
It switches to the new credit as the source emits. While the ID is `undefined`, it emits the client's loading state and a balance of `0`.
|
|
378
|
+
|
|
232
379
|
## API Reference
|
|
233
380
|
|
|
234
381
|
### `provideSchematic(config)`
|
|
@@ -248,6 +395,7 @@ Injectable service providing all Schematic functionality:
|
|
|
248
395
|
| `flagValue$(key, fallback?)` | `Observable<boolean>` | Observe a feature flag's boolean value |
|
|
249
396
|
| `entitlement$(key, fallback?)` | `Observable<CheckFlagReturn>` | Observe detailed entitlement data |
|
|
250
397
|
| `plan$()` | `Observable<CheckPlanReturn \| undefined>` | Observe plan information |
|
|
398
|
+
| `creditBalance$(creditId)` | `Observable<SchematicCreditBalance>` | Observe a company's lease-aware credit balance. Takes a credit ID or an Observable of credit IDs |
|
|
251
399
|
| `isPending$()` | `Observable<boolean>` | Observe loading state |
|
|
252
400
|
|
|
253
401
|
### `SCHEMATIC_CLIENT`
|
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { InjectionToken, inject, Injectable, makeEnvironmentProviders, DestroyRef } from '@angular/core';
|
|
3
3
|
import * as SchematicJS from '@schematichq/schematic-js';
|
|
4
4
|
export { RuleType, Schematic, TrialStatus, UsagePeriod } from '@schematichq/schematic-js';
|
|
5
|
-
import { Observable, distinctUntilChanged, shareReplay, finalize } from 'rxjs';
|
|
5
|
+
import { Observable, distinctUntilChanged, shareReplay, finalize, isObservable, switchMap, map } from 'rxjs';
|
|
6
6
|
|
|
7
7
|
const SCHEMATIC_CLIENT = new InjectionToken("SchematicClient");
|
|
8
8
|
|
|
@@ -28,6 +28,7 @@ class SchematicService {
|
|
|
28
28
|
client = inject(SCHEMATIC_CLIENT);
|
|
29
29
|
flagValueCache = new Map();
|
|
30
30
|
entitlementCache = new Map();
|
|
31
|
+
creditBalanceCache = new Map();
|
|
31
32
|
planCache;
|
|
32
33
|
isPendingCache;
|
|
33
34
|
getClient() {
|
|
@@ -95,6 +96,59 @@ class SchematicService {
|
|
|
95
96
|
}));
|
|
96
97
|
return this.planCache;
|
|
97
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Observe a company's live, lease-aware credit balance for a single credit type.
|
|
101
|
+
*
|
|
102
|
+
* Surfaces the spendable `settled` balance, sourced from the streamed credit
|
|
103
|
+
* balances map (keyed by credit ID). It emits as partials arrive over the
|
|
104
|
+
* DataStream, so it stays accurate during an open lease — when the raw
|
|
105
|
+
* `remaining` would otherwise read stale / falsely "exhausted".
|
|
106
|
+
*
|
|
107
|
+
* The credit ID is available on a feature's entitlement: `entitlement$(key)`
|
|
108
|
+
* emits `creditId` for credit-based features. Pass that stream straight in:
|
|
109
|
+
* this accepts an Observable of credit IDs as well as a plain one, switching
|
|
110
|
+
* to the new credit as the source emits. While the ID is undefined it emits
|
|
111
|
+
* the client's loading state and a balance of 0.
|
|
112
|
+
*/
|
|
113
|
+
creditBalance$(creditId) {
|
|
114
|
+
if (isObservable(creditId)) {
|
|
115
|
+
return creditId.pipe(distinctUntilChanged(), switchMap((id) => this.creditBalanceFor(id)), distinctUntilChanged(shallowEqual), shareReplay({ bufferSize: 1, refCount: true }));
|
|
116
|
+
}
|
|
117
|
+
return this.creditBalanceFor(creditId);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Emits a zeroed balance that still tracks the client's loading state, for
|
|
121
|
+
* when there is no credit ID to read (a check that has not arrived yet, or a
|
|
122
|
+
* feature that is not credit-based).
|
|
123
|
+
*/
|
|
124
|
+
noCreditBalance$() {
|
|
125
|
+
return this.isPending$().pipe(map((isLoading) => ({ balance: 0, isLoading })));
|
|
126
|
+
}
|
|
127
|
+
creditBalanceFor(creditId) {
|
|
128
|
+
if (creditId === undefined)
|
|
129
|
+
return this.noCreditBalance$();
|
|
130
|
+
let cached = this.creditBalanceCache.get(creditId);
|
|
131
|
+
if (cached)
|
|
132
|
+
return cached;
|
|
133
|
+
cached = new Observable((subscriber) => {
|
|
134
|
+
const emit = () => {
|
|
135
|
+
const balance = this.client.getCreditBalance(creditId);
|
|
136
|
+
subscriber.next({
|
|
137
|
+
balance: balance?.settled ?? 0,
|
|
138
|
+
isLoading: balance === undefined && this.client.getIsPending(),
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
emit();
|
|
142
|
+
const unsubscribeBalance = this.client.addCreditBalanceListener(() => emit());
|
|
143
|
+
const unsubscribePending = this.client.addIsPendingListener(() => emit());
|
|
144
|
+
return () => {
|
|
145
|
+
unsubscribeBalance();
|
|
146
|
+
unsubscribePending();
|
|
147
|
+
};
|
|
148
|
+
}).pipe(distinctUntilChanged(shallowEqual), shareReplay({ bufferSize: 1, refCount: true }), finalize(() => this.creditBalanceCache.delete(creditId)));
|
|
149
|
+
this.creditBalanceCache.set(creditId, cached);
|
|
150
|
+
return cached;
|
|
151
|
+
}
|
|
98
152
|
isPending$() {
|
|
99
153
|
if (this.isPendingCache)
|
|
100
154
|
return this.isPendingCache;
|
|
@@ -109,14 +163,14 @@ class SchematicService {
|
|
|
109
163
|
}));
|
|
110
164
|
return this.isPendingCache;
|
|
111
165
|
}
|
|
112
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
113
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
166
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SchematicService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
167
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SchematicService });
|
|
114
168
|
}
|
|
115
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
169
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: SchematicService, decorators: [{
|
|
116
170
|
type: Injectable
|
|
117
171
|
}] });
|
|
118
172
|
|
|
119
|
-
const version = "1.
|
|
173
|
+
const version = "1.6.0";
|
|
120
174
|
|
|
121
175
|
function provideSchematic(config) {
|
|
122
176
|
const { client: providedClient, publishableKey, additionalHeaders, ...restOpts } = config;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schematichq-schematic-angular.mjs","sources":["../../src/token.ts","../../src/schematic.service.ts","../../src/version.ts","../../src/provide.ts","../../src/schematichq-schematic-angular.ts"],"sourcesContent":["import { InjectionToken } from \"@angular/core\";\nimport * as SchematicJS from \"@schematichq/schematic-js\";\n\nexport const SCHEMATIC_CLIENT = new InjectionToken<SchematicJS.Schematic>(\n \"SchematicClient\",\n);\n","import { Injectable, inject } from \"@angular/core\";\nimport * as SchematicJS from \"@schematichq/schematic-js\";\nimport { Observable, distinctUntilChanged, finalize, shareReplay } from \"rxjs\";\nimport { SCHEMATIC_CLIENT } from \"./token\";\n\nfunction shallowEqual<T extends Record<string, unknown>>(\n a: T | undefined,\n b: T | undefined,\n): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n return keysA.every((key) => {\n const valA = a[key];\n const valB = b[key];\n if (valA instanceof Date && valB instanceof Date) {\n return valA.getTime() === valB.getTime();\n }\n return valA === valB;\n });\n}\n\n@Injectable()\nexport class SchematicService {\n private client = inject(SCHEMATIC_CLIENT);\n\n private flagValueCache = new Map<string, Observable<boolean>>();\n private entitlementCache = new Map<\n string,\n Observable<SchematicJS.CheckFlagReturn>\n >();\n private planCache?: Observable<SchematicJS.CheckPlanReturn | undefined>;\n private isPendingCache?: Observable<boolean>;\n\n getClient(): SchematicJS.Schematic {\n return this.client;\n }\n\n setContext(context: SchematicJS.SchematicContext): void {\n this.client.setContext(context);\n }\n\n identify(body: SchematicJS.EventBodyIdentify): void {\n this.client.identify(body);\n }\n\n track(body: SchematicJS.EventBodyTrack): void {\n this.client.track(body);\n }\n\n flagValue$(key: string, fallback: boolean = false): Observable<boolean> {\n const cacheKey = `${key}:${fallback}`;\n let cached = this.flagValueCache.get(cacheKey);\n if (cached) return cached;\n\n cached = new Observable<boolean>((subscriber) => {\n const current = this.client.getFlagValue(key);\n subscriber.next(current ?? fallback);\n\n const unsubscribe = this.client.addFlagValueListener(key, () => {\n const value = this.client.getFlagValue(key);\n subscriber.next(value ?? fallback);\n });\n\n return () => unsubscribe();\n }).pipe(\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true }),\n finalize(() => this.flagValueCache.delete(cacheKey)),\n );\n\n this.flagValueCache.set(cacheKey, cached);\n return cached;\n }\n\n entitlement$(\n key: string,\n fallback: boolean = false,\n ): Observable<SchematicJS.CheckFlagReturn> {\n const cacheKey = `${key}:${fallback}`;\n let cached = this.entitlementCache.get(cacheKey);\n if (cached) return cached;\n\n const fallbackCheck: SchematicJS.CheckFlagReturn = {\n flag: key,\n reason: \"Fallback\",\n value: fallback,\n };\n\n cached = new Observable<SchematicJS.CheckFlagReturn>((subscriber) => {\n const current = this.client.getFlagCheck(key);\n subscriber.next(current ?? fallbackCheck);\n\n const unsubscribe = this.client.addFlagCheckListener(key, () => {\n const check = this.client.getFlagCheck(key);\n subscriber.next(check ?? fallbackCheck);\n });\n\n return () => unsubscribe();\n }).pipe(\n distinctUntilChanged(shallowEqual),\n shareReplay({ bufferSize: 1, refCount: true }),\n finalize(() => this.entitlementCache.delete(cacheKey)),\n );\n\n this.entitlementCache.set(cacheKey, cached);\n return cached;\n }\n\n plan$(): Observable<SchematicJS.CheckPlanReturn | undefined> {\n if (this.planCache) return this.planCache;\n\n this.planCache = new Observable<SchematicJS.CheckPlanReturn | undefined>(\n (subscriber) => {\n subscriber.next(this.client.getPlan());\n\n const unsubscribe = this.client.addPlanListener(() => {\n subscriber.next(this.client.getPlan());\n });\n\n return () => unsubscribe();\n },\n ).pipe(\n distinctUntilChanged(shallowEqual),\n shareReplay({ bufferSize: 1, refCount: true }),\n finalize(() => {\n this.planCache = undefined;\n }),\n );\n\n return this.planCache;\n }\n\n isPending$(): Observable<boolean> {\n if (this.isPendingCache) return this.isPendingCache;\n\n this.isPendingCache = new Observable<boolean>((subscriber) => {\n subscriber.next(this.client.getIsPending());\n\n const unsubscribe = this.client.addIsPendingListener(() => {\n subscriber.next(this.client.getIsPending());\n });\n\n return () => unsubscribe();\n }).pipe(\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true }),\n finalize(() => {\n this.isPendingCache = undefined;\n }),\n );\n\n return this.isPendingCache;\n }\n}\n","export const version = \"1.4.0\";\n","import { DestroyRef, inject, makeEnvironmentProviders } from \"@angular/core\";\nimport * as SchematicJS from \"@schematichq/schematic-js\";\n\nimport { SchematicService } from \"./schematic.service\";\nimport { SCHEMATIC_CLIENT } from \"./token\";\nimport { version } from \"./version\";\n\ntype BaseSchematicConfig = Omit<SchematicJS.SchematicOptions, \"useWebSocket\">;\n\ntype SchematicConfigWithClient = BaseSchematicConfig & {\n client: SchematicJS.Schematic;\n publishableKey?: never;\n};\n\ntype SchematicConfigWithKey = BaseSchematicConfig & {\n client?: never;\n publishableKey: string;\n};\n\nexport type SchematicConfig =\n | SchematicConfigWithClient\n | SchematicConfigWithKey;\n\nexport function provideSchematic(config: SchematicConfig) {\n const {\n client: providedClient,\n publishableKey,\n additionalHeaders,\n ...restOpts\n } = config;\n\n return makeEnvironmentProviders([\n {\n provide: SCHEMATIC_CLIENT,\n useFactory: () => {\n const isProvidedClient = !!providedClient;\n\n const client = isProvidedClient\n ? providedClient\n : new SchematicJS.Schematic(publishableKey!, {\n ...restOpts,\n useWebSocket: true,\n additionalHeaders: {\n \"X-Schematic-Client-Version\": `schematic-angular@${version}`,\n ...additionalHeaders,\n },\n });\n\n const destroyRef = inject(DestroyRef);\n destroyRef.onDestroy(() => {\n if (!isProvidedClient) {\n client.cleanup().catch((error: unknown) => {\n console.error(\"Error during Schematic cleanup:\", error);\n });\n }\n });\n\n return client;\n },\n },\n SchematicService,\n ]);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schematichq-schematic-angular.mjs","sources":["../../src/token.ts","../../src/schematic.service.ts","../../src/version.ts","../../src/provide.ts","../../src/schematichq-schematic-angular.ts"],"sourcesContent":["import { InjectionToken } from \"@angular/core\";\nimport * as SchematicJS from \"@schematichq/schematic-js\";\n\nexport const SCHEMATIC_CLIENT = new InjectionToken<SchematicJS.Schematic>(\n \"SchematicClient\",\n);\n","import { Injectable, inject } from \"@angular/core\";\nimport * as SchematicJS from \"@schematichq/schematic-js\";\nimport {\n Observable,\n distinctUntilChanged,\n finalize,\n isObservable,\n map,\n shareReplay,\n switchMap,\n} from \"rxjs\";\nimport { SCHEMATIC_CLIENT } from \"./token\";\n\n/** A company's credit balance for a single credit type, plus a loading flag */\nexport type SchematicCreditBalance = {\n /** The spendable balance; 0 while loading or when the company holds no balance in this credit */\n balance: number;\n /** True while the balance is still loading and no value has arrived yet */\n isLoading: boolean;\n};\n\nfunction shallowEqual<T extends Record<string, unknown>>(\n a: T | undefined,\n b: T | undefined,\n): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n return keysA.every((key) => {\n const valA = a[key];\n const valB = b[key];\n if (valA instanceof Date && valB instanceof Date) {\n return valA.getTime() === valB.getTime();\n }\n return valA === valB;\n });\n}\n\n@Injectable()\nexport class SchematicService {\n private client = inject(SCHEMATIC_CLIENT);\n\n private flagValueCache = new Map<string, Observable<boolean>>();\n private entitlementCache = new Map<\n string,\n Observable<SchematicJS.CheckFlagReturn>\n >();\n private creditBalanceCache = new Map<\n string,\n Observable<SchematicCreditBalance>\n >();\n private planCache?: Observable<SchematicJS.CheckPlanReturn | undefined>;\n private isPendingCache?: Observable<boolean>;\n\n getClient(): SchematicJS.Schematic {\n return this.client;\n }\n\n setContext(context: SchematicJS.SchematicContext): void {\n this.client.setContext(context);\n }\n\n identify(body: SchematicJS.EventBodyIdentify): void {\n this.client.identify(body);\n }\n\n track(body: SchematicJS.EventBodyTrack): void {\n this.client.track(body);\n }\n\n flagValue$(key: string, fallback: boolean = false): Observable<boolean> {\n const cacheKey = `${key}:${fallback}`;\n let cached = this.flagValueCache.get(cacheKey);\n if (cached) return cached;\n\n cached = new Observable<boolean>((subscriber) => {\n const current = this.client.getFlagValue(key);\n subscriber.next(current ?? fallback);\n\n const unsubscribe = this.client.addFlagValueListener(key, () => {\n const value = this.client.getFlagValue(key);\n subscriber.next(value ?? fallback);\n });\n\n return () => unsubscribe();\n }).pipe(\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true }),\n finalize(() => this.flagValueCache.delete(cacheKey)),\n );\n\n this.flagValueCache.set(cacheKey, cached);\n return cached;\n }\n\n entitlement$(\n key: string,\n fallback: boolean = false,\n ): Observable<SchematicJS.CheckFlagReturn> {\n const cacheKey = `${key}:${fallback}`;\n let cached = this.entitlementCache.get(cacheKey);\n if (cached) return cached;\n\n const fallbackCheck: SchematicJS.CheckFlagReturn = {\n flag: key,\n reason: \"Fallback\",\n value: fallback,\n };\n\n cached = new Observable<SchematicJS.CheckFlagReturn>((subscriber) => {\n const current = this.client.getFlagCheck(key);\n subscriber.next(current ?? fallbackCheck);\n\n const unsubscribe = this.client.addFlagCheckListener(key, () => {\n const check = this.client.getFlagCheck(key);\n subscriber.next(check ?? fallbackCheck);\n });\n\n return () => unsubscribe();\n }).pipe(\n distinctUntilChanged(shallowEqual),\n shareReplay({ bufferSize: 1, refCount: true }),\n finalize(() => this.entitlementCache.delete(cacheKey)),\n );\n\n this.entitlementCache.set(cacheKey, cached);\n return cached;\n }\n\n plan$(): Observable<SchematicJS.CheckPlanReturn | undefined> {\n if (this.planCache) return this.planCache;\n\n this.planCache = new Observable<SchematicJS.CheckPlanReturn | undefined>(\n (subscriber) => {\n subscriber.next(this.client.getPlan());\n\n const unsubscribe = this.client.addPlanListener(() => {\n subscriber.next(this.client.getPlan());\n });\n\n return () => unsubscribe();\n },\n ).pipe(\n distinctUntilChanged(shallowEqual),\n shareReplay({ bufferSize: 1, refCount: true }),\n finalize(() => {\n this.planCache = undefined;\n }),\n );\n\n return this.planCache;\n }\n\n /**\n * Observe a company's live, lease-aware credit balance for a single credit type.\n *\n * Surfaces the spendable `settled` balance, sourced from the streamed credit\n * balances map (keyed by credit ID). It emits as partials arrive over the\n * DataStream, so it stays accurate during an open lease — when the raw\n * `remaining` would otherwise read stale / falsely \"exhausted\".\n *\n * The credit ID is available on a feature's entitlement: `entitlement$(key)`\n * emits `creditId` for credit-based features. Pass that stream straight in:\n * this accepts an Observable of credit IDs as well as a plain one, switching\n * to the new credit as the source emits. While the ID is undefined it emits\n * the client's loading state and a balance of 0.\n */\n creditBalance$(\n creditId: string | undefined | Observable<string | undefined>,\n ): Observable<SchematicCreditBalance> {\n if (isObservable(creditId)) {\n return creditId.pipe(\n distinctUntilChanged(),\n switchMap((id) => this.creditBalanceFor(id)),\n distinctUntilChanged(shallowEqual),\n shareReplay({ bufferSize: 1, refCount: true }),\n );\n }\n\n return this.creditBalanceFor(creditId);\n }\n\n /**\n * Emits a zeroed balance that still tracks the client's loading state, for\n * when there is no credit ID to read (a check that has not arrived yet, or a\n * feature that is not credit-based).\n */\n private noCreditBalance$(): Observable<SchematicCreditBalance> {\n return this.isPending$().pipe(\n map((isLoading) => ({ balance: 0, isLoading })),\n );\n }\n\n private creditBalanceFor(\n creditId: string | undefined,\n ): Observable<SchematicCreditBalance> {\n if (creditId === undefined) return this.noCreditBalance$();\n\n let cached = this.creditBalanceCache.get(creditId);\n if (cached) return cached;\n\n cached = new Observable<SchematicCreditBalance>((subscriber) => {\n const emit = () => {\n const balance = this.client.getCreditBalance(creditId);\n subscriber.next({\n balance: balance?.settled ?? 0,\n isLoading: balance === undefined && this.client.getIsPending(),\n });\n };\n\n emit();\n\n const unsubscribeBalance = this.client.addCreditBalanceListener(() =>\n emit(),\n );\n const unsubscribePending = this.client.addIsPendingListener(() => emit());\n\n return () => {\n unsubscribeBalance();\n unsubscribePending();\n };\n }).pipe(\n distinctUntilChanged(shallowEqual),\n shareReplay({ bufferSize: 1, refCount: true }),\n finalize(() => this.creditBalanceCache.delete(creditId)),\n );\n\n this.creditBalanceCache.set(creditId, cached);\n return cached;\n }\n\n isPending$(): Observable<boolean> {\n if (this.isPendingCache) return this.isPendingCache;\n\n this.isPendingCache = new Observable<boolean>((subscriber) => {\n subscriber.next(this.client.getIsPending());\n\n const unsubscribe = this.client.addIsPendingListener(() => {\n subscriber.next(this.client.getIsPending());\n });\n\n return () => unsubscribe();\n }).pipe(\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true }),\n finalize(() => {\n this.isPendingCache = undefined;\n }),\n );\n\n return this.isPendingCache;\n }\n}\n","export const version = \"1.6.0\";\n","import { DestroyRef, inject, makeEnvironmentProviders } from \"@angular/core\";\nimport * as SchematicJS from \"@schematichq/schematic-js\";\n\nimport { SchematicService } from \"./schematic.service\";\nimport { SCHEMATIC_CLIENT } from \"./token\";\nimport { version } from \"./version\";\n\ntype BaseSchematicConfig = Omit<SchematicJS.SchematicOptions, \"useWebSocket\">;\n\ntype SchematicConfigWithClient = BaseSchematicConfig & {\n client: SchematicJS.Schematic;\n publishableKey?: never;\n};\n\ntype SchematicConfigWithKey = BaseSchematicConfig & {\n client?: never;\n publishableKey: string;\n};\n\nexport type SchematicConfig =\n SchematicConfigWithClient | SchematicConfigWithKey;\n\nexport function provideSchematic(config: SchematicConfig) {\n const {\n client: providedClient,\n publishableKey,\n additionalHeaders,\n ...restOpts\n } = config;\n\n return makeEnvironmentProviders([\n {\n provide: SCHEMATIC_CLIENT,\n useFactory: () => {\n const isProvidedClient = !!providedClient;\n\n const client = isProvidedClient\n ? providedClient\n : new SchematicJS.Schematic(publishableKey!, {\n ...restOpts,\n useWebSocket: true,\n additionalHeaders: {\n \"X-Schematic-Client-Version\": `schematic-angular@${version}`,\n ...additionalHeaders,\n },\n });\n\n const destroyRef = inject(DestroyRef);\n destroyRef.onDestroy(() => {\n if (!isProvidedClient) {\n client.cleanup().catch((error: unknown) => {\n console.error(\"Error during Schematic cleanup:\", error);\n });\n }\n });\n\n return client;\n },\n },\n SchematicService,\n ]);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schematichq/schematic-angular",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"author": "Schematic <engineering@schematichq.com>",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+ssh://git@github.com/SchematicHQ/schematic-js.git"
|
|
9
9
|
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@schematichq/schematic-js": "^1.8.0",
|
|
12
|
+
"tslib": "^2.3.0"
|
|
13
|
+
},
|
|
10
14
|
"peerDependencies": {
|
|
11
15
|
"@angular/core": ">=19.0.0",
|
|
12
16
|
"rxjs": ">=7.0.0"
|
|
13
17
|
},
|
|
14
|
-
"
|
|
15
|
-
"minimatch": ">=3.1.3"
|
|
16
|
-
},
|
|
17
|
-
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
|
|
18
|
+
"packageManager": "pnpm@11.9.0+sha512.bd682d5d03fe525ef7c9fd6780c6884d1e756ac4c9c9fe00c538782824310dcf90e3ddc4f53835f06dfaebd5085e41855e0bcbb3b60de2ac5bbab89e5036f03b",
|
|
18
19
|
"module": "fesm2022/schematichq-schematic-angular.mjs",
|
|
19
20
|
"typings": "types/schematichq-schematic-angular.d.ts",
|
|
20
21
|
"exports": {
|
|
@@ -27,8 +28,5 @@
|
|
|
27
28
|
}
|
|
28
29
|
},
|
|
29
30
|
"sideEffects": false,
|
|
30
|
-
"type": "module"
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"tslib": "^2.3.0"
|
|
33
|
-
}
|
|
31
|
+
"type": "module"
|
|
34
32
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken } from '@angular/core';
|
|
3
3
|
import * as SchematicJS from '@schematichq/schematic-js';
|
|
4
|
-
export { CheckFlagReturn, CheckPlanReturn, Event, EventBody, EventBodyIdentify, EventBodyTrack, EventType, Keys, RuleType, Schematic, SchematicContext, SchematicOptions, StoragePersister, Traits, TrialStatus, UsagePeriod } from '@schematichq/schematic-js';
|
|
4
|
+
export { CheckFlagReturn, CheckPlanReturn, CompanyCreditBalance, CreditBalance, CreditBalances, Event, EventBody, EventBodyIdentify, EventBodyTrack, EventType, Keys, RuleType, Schematic, SchematicContext, SchematicOptions, StoragePersister, Traits, TrialStatus, UsagePeriod, WarningTier } from '@schematichq/schematic-js';
|
|
5
5
|
import { Observable } from 'rxjs';
|
|
6
6
|
|
|
7
7
|
type BaseSchematicConfig = Omit<SchematicJS.SchematicOptions, "useWebSocket">;
|
|
@@ -18,10 +18,18 @@ declare function provideSchematic(config: SchematicConfig): i0.EnvironmentProvid
|
|
|
18
18
|
|
|
19
19
|
declare const SCHEMATIC_CLIENT: InjectionToken<SchematicJS.Schematic>;
|
|
20
20
|
|
|
21
|
+
/** A company's credit balance for a single credit type, plus a loading flag */
|
|
22
|
+
type SchematicCreditBalance = {
|
|
23
|
+
/** The spendable balance; 0 while loading or when the company holds no balance in this credit */
|
|
24
|
+
balance: number;
|
|
25
|
+
/** True while the balance is still loading and no value has arrived yet */
|
|
26
|
+
isLoading: boolean;
|
|
27
|
+
};
|
|
21
28
|
declare class SchematicService {
|
|
22
29
|
private client;
|
|
23
30
|
private flagValueCache;
|
|
24
31
|
private entitlementCache;
|
|
32
|
+
private creditBalanceCache;
|
|
25
33
|
private planCache?;
|
|
26
34
|
private isPendingCache?;
|
|
27
35
|
getClient(): SchematicJS.Schematic;
|
|
@@ -31,10 +39,32 @@ declare class SchematicService {
|
|
|
31
39
|
flagValue$(key: string, fallback?: boolean): Observable<boolean>;
|
|
32
40
|
entitlement$(key: string, fallback?: boolean): Observable<SchematicJS.CheckFlagReturn>;
|
|
33
41
|
plan$(): Observable<SchematicJS.CheckPlanReturn | undefined>;
|
|
42
|
+
/**
|
|
43
|
+
* Observe a company's live, lease-aware credit balance for a single credit type.
|
|
44
|
+
*
|
|
45
|
+
* Surfaces the spendable `settled` balance, sourced from the streamed credit
|
|
46
|
+
* balances map (keyed by credit ID). It emits as partials arrive over the
|
|
47
|
+
* DataStream, so it stays accurate during an open lease — when the raw
|
|
48
|
+
* `remaining` would otherwise read stale / falsely "exhausted".
|
|
49
|
+
*
|
|
50
|
+
* The credit ID is available on a feature's entitlement: `entitlement$(key)`
|
|
51
|
+
* emits `creditId` for credit-based features. Pass that stream straight in:
|
|
52
|
+
* this accepts an Observable of credit IDs as well as a plain one, switching
|
|
53
|
+
* to the new credit as the source emits. While the ID is undefined it emits
|
|
54
|
+
* the client's loading state and a balance of 0.
|
|
55
|
+
*/
|
|
56
|
+
creditBalance$(creditId: string | undefined | Observable<string | undefined>): Observable<SchematicCreditBalance>;
|
|
57
|
+
/**
|
|
58
|
+
* Emits a zeroed balance that still tracks the client's loading state, for
|
|
59
|
+
* when there is no credit ID to read (a check that has not arrived yet, or a
|
|
60
|
+
* feature that is not credit-based).
|
|
61
|
+
*/
|
|
62
|
+
private noCreditBalance$;
|
|
63
|
+
private creditBalanceFor;
|
|
34
64
|
isPending$(): Observable<boolean>;
|
|
35
65
|
static ɵfac: i0.ɵɵFactoryDeclaration<SchematicService, never>;
|
|
36
|
-
static ɵprov: i0.ɵɵInjectableDeclaration<
|
|
66
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<any>;
|
|
37
67
|
}
|
|
38
68
|
|
|
39
69
|
export { SCHEMATIC_CLIENT, SchematicService, provideSchematic };
|
|
40
|
-
export type { SchematicConfig };
|
|
70
|
+
export type { SchematicConfig, SchematicCreditBalance };
|