@schematichq/schematic-angular 1.4.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 ADDED
@@ -0,0 +1,334 @@
1
+ # schematic-angular
2
+
3
+ `schematic-angular` is a client-side Angular library for [Schematic](https://schematichq.com) which provides an injectable service to track events, check flags, and more. `schematic-angular` provides the same capabilities as [schematic-js](https://github.com/schematichq/schematic-js/tree/main/js), for Angular apps.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @schematichq/schematic-angular
9
+ # or
10
+ yarn add @schematichq/schematic-angular
11
+ # or
12
+ pnpm add @schematichq/schematic-angular
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### Setup with `provideSchematic`
18
+
19
+ Add `provideSchematic` to your application's providers. This works with both standalone and NgModule-based apps.
20
+
21
+ **Standalone app (app.config.ts):**
22
+
23
+ ```typescript
24
+ import { ApplicationConfig } from "@angular/core";
25
+ import { provideSchematic } from "@schematichq/schematic-angular";
26
+
27
+ export const appConfig: ApplicationConfig = {
28
+ providers: [
29
+ provideSchematic({ publishableKey: "your-publishable-key" }),
30
+ ],
31
+ };
32
+ ```
33
+
34
+ **NgModule-based app:**
35
+
36
+ ```typescript
37
+ import { NgModule } from "@angular/core";
38
+ import { provideSchematic } from "@schematichq/schematic-angular";
39
+
40
+ @NgModule({
41
+ providers: [
42
+ provideSchematic({ publishableKey: "your-publishable-key" }),
43
+ ],
44
+ })
45
+ export class AppModule {}
46
+ ```
47
+
48
+ You can also pass a pre-configured client:
49
+
50
+ ```typescript
51
+ import { Schematic } from "@schematichq/schematic-angular";
52
+
53
+ const client = new Schematic("your-publishable-key", { useWebSocket: true });
54
+
55
+ provideSchematic({ client });
56
+ ```
57
+
58
+ ### Setting context
59
+
60
+ To set the user context for events and flag checks, use the `identify` method on `SchematicService`:
61
+
62
+ ```typescript
63
+ import { Component, OnInit, inject } from "@angular/core";
64
+ import { SchematicService } from "@schematichq/schematic-angular";
65
+
66
+ @Component({ selector: "app-root", template: `<router-outlet />` })
67
+ export class AppComponent implements OnInit {
68
+ private schematic = inject(SchematicService);
69
+
70
+ ngOnInit() {
71
+ this.schematic.identify({
72
+ keys: { id: "my-user-id" },
73
+ company: {
74
+ keys: { id: "my-company-id" },
75
+ traits: { location: "Atlanta, GA" },
76
+ },
77
+ });
78
+ }
79
+ }
80
+ ```
81
+
82
+ To learn more about identifying companies with the `keys` map, see [key management in Schematic public docs](https://docs.schematichq.com/developer_resources/key_management).
83
+
84
+ ### Tracking usage
85
+
86
+ Once you've set the context with `identify`, you can track events:
87
+
88
+ ```typescript
89
+ import { Component, inject } from "@angular/core";
90
+ import { SchematicService } from "@schematichq/schematic-angular";
91
+
92
+ @Component({
93
+ selector: "app-usage",
94
+ template: `<button (click)="onQuery()">Run Query</button>`,
95
+ })
96
+ export class UsageComponent {
97
+ private schematic = inject(SchematicService);
98
+
99
+ onQuery() {
100
+ this.schematic.track({ event: "query" });
101
+ }
102
+ }
103
+ ```
104
+
105
+ If you want to record large numbers of the same event at once, or measure usage in terms of a unit like tokens or memory, you can optionally specify a quantity:
106
+
107
+ ```typescript
108
+ this.schematic.track({ event: "query", quantity: 10 });
109
+ ```
110
+
111
+ ### Checking flags
112
+
113
+ Use `flagValue$` to get an Observable of a flag's boolean value:
114
+
115
+ **With async pipe:**
116
+
117
+ ```typescript
118
+ import { Component, inject } from "@angular/core";
119
+ import { AsyncPipe } from "@angular/common";
120
+ import { SchematicService } from "@schematichq/schematic-angular";
121
+
122
+ @Component({
123
+ selector: "app-feature",
124
+ standalone: true,
125
+ imports: [AsyncPipe],
126
+ template: `
127
+ @if (isFeatureEnabled$ | async) {
128
+ <app-feature />
129
+ } @else {
130
+ <app-fallback />
131
+ }
132
+ `,
133
+ })
134
+ export class FeatureComponent {
135
+ private schematic = inject(SchematicService);
136
+ isFeatureEnabled$ = this.schematic.flagValue$("my-flag-key");
137
+ }
138
+ ```
139
+
140
+ **With Signals (Angular 16+):**
141
+
142
+ ```typescript
143
+ import { Component, inject } from "@angular/core";
144
+ import { toSignal } from "@angular/core/rxjs-interop";
145
+ import { SchematicService } from "@schematichq/schematic-angular";
146
+
147
+ @Component({
148
+ selector: "app-feature",
149
+ standalone: true,
150
+ template: `
151
+ @if (isFeatureEnabled()) {
152
+ <app-feature />
153
+ } @else {
154
+ <app-fallback />
155
+ }
156
+ `,
157
+ })
158
+ export class FeatureComponent {
159
+ private schematic = inject(SchematicService);
160
+ isFeatureEnabled = toSignal(this.schematic.flagValue$("my-flag-key"), {
161
+ initialValue: false,
162
+ });
163
+ }
164
+ ```
165
+
166
+ ### Checking entitlements
167
+
168
+ Use `entitlement$` to get an Observable with detailed entitlement data including usage information:
169
+
170
+ ```typescript
171
+ import { Component, inject } from "@angular/core";
172
+ import { AsyncPipe } from "@angular/common";
173
+ import { SchematicService } from "@schematichq/schematic-angular";
174
+
175
+ @Component({
176
+ selector: "app-entitlement",
177
+ standalone: true,
178
+ imports: [AsyncPipe],
179
+ template: `
180
+ @if (isPending$ | async) {
181
+ <app-loader />
182
+ } @else if (entitlement$ | async; as entitlement) {
183
+ @if (entitlement.featureUsageExceeded) {
184
+ <div>
185
+ You have used all of your usage
186
+ ({{ entitlement.featureUsage }} / {{ entitlement.featureAllocation }})
187
+ </div>
188
+ } @else if (entitlement.value) {
189
+ <app-feature />
190
+ } @else {
191
+ <app-no-access />
192
+ }
193
+ }
194
+ `,
195
+ })
196
+ export class EntitlementComponent {
197
+ private schematic = inject(SchematicService);
198
+ isPending$ = this.schematic.isPending$();
199
+ entitlement$ = this.schematic.entitlement$("my-flag-key");
200
+ }
201
+ ```
202
+
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
+
205
+ ### Checking plans
206
+
207
+ Use `plan$` to get an Observable of the current plan information:
208
+
209
+ ```typescript
210
+ import { Component, inject } from "@angular/core";
211
+ import { AsyncPipe } from "@angular/common";
212
+ import { SchematicService } from "@schematichq/schematic-angular";
213
+
214
+ @Component({
215
+ selector: "app-plan",
216
+ standalone: true,
217
+ imports: [AsyncPipe],
218
+ template: `
219
+ @if (plan$ | async; as plan) {
220
+ <div>Current plan: {{ plan.name }}</div>
221
+ } @else {
222
+ <div>No active subscription</div>
223
+ }
224
+ `,
225
+ })
226
+ export class PlanComponent {
227
+ private schematic = inject(SchematicService);
228
+ plan$ = this.schematic.plan$();
229
+ }
230
+ ```
231
+
232
+ ## API Reference
233
+
234
+ ### `provideSchematic(config)`
235
+
236
+ Configures the Schematic client for dependency injection. Accepts either a `publishableKey` string or a pre-configured `client` instance, plus any `SchematicOptions`.
237
+
238
+ ### `SchematicService`
239
+
240
+ Injectable service providing all Schematic functionality:
241
+
242
+ | Method | Return Type | Description |
243
+ |---|---|---|
244
+ | `getClient()` | `Schematic` | Access the underlying Schematic client |
245
+ | `setContext(ctx)` | `void` | Set the evaluation context (company/user) |
246
+ | `identify(body)` | `void` | Identify a user and/or company |
247
+ | `track(body)` | `void` | Track a usage event |
248
+ | `flagValue$(key, fallback?)` | `Observable<boolean>` | Observe a feature flag's boolean value |
249
+ | `entitlement$(key, fallback?)` | `Observable<CheckFlagReturn>` | Observe detailed entitlement data |
250
+ | `plan$()` | `Observable<CheckPlanReturn \| undefined>` | Observe plan information |
251
+ | `isPending$()` | `Observable<boolean>` | Observe loading state |
252
+
253
+ ### `SCHEMATIC_CLIENT`
254
+
255
+ `InjectionToken<Schematic>` for direct access to the raw client instance via Angular DI.
256
+
257
+ ## Fallback Behavior
258
+
259
+ The SDK includes built-in fallback behavior to ensure your application continues to function even when unable to reach Schematic.
260
+
261
+ ### Flag Check Fallbacks
262
+
263
+ When flag checks cannot reach Schematic, they use fallback values in the following priority order:
264
+
265
+ 1. **Callsite fallback**: provided as the second argument to `flagValue$` or `entitlement$`
266
+ 2. **Initialization defaults**: configured via `flagCheckDefaults` or `flagValueDefaults` options in `provideSchematic`
267
+ 3. **Default value**: returns `false` if no fallback is configured
268
+
269
+ ```typescript
270
+ // Provide a fallback value at the callsite
271
+ isFeatureEnabled$ = this.schematic.flagValue$("feature-flag", true);
272
+
273
+ // Or configure defaults at initialization
274
+ provideSchematic({
275
+ publishableKey: "your-publishable-key",
276
+ flagValueDefaults: {
277
+ "feature-flag": true,
278
+ },
279
+ });
280
+ ```
281
+
282
+ ### Event Queueing and Retry
283
+
284
+ When events (track, identify) cannot be sent due to network issues, they are automatically queued and retried:
285
+
286
+ - Events are queued in memory (up to 100 events by default, configurable via `maxEventQueueSize`)
287
+ - Failed events are retried with exponential backoff (up to 5 attempts by default, configurable via `maxEventRetries`)
288
+ - Events are automatically flushed when the network connection is restored
289
+
290
+ ### WebSocket Fallback
291
+
292
+ In WebSocket mode, if the WebSocket connection fails, the SDK will provide the last known value or the configured fallback values as outlined above. The WebSocket will also automatically attempt to re-establish its connection using an exponential backoff.
293
+
294
+ ## Troubleshooting
295
+
296
+ For debugging and development, Schematic supports two special modes:
297
+
298
+ ### Debug Mode
299
+
300
+ Enables console logging of all Schematic operations:
301
+
302
+ ```typescript
303
+ provideSchematic({
304
+ publishableKey: "your-publishable-key",
305
+ debug: true,
306
+ });
307
+
308
+ // Or via URL parameter
309
+ // https://yoursite.com/?schematic_debug=true
310
+ ```
311
+
312
+ ### Offline Mode
313
+
314
+ Prevents network requests and returns fallback values for all flag checks:
315
+
316
+ ```typescript
317
+ provideSchematic({
318
+ publishableKey: "your-publishable-key",
319
+ offline: true,
320
+ });
321
+
322
+ // Or via URL parameter
323
+ // https://yoursite.com/?schematic_offline=true
324
+ ```
325
+
326
+ Offline mode automatically enables debug mode to help with troubleshooting.
327
+
328
+ ## License
329
+
330
+ MIT
331
+
332
+ ## Support
333
+
334
+ Need help? Please open a GitHub issue or reach out to [support@schematichq.com](mailto:support@schematichq.com) and we'll be happy to assist.
@@ -0,0 +1,158 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, Injectable, makeEnvironmentProviders, DestroyRef } from '@angular/core';
3
+ import * as SchematicJS from '@schematichq/schematic-js';
4
+ export { RuleType, Schematic, TrialStatus, UsagePeriod } from '@schematichq/schematic-js';
5
+ import { Observable, distinctUntilChanged, shareReplay, finalize } from 'rxjs';
6
+
7
+ const SCHEMATIC_CLIENT = new InjectionToken("SchematicClient");
8
+
9
+ function shallowEqual(a, b) {
10
+ if (a === b)
11
+ return true;
12
+ if (!a || !b)
13
+ return false;
14
+ const keysA = Object.keys(a);
15
+ const keysB = Object.keys(b);
16
+ if (keysA.length !== keysB.length)
17
+ return false;
18
+ return keysA.every((key) => {
19
+ const valA = a[key];
20
+ const valB = b[key];
21
+ if (valA instanceof Date && valB instanceof Date) {
22
+ return valA.getTime() === valB.getTime();
23
+ }
24
+ return valA === valB;
25
+ });
26
+ }
27
+ class SchematicService {
28
+ client = inject(SCHEMATIC_CLIENT);
29
+ flagValueCache = new Map();
30
+ entitlementCache = new Map();
31
+ planCache;
32
+ isPendingCache;
33
+ getClient() {
34
+ return this.client;
35
+ }
36
+ setContext(context) {
37
+ this.client.setContext(context);
38
+ }
39
+ identify(body) {
40
+ this.client.identify(body);
41
+ }
42
+ track(body) {
43
+ this.client.track(body);
44
+ }
45
+ flagValue$(key, fallback = false) {
46
+ const cacheKey = `${key}:${fallback}`;
47
+ let cached = this.flagValueCache.get(cacheKey);
48
+ if (cached)
49
+ return cached;
50
+ cached = new Observable((subscriber) => {
51
+ const current = this.client.getFlagValue(key);
52
+ subscriber.next(current ?? fallback);
53
+ const unsubscribe = this.client.addFlagValueListener(key, () => {
54
+ const value = this.client.getFlagValue(key);
55
+ subscriber.next(value ?? fallback);
56
+ });
57
+ return () => unsubscribe();
58
+ }).pipe(distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: true }), finalize(() => this.flagValueCache.delete(cacheKey)));
59
+ this.flagValueCache.set(cacheKey, cached);
60
+ return cached;
61
+ }
62
+ entitlement$(key, fallback = false) {
63
+ const cacheKey = `${key}:${fallback}`;
64
+ let cached = this.entitlementCache.get(cacheKey);
65
+ if (cached)
66
+ return cached;
67
+ const fallbackCheck = {
68
+ flag: key,
69
+ reason: "Fallback",
70
+ value: fallback,
71
+ };
72
+ cached = new Observable((subscriber) => {
73
+ const current = this.client.getFlagCheck(key);
74
+ subscriber.next(current ?? fallbackCheck);
75
+ const unsubscribe = this.client.addFlagCheckListener(key, () => {
76
+ const check = this.client.getFlagCheck(key);
77
+ subscriber.next(check ?? fallbackCheck);
78
+ });
79
+ return () => unsubscribe();
80
+ }).pipe(distinctUntilChanged(shallowEqual), shareReplay({ bufferSize: 1, refCount: true }), finalize(() => this.entitlementCache.delete(cacheKey)));
81
+ this.entitlementCache.set(cacheKey, cached);
82
+ return cached;
83
+ }
84
+ plan$() {
85
+ if (this.planCache)
86
+ return this.planCache;
87
+ this.planCache = new Observable((subscriber) => {
88
+ subscriber.next(this.client.getPlan());
89
+ const unsubscribe = this.client.addPlanListener(() => {
90
+ subscriber.next(this.client.getPlan());
91
+ });
92
+ return () => unsubscribe();
93
+ }).pipe(distinctUntilChanged(shallowEqual), shareReplay({ bufferSize: 1, refCount: true }), finalize(() => {
94
+ this.planCache = undefined;
95
+ }));
96
+ return this.planCache;
97
+ }
98
+ isPending$() {
99
+ if (this.isPendingCache)
100
+ return this.isPendingCache;
101
+ this.isPendingCache = new Observable((subscriber) => {
102
+ subscriber.next(this.client.getIsPending());
103
+ const unsubscribe = this.client.addIsPendingListener(() => {
104
+ subscriber.next(this.client.getIsPending());
105
+ });
106
+ return () => unsubscribe();
107
+ }).pipe(distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: true }), finalize(() => {
108
+ this.isPendingCache = undefined;
109
+ }));
110
+ return this.isPendingCache;
111
+ }
112
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: SchematicService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
113
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: SchematicService });
114
+ }
115
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: SchematicService, decorators: [{
116
+ type: Injectable
117
+ }] });
118
+
119
+ const version = "1.4.0";
120
+
121
+ function provideSchematic(config) {
122
+ const { client: providedClient, publishableKey, additionalHeaders, ...restOpts } = config;
123
+ return makeEnvironmentProviders([
124
+ {
125
+ provide: SCHEMATIC_CLIENT,
126
+ useFactory: () => {
127
+ const isProvidedClient = !!providedClient;
128
+ const client = isProvidedClient
129
+ ? providedClient
130
+ : new SchematicJS.Schematic(publishableKey, {
131
+ ...restOpts,
132
+ useWebSocket: true,
133
+ additionalHeaders: {
134
+ "X-Schematic-Client-Version": `schematic-angular@${version}`,
135
+ ...additionalHeaders,
136
+ },
137
+ });
138
+ const destroyRef = inject(DestroyRef);
139
+ destroyRef.onDestroy(() => {
140
+ if (!isProvidedClient) {
141
+ client.cleanup().catch((error) => {
142
+ console.error("Error during Schematic cleanup:", error);
143
+ });
144
+ }
145
+ });
146
+ return client;
147
+ },
148
+ },
149
+ SchematicService,
150
+ ]);
151
+ }
152
+
153
+ /**
154
+ * Generated bundle index. Do not edit.
155
+ */
156
+
157
+ export { SCHEMATIC_CLIENT, SchematicService, provideSchematic };
158
+ //# sourceMappingURL=schematichq-schematic-angular.mjs.map
@@ -0,0 +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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"}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@schematichq/schematic-angular",
3
+ "version": "1.4.0",
4
+ "author": "Schematic <engineering@schematichq.com>",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+ssh://git@github.com/SchematicHQ/schematic-js.git"
9
+ },
10
+ "peerDependencies": {
11
+ "@angular/core": ">=19.0.0",
12
+ "rxjs": ">=7.0.0"
13
+ },
14
+ "resolutions": {
15
+ "minimatch": ">=3.1.3"
16
+ },
17
+ "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
18
+ "module": "fesm2022/schematichq-schematic-angular.mjs",
19
+ "typings": "types/schematichq-schematic-angular.d.ts",
20
+ "exports": {
21
+ "./package.json": {
22
+ "default": "./package.json"
23
+ },
24
+ ".": {
25
+ "types": "./types/schematichq-schematic-angular.d.ts",
26
+ "default": "./fesm2022/schematichq-schematic-angular.mjs"
27
+ }
28
+ },
29
+ "sideEffects": false,
30
+ "type": "module",
31
+ "dependencies": {
32
+ "tslib": "^2.3.0"
33
+ }
34
+ }
@@ -0,0 +1,40 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken } from '@angular/core';
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';
5
+ import { Observable } from 'rxjs';
6
+
7
+ type BaseSchematicConfig = Omit<SchematicJS.SchematicOptions, "useWebSocket">;
8
+ type SchematicConfigWithClient = BaseSchematicConfig & {
9
+ client: SchematicJS.Schematic;
10
+ publishableKey?: never;
11
+ };
12
+ type SchematicConfigWithKey = BaseSchematicConfig & {
13
+ client?: never;
14
+ publishableKey: string;
15
+ };
16
+ type SchematicConfig = SchematicConfigWithClient | SchematicConfigWithKey;
17
+ declare function provideSchematic(config: SchematicConfig): i0.EnvironmentProviders;
18
+
19
+ declare const SCHEMATIC_CLIENT: InjectionToken<SchematicJS.Schematic>;
20
+
21
+ declare class SchematicService {
22
+ private client;
23
+ private flagValueCache;
24
+ private entitlementCache;
25
+ private planCache?;
26
+ private isPendingCache?;
27
+ getClient(): SchematicJS.Schematic;
28
+ setContext(context: SchematicJS.SchematicContext): void;
29
+ identify(body: SchematicJS.EventBodyIdentify): void;
30
+ track(body: SchematicJS.EventBodyTrack): void;
31
+ flagValue$(key: string, fallback?: boolean): Observable<boolean>;
32
+ entitlement$(key: string, fallback?: boolean): Observable<SchematicJS.CheckFlagReturn>;
33
+ plan$(): Observable<SchematicJS.CheckPlanReturn | undefined>;
34
+ isPending$(): Observable<boolean>;
35
+ static ɵfac: i0.ɵɵFactoryDeclaration<SchematicService, never>;
36
+ static ɵprov: i0.ɵɵInjectableDeclaration<SchematicService>;
37
+ }
38
+
39
+ export { SCHEMATIC_CLIENT, SchematicService, provideSchematic };
40
+ export type { SchematicConfig };