{"version":3,"file":"schematichq-schematic-angular.mjs","names":[],"sources":["../../src/token.ts","../../src/schematic.service.ts","../../src/version.ts","../../src/provide.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\n/** The credit spend policies binding the current context, plus a loading flag */\nexport type SchematicCreditSpendPolicies = {\n  /** Company-scope policies first, then the user's own; empty when none bind */\n  policies: SchematicJS.CreditSpendPolicies;\n  /** True while the policies are still loading and nothing 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 creditSpendPoliciesCache?: Observable<SchematicCreditSpendPolicies>;\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  /**\n   * Observe every credit spend policy binding the current context, company-scope\n   * first. It emits as partials arrive over the DataStream, so a policy edited\n   * or deleted in the dashboard arrives without a refetch. A window policy also\n   * carries `consumed` and `resetsAt`, which move as credits are spent.\n   */\n  creditSpendPolicies$(): Observable<SchematicCreditSpendPolicies> {\n    if (this.creditSpendPoliciesCache) return this.creditSpendPoliciesCache;\n\n    this.creditSpendPoliciesCache =\n      new Observable<SchematicCreditSpendPolicies>((subscriber) => {\n        const emit = () => {\n          const policies = this.client.getCreditSpendPolicies();\n          subscriber.next({\n            policies,\n            isLoading: policies.length === 0 && this.client.getIsPending(),\n          });\n        };\n\n        emit();\n\n        const unsubscribePolicies = this.client.addCreditSpendPolicyListener(\n          () => emit(),\n        );\n        const unsubscribePending = this.client.addIsPendingListener(() =>\n          emit(),\n        );\n\n        return () => {\n          unsubscribePolicies();\n          unsubscribePending();\n        };\n      }).pipe(\n        distinctUntilChanged(shallowEqual),\n        shareReplay({ bufferSize: 1, refCount: true }),\n        finalize(() => {\n          this.creditSpendPoliciesCache = undefined;\n        }),\n      );\n\n    return this.creditSpendPoliciesCache;\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.7.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"],"mappings":"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"}