bharosa 0.4.0 → 0.5.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.
@@ -1 +1 @@
1
- ebab801a241565a3b115993b6ae8470d144f8d69f79cdb8acc274ff8c200cf3e
1
+ 1d2d37edf6ea65cdd3bac707119c6815ee73c89770a791d7dfdfadc9630b6f2b
@@ -1 +1 @@
1
- 29463b6a150e368a47ac11e2f8f841e3808d94d3ff9b70221fe3804c93b91004
1
+ ef53094920c324ab9d9fd31d8846b6f37da13b757301c6742461ee33b8fe49c4
package/README.md CHANGED
@@ -2,19 +2,19 @@
2
2
 
3
3
  A TypeScript client for Bharosa accounts, investors, portfolios, and mutual funds. Use one resource interface from TypeScript, ESM, or CommonJS, with no runtime dependencies.
4
4
 
5
- **Local release candidate (unpublished):** `bharosa@0.4.0`. Both clients use the production API at `https://api.bharosa.finance` by default. Account access and credentials are still required; installing the SDK does not grant access.
5
+ **Local release candidate (unpublished):** `bharosa@0.5.0`. Both clients use the production API at `https://api.bharosa.finance` by default. Account access and credentials are still required; installing the SDK does not grant access.
6
6
 
7
7
  ## Start here
8
8
 
9
9
  Use Node.js 22.12+ in a supported LTS release. Install the reviewed local candidate in your backend application:
10
10
 
11
11
  ```sh
12
- npm install /absolute/path/to/bharosa-0.4.0.tgz --ignore-scripts
12
+ npm install /absolute/path/to/bharosa-0.5.0.tgz --ignore-scripts
13
13
  ```
14
14
 
15
15
  Source contributors can build and pack a local archive using the commands in CONTRIBUTING.md.
16
16
 
17
- Configure your application's account ID and account key through its secret manager. Then:
17
+ Configure your API key through your backend secret manager. In the local unified-key API candidate, every active key has baseline market access; private account calls require the optional account permissions. Then:
18
18
 
19
19
  ```ts
20
20
  import { Bharosa } from "bharosa";
@@ -25,10 +25,11 @@ function required(name: string): string {
25
25
  return value;
26
26
  }
27
27
  const bharosa = new Bharosa({
28
- account: required("BHAROSA_ACCOUNT_ID"),
29
- auth: { type: "account_key", apiKey: required("BHAROSA_SECRET_KEY") },
28
+ apiKey: required("BHAROSA_SECRET_KEY"),
30
29
  });
31
- const account = await bharosa.accounts.retrieve();
30
+ const latestNav = await bharosa.markets.schemes.nav("45139");
31
+ // Optional own-account permission is required for this call:
32
+ // const account = await bharosa.accounts.retrieve();
32
33
  ```
33
34
 
34
35
  The startup check names missing environment variables without printing their values. See the [complete setup guide](docs/getting-started.md) for explicit checks and delegated authentication. CommonJS uses `const { Bharosa } = require("bharosa")`.
@@ -127,4 +128,10 @@ Set `baseUrl` only for another deployment or tests. Omitted or `undefined` uses
127
128
 
128
129
  ## Growth performance and category returns
129
130
 
130
- Adds `mutualFundSchemes.performance.retrieve` and `fundCategories.statistics.retrieve` for authenticated account access. See [analytics methods, coverage and limitations](docs/analytics.md). These API routes are deployed; this SDK candidate is not yet published. `BharosaMarket` retains its four monthly operations and cannot call account analytics.
131
+ Adds `mutualFundSchemes.performance.retrieve` and `fundCategories.statistics.retrieve` for authenticated account access. See [analytics methods, coverage and limitations](docs/analytics.md). These API routes and the SDK 0.4.0 methods are published; this unified-key SDK candidate is not yet published. `BharosaMarket` retains its four monthly operations and cannot call account analytics.
132
+
133
+ ## Unified-key candidate
134
+
135
+ This local 0.5.0 candidate adds `new Bharosa({ apiKey })` and `client.markets`, using the existing account-independent market routes. Omit the NAV selection for latest NAV, or pass `{ asOf: "2026-10-01" }` for a monthly snapshot. Missing observations return `status: "missing"` and `data: null`. Explicit dates must be month starts. The account-scoped NAV method also accepts omission, while keeping account authorization.
136
+
137
+ Existing `auth` configurations and `BharosaMarket` remain supported. Baseline calls use only the API key; delegated private calls still require user consent and a valid user token. The production origin remains `https://api.bharosa.finance`. Unified-key server changes are locally tested and pending coordinated activation; this archive alone does not activate permissions.
@@ -24,7 +24,7 @@ interface BharosaBaseConfig {
24
24
  readonly allowLocalhostHttp?: boolean;
25
25
  readonly maxResponseBytes?: number;
26
26
  }
27
- export type BharosaConfig = BharosaBaseConfig & ({
27
+ type LegacyBharosaConfig = BharosaBaseConfig & ({
28
28
  readonly auth: Auth;
29
29
  readonly fetch?: typeof globalThis.fetch;
30
30
  readonly transport?: never;
@@ -33,6 +33,17 @@ export type BharosaConfig = BharosaBaseConfig & ({
33
33
  readonly auth?: never;
34
34
  readonly fetch?: never;
35
35
  });
36
+ /** Simple server-side API-key configuration. Account access remains server-authorized. */
37
+ export type BharosaConfig = LegacyBharosaConfig | {
38
+ readonly apiKey: string;
39
+ readonly account?: string;
40
+ readonly baseUrl?: string;
41
+ readonly allowLocalhostHttp?: boolean;
42
+ readonly maxResponseBytes?: number;
43
+ readonly fetch?: typeof globalThis.fetch;
44
+ readonly auth?: never;
45
+ readonly transport?: never;
46
+ };
36
47
  export interface RequestOptions {
37
48
  idempotencyKey?: string;
38
49
  signal?: AbortSignal;
@@ -24,7 +24,7 @@ interface BharosaBaseConfig {
24
24
  readonly allowLocalhostHttp?: boolean;
25
25
  readonly maxResponseBytes?: number;
26
26
  }
27
- export type BharosaConfig = BharosaBaseConfig & ({
27
+ type LegacyBharosaConfig = BharosaBaseConfig & ({
28
28
  readonly auth: Auth;
29
29
  readonly fetch?: typeof globalThis.fetch;
30
30
  readonly transport?: never;
@@ -33,6 +33,17 @@ export type BharosaConfig = BharosaBaseConfig & ({
33
33
  readonly auth?: never;
34
34
  readonly fetch?: never;
35
35
  });
36
+ /** Simple server-side API-key configuration. Account access remains server-authorized. */
37
+ export type BharosaConfig = LegacyBharosaConfig | {
38
+ readonly apiKey: string;
39
+ readonly account?: string;
40
+ readonly baseUrl?: string;
41
+ readonly allowLocalhostHttp?: boolean;
42
+ readonly maxResponseBytes?: number;
43
+ readonly fetch?: typeof globalThis.fetch;
44
+ readonly auth?: never;
45
+ readonly transport?: never;
46
+ };
36
47
  export interface RequestOptions {
37
48
  idempotencyKey?: string;
38
49
  signal?: AbortSignal;
package/dist/index.cjs CHANGED
@@ -45,9 +45,11 @@ class Bharosa {
45
45
  fundCategories;
46
46
  mutualFunds;
47
47
  mutualFundSchemes;
48
+ markets;
48
49
  marketSnapshots;
49
50
  marketData;
50
51
  constructor(config) {
52
+ this.markets = baselineMarkets((0, transport_cjs_1.createTransport)(config, true));
51
53
  const call = (0, transport_cjs_1.createTransport)(config);
52
54
  const analyticsQuery = (q, extra = []) => {
53
55
  (0, transport_cjs_1.keys)(q, ["asOf", "periods", ...extra]);
@@ -314,7 +316,10 @@ class Bharosa {
314
316
  };
315
317
  this.marketSnapshots = {
316
318
  schemes: {
317
- nav: (id, q, o) => call("monthly_nav", { id, ...monthlyQuery(q) }, undefined, o),
319
+ nav: (id, q = {}, o) => {
320
+ (0, transport_cjs_1.keys)(q, ["asOf"]);
321
+ return call("monthly_nav", { id, ...(q.asOf === undefined ? {} : { as_of: q.asOf }) }, undefined, o);
322
+ },
318
323
  expenseRatio: (id, q, o) => call("monthly_expense", { id, ...monthlyQuery(q) }, undefined, o),
319
324
  valuation: (id, input = {}, o) => {
320
325
  (0, transport_cjs_1.keys)(input, ["units", "asOf", "positionDate", "observedValue"]);
@@ -408,24 +413,33 @@ class BharosaMarket {
408
413
  ]);
409
414
  const { apiKey, ...rest } = config;
410
415
  const call = (0, transport_cjs_1.createTransport)({ ...rest, account: "me", auth: { type: "account_key", apiKey } }, true);
411
- const query = (q, paging = false) => {
412
- (0, transport_cjs_1.keys)(q, paging ? ["asOf", "limit", "startingAfter"] : ["asOf"]);
413
- return {
414
- as_of: q.asOf,
415
- ...(q.limit === undefined ? {} : { limit: q.limit }),
416
- ...(q.startingAfter === undefined
417
- ? {}
418
- : { starting_after: q.startingAfter }),
419
- };
420
- };
421
- this.schemes = {
422
- nav: (id, q, o) => call("monthly_nav", { id, ...query(q) }, undefined, o),
423
- expenseRatio: (id, q, o) => call("monthly_expense", { id, ...query(q) }, undefined, o),
424
- };
425
- this.funds = {
426
- portfolio: (id, q, o) => call("monthly_portfolio", { id, ...query(q) }, undefined, o),
427
- holdings: (id, q, o) => call("monthly_holdings", { id, ...query(q, true) }, undefined, o),
428
- };
416
+ const resources = baselineMarkets(call);
417
+ this.schemes = resources.schemes;
418
+ this.funds = resources.funds;
429
419
  }
430
420
  }
431
421
  exports.BharosaMarket = BharosaMarket;
422
+ function baselineMarkets(call) {
423
+ const query = (q, paging = false) => {
424
+ (0, transport_cjs_1.keys)(q, paging ? ["asOf", "limit", "startingAfter"] : ["asOf"]);
425
+ return {
426
+ as_of: q.asOf,
427
+ ...(q.limit === undefined ? {} : { limit: q.limit }),
428
+ ...(q.startingAfter === undefined
429
+ ? {}
430
+ : { starting_after: q.startingAfter }),
431
+ };
432
+ };
433
+ const schemes = {
434
+ nav: (id, q = {}, o) => {
435
+ (0, transport_cjs_1.keys)(q, ["asOf"]);
436
+ return call("monthly_nav", { id, ...(q.asOf === undefined ? {} : { as_of: q.asOf }) }, undefined, o);
437
+ },
438
+ expenseRatio: (id, q, o) => call("monthly_expense", { id, ...query(q) }, undefined, o),
439
+ };
440
+ const funds = {
441
+ portfolio: (id, q, o) => call("monthly_portfolio", { id, ...query(q) }, undefined, o),
442
+ holdings: (id, q, o) => call("monthly_holdings", { id, ...query(q, true) }, undefined, o),
443
+ };
444
+ return Object.freeze({ schemes: Object.freeze(schemes), funds: Object.freeze(funds) });
445
+ }
package/dist/index.d.cts CHANGED
@@ -13,6 +13,7 @@ export declare class Bharosa implements T.ClientSurface {
13
13
  readonly fundCategories: T.ClientSurface["fundCategories"];
14
14
  readonly mutualFunds: T.ClientSurface["mutualFunds"];
15
15
  readonly mutualFundSchemes: T.ClientSurface["mutualFundSchemes"];
16
+ readonly markets: BaselineMarketClient;
16
17
  readonly marketSnapshots: MonthlyMarketClient;
17
18
  readonly marketData: D.MarketDataClient;
18
19
  constructor(config: T.BharosaConfig);
@@ -27,7 +28,16 @@ export interface BharosaMarketConfig {
27
28
  }
28
29
  /** Server-only registered-app monthly market access. No account or user token. */
29
30
  export declare class BharosaMarket {
30
- readonly schemes: Pick<MonthlyMarketClient["schemes"], "nav" | "expenseRatio">;
31
+ readonly schemes: BaselineMarketClient["schemes"];
31
32
  readonly funds: MonthlyMarketClient["funds"];
32
33
  constructor(config: BharosaMarketConfig);
33
34
  }
35
+ export interface BaselineMarketClient {
36
+ readonly schemes: {
37
+ nav(id: string, selection?: {
38
+ asOf?: string;
39
+ }, options?: T.RequestOptions): ReturnType<MonthlyMarketClient["schemes"]["nav"]>;
40
+ expenseRatio: MonthlyMarketClient["schemes"]["expenseRatio"];
41
+ };
42
+ readonly funds: MonthlyMarketClient["funds"];
43
+ }
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export declare class Bharosa implements T.ClientSurface {
13
13
  readonly fundCategories: T.ClientSurface["fundCategories"];
14
14
  readonly mutualFunds: T.ClientSurface["mutualFunds"];
15
15
  readonly mutualFundSchemes: T.ClientSurface["mutualFundSchemes"];
16
+ readonly markets: BaselineMarketClient;
16
17
  readonly marketSnapshots: MonthlyMarketClient;
17
18
  readonly marketData: D.MarketDataClient;
18
19
  constructor(config: T.BharosaConfig);
@@ -27,7 +28,16 @@ export interface BharosaMarketConfig {
27
28
  }
28
29
  /** Server-only registered-app monthly market access. No account or user token. */
29
30
  export declare class BharosaMarket {
30
- readonly schemes: Pick<MonthlyMarketClient["schemes"], "nav" | "expenseRatio">;
31
+ readonly schemes: BaselineMarketClient["schemes"];
31
32
  readonly funds: MonthlyMarketClient["funds"];
32
33
  constructor(config: BharosaMarketConfig);
33
34
  }
35
+ export interface BaselineMarketClient {
36
+ readonly schemes: {
37
+ nav(id: string, selection?: {
38
+ asOf?: string;
39
+ }, options?: T.RequestOptions): ReturnType<MonthlyMarketClient["schemes"]["nav"]>;
40
+ expenseRatio: MonthlyMarketClient["schemes"]["expenseRatio"];
41
+ };
42
+ readonly funds: MonthlyMarketClient["funds"];
43
+ }
@@ -29,12 +29,13 @@ module.exports = {
29
29
  {
30
30
  "name": "as_of",
31
31
  "in": "query",
32
- "required": true,
32
+ "required": false,
33
33
  "schema": {
34
34
  "type": "string",
35
35
  "format": "date",
36
36
  "pattern": "^[0-9]{4}-[0-9]{2}-01$"
37
- }
37
+ },
38
+ "description": "Omit for latest NAV on or before today in Asia/Kolkata. When supplied, must be the first of a month and not in the future. Actual observation date is returned separately."
38
39
  }
39
40
  ],
40
41
  "response": {
@@ -21,7 +21,7 @@ export interface MonthSelection {
21
21
  }
22
22
  export interface MonthlyMarketClient {
23
23
  schemes: {
24
- nav(id: string, query: MonthSelection, options?: RequestOptions): Promise<MarketSnapshot<D.NavObservation>>;
24
+ nav(id: string, query?: Partial<MonthSelection>, options?: RequestOptions): Promise<MarketSnapshot<D.NavObservation>>;
25
25
  expenseRatio(id: string, query: MonthSelection, options?: RequestOptions): Promise<MarketSnapshot<D.ExpenseObservation>>;
26
26
  valuation(id: string, input?: D.ValuationInput, options?: RequestOptions): Promise<D.LatestNavValuation>;
27
27
  };
@@ -21,7 +21,7 @@ export interface MonthSelection {
21
21
  }
22
22
  export interface MonthlyMarketClient {
23
23
  schemes: {
24
- nav(id: string, query: MonthSelection, options?: RequestOptions): Promise<MarketSnapshot<D.NavObservation>>;
24
+ nav(id: string, query?: Partial<MonthSelection>, options?: RequestOptions): Promise<MarketSnapshot<D.NavObservation>>;
25
25
  expenseRatio(id: string, query: MonthSelection, options?: RequestOptions): Promise<MarketSnapshot<D.ExpenseObservation>>;
26
26
  valuation(id: string, input?: D.ValuationInput, options?: RequestOptions): Promise<D.LatestNavValuation>;
27
27
  };
@@ -190,7 +190,7 @@ function responseMatches(id, op, data, params, body, account) {
190
190
  }
191
191
  if (id.startsWith("monthly_") && id !== "monthly_valuation") {
192
192
  const observation = d("observation_date"), requested = d("requested_date"), data = d("data");
193
- if (requested !== params.as_of)
193
+ if (!(id === "monthly_nav" && params.as_of === undefined) && requested !== params.as_of)
194
194
  return false;
195
195
  if (d("status") === "available") {
196
196
  if (typeof observation !== "string" ||
@@ -143,7 +143,17 @@ async function read(response, max, signal) {
143
143
  reader.releaseLock();
144
144
  }
145
145
  }
146
- function createTransport(config, marketOnly = false) {
146
+ function createTransport(input, marketOnly = false) {
147
+ let config;
148
+ if (input != null && typeof input === "object" && Object.hasOwn(input, "apiKey")) {
149
+ keys(input, ["apiKey", "account", "baseUrl", "allowLocalhostHttp", "maxResponseBytes", "fetch"]);
150
+ const simple = input;
151
+ const { apiKey, account, ...rest } = simple;
152
+ config = { ...rest, account: account === undefined ? "me" : account, auth: { type: "account_key", apiKey } };
153
+ }
154
+ else {
155
+ config = input;
156
+ }
147
157
  const customTransport = config?.transport !== undefined;
148
158
  if (!customTransport)
149
159
  assertServer();
@@ -177,7 +187,7 @@ function createTransport(config, marketOnly = false) {
177
187
  (a.type === "delegated_application" && token(a.userAccessToken)));
178
188
  headers = Object.freeze({
179
189
  Authorization: "Bearer " + a.apiKey,
180
- ...(a.type === "delegated_application"
190
+ ...(a.type === "delegated_application" && !marketOnly
181
191
  ? { "Bharosa-User-Authorization": "Bearer " + a.userAccessToken }
182
192
  : {}),
183
193
  Accept: "application/json",
@@ -2,4 +2,4 @@ import type { OperationResults } from "./operation-types.cjs";
2
2
  import type { BharosaConfig, RequestOptions } from "./client-types.cjs";
3
3
  export declare function check(v: unknown): asserts v;
4
4
  export declare function keys(v: unknown, allowed: readonly string[]): void;
5
- export declare function createTransport(config: BharosaConfig, marketOnly?: boolean): <K extends keyof OperationResults>(id: K, params?: Record<string, unknown>, body?: unknown, opts?: RequestOptions) => Promise<OperationResults[K]>;
5
+ export declare function createTransport(input: BharosaConfig, marketOnly?: boolean): <K extends keyof OperationResults>(id: K, params?: Record<string, unknown>, body?: unknown, opts?: RequestOptions) => Promise<OperationResults[K]>;
@@ -2,4 +2,4 @@ import type { OperationResults } from "./operation-types.js";
2
2
  import type { BharosaConfig, RequestOptions } from "./client-types.js";
3
3
  export declare function check(v: unknown): asserts v;
4
4
  export declare function keys(v: unknown, allowed: readonly string[]): void;
5
- export declare function createTransport(config: BharosaConfig, marketOnly?: boolean): <K extends keyof OperationResults>(id: K, params?: Record<string, unknown>, body?: unknown, opts?: RequestOptions) => Promise<OperationResults[K]>;
5
+ export declare function createTransport(input: BharosaConfig, marketOnly?: boolean): <K extends keyof OperationResults>(id: K, params?: Record<string, unknown>, body?: unknown, opts?: RequestOptions) => Promise<OperationResults[K]>;
package/docs/analytics.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Growth scheme performance and category returns
2
2
 
3
- SDK0.4.0 candidate, unpublished. The two API methods are deployed. Default origin is https://api.bharosa.finance, incorporating the reviewed host-default delta directly on published0.3.2; explicit baseUrl overrides remain supported. Account authorization with accounts:read is required. BharosaMarket does not expose these methods.
3
+ The two analytics methods are deployed and published in SDK 0.4.0. This local unified-key successor preserves them. Default origin is https://api.bharosa.finance; explicit baseUrl overrides remain supported. Account authorization with accounts:read is required. BharosaMarket does not expose these methods.
4
4
 
5
5
  ```ts
6
6
  import { Bharosa } from "bharosa";
@@ -6,10 +6,10 @@ Use Node.js 22.12 or later in a supported LTS release. The SDK supports ESM and
6
6
 
7
7
  Obtain your authorized account ID and account key. Bharosa and BharosaMarket default to the production origin `https://api.bharosa.finance`; no API URL environment variable is required. The SDK neither provisions accounts nor runs an OAuth consent flow.
8
8
 
9
- ## Install the unpublished 0.4.0 candidate
9
+ ## Install the unpublished 0.5.0 candidate
10
10
 
11
11
  ```sh
12
- npm install /absolute/path/to/bharosa-0.4.0.tgz --ignore-scripts
12
+ npm install /absolute/path/to/bharosa-0.5.0.tgz --ignore-scripts
13
13
  ```
14
14
 
15
15
  Source contributors can build and pack a local archive as described in CONTRIBUTING.md.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bharosa",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "private": false,
5
5
  "description": "Typed Bharosa resource SDK with server credentials or caller-owned transport.",
6
6
  "license": "MIT",