@ledewire/browser 0.9.0 → 0.10.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
@@ -158,6 +158,7 @@ await lw.auth.signup({ email, password, name, company_invitation_token: token })
158
158
  // Company admins: members, spend caps, Machine users, top-ups, reports
159
159
  const { data: members } = await lw.company.members.list()
160
160
  await lw.company.members.update(members[0].id, { daily_spend_limit_cents: 5000 })
161
+ const { balance_cents, held_cents } = await lw.company.wallet.get() // the Company balance
161
162
  const { data: pending } = await lw.company.wallet.listPendingTopUps()
162
163
  ```
163
164
 
package/dist/index.d.ts CHANGED
@@ -115,9 +115,16 @@ declare class BrowserAuthNamespace {
115
115
  * Tokens are stored automatically after successful signup.
116
116
  *
117
117
  * Pass `company_invitation_token` (from a Company invitation email) to sign
118
- * up and join the Company in one step. If the token does not name a pending
119
- * invitation addressed to this email, the account is still created, without
120
- * a membership.
118
+ * up and join the Company in one step, or `invitation_token` (from a store
119
+ * invitation email) to join the store. If an invitation can't be accepted,
120
+ * nothing is created and the signup is refused; with both tokens it joins
121
+ * both or neither.
122
+ *
123
+ * @throws {LedewireError} With `statusCode === 422` and
124
+ * `type === 'invitation_not_accepted'` when an invitation token can't be
125
+ * accepted. `details.reason` says why (an `InvitationRefusalReason`) and
126
+ * `details.invitation` says which (`'store'` or `'company'`). A `409` still
127
+ * means only that the email is taken.
121
128
  *
122
129
  * @param body - Signup credentials and display name.
123
130
  * @returns The authentication token response.
@@ -135,6 +142,14 @@ declare class BrowserAuthNamespace {
135
142
  * Log in with a Google ID token obtained from the Google OAuth flow.
136
143
  * Tokens are stored automatically after successful login.
137
144
  *
145
+ * Pass `invitation_token` (store) or `company_invitation_token` (Company)
146
+ * from an invitation email to accept it as you sign in. When this call
147
+ * creates the account, an invitation that can't be accepted refuses the
148
+ * whole call with a `422` (`type === 'invitation_not_accepted'`, as for
149
+ * {@link signup}) and nothing is created. For an account that already
150
+ * exists, the sign-in succeeds either way and the response's `invitations`
151
+ * reports what happened to each token sent.
152
+ *
138
153
  * @param body - The Google ID token.
139
154
  * @returns The authentication token response.
140
155
  */
@@ -698,10 +713,12 @@ export declare type CompanyInvitationRequest = Omit<components['schemas']['Compa
698
713
  * Nobody joins until they accept, because joining moves their spending onto
699
714
  * the Company wallet. Every invitation emails a token that accepting requires,
700
715
  * even for a buyer already signed in as the invited address. An existing buyer
701
- * passes it to {@link accept}; a new address passes it to `auth.signup()` as
702
- * `company_invitation_token`, which signs up and joins in one step.
716
+ * passes it to {@link accept}; a new address passes it to `auth.signup()` or
717
+ * `auth.loginWithGoogle()` as `company_invitation_token`, which creates the
718
+ * account and joins in one step.
703
719
  *
704
- * `list()` and `create()` are Company-admin only; `accept()` is for the invitee.
720
+ * `list()`, `create()` and `revoke()` are Company-admin only; `accept()` is for
721
+ * the invitee.
705
722
  *
706
723
  * Obtain via `client.company.invitations` — do not construct directly.
707
724
  *
@@ -737,18 +754,35 @@ declare class CompanyInvitationsNamespace {
737
754
  * already a member or already has a pending invitation.
738
755
  */
739
756
  create(body: CompanyInvitationRequest): Promise<CompanyInvitation>;
757
+ /**
758
+ * Revokes a pending invitation. Company admins only. The emailed token can no
759
+ * longer be accepted, and the address can be invited again at once rather
760
+ * than when this invitation would have expired.
761
+ *
762
+ * @param id - The invitation id (`CompanyInvitation.id`).
763
+ * @throws {ForbiddenError} When the caller is not a Company admin.
764
+ * @throws {NotFoundError} When the caller belongs to no Company, or the
765
+ * invitation is not one of its own.
766
+ * @throws {LedewireError} With `statusCode === 409` when the invitation is no
767
+ * longer pending (accepted, already revoked, or expired).
768
+ */
769
+ revoke(id: string): Promise<void>;
740
770
  /**
741
771
  * Accepts an invitation, opening a membership with the invited role. The
742
772
  * token must belong to an invitation addressed to one of the buyer's
743
773
  * addresses.
744
774
  *
775
+ * Every refusal carries `type === 'invitation_not_accepted'` and the reason
776
+ * as `details.reason` (an `InvitationRefusalReason`).
777
+ *
745
778
  * @param body - The token from the invitation email.
746
779
  * @returns The new membership.
747
780
  * @throws {NotFoundError} When no invitation with this token is addressed to
748
- * this buyer.
749
- * @throws {LedewireError} With `statusCode === 409` when already accepted, or
750
- * when the buyer already belongs to a Company (leave it first); with
751
- * `statusCode === 410` when the invitation has expired or was withdrawn.
781
+ * this buyer (`details.reason === 'not_found'`).
782
+ * @throws {LedewireError} With `statusCode === 409` when already accepted
783
+ * (`'already_accepted'`), or when the buyer already belongs to a Company
784
+ * (`'already_in_company'`; leave it first); with `statusCode === 410` when
785
+ * the invitation has expired or was withdrawn (`'expired'`).
752
786
  */
753
787
  accept(body: CompanyInvitationAcceptRequest): Promise<CompanyMembership>;
754
788
  }
@@ -946,6 +980,22 @@ declare class CompanyMachineUsersNamespace {
946
980
  * blank or too long.
947
981
  */
948
982
  create(body: CompanyMachineUserCreateRequest): Promise<CompanyMachineUser>;
983
+ /**
984
+ * Renames a Machine user or changes its description, under the same name
985
+ * rules as {@link create}. Its keys and sessions are untouched, so the agent
986
+ * keeps working without being re-issued anything. Company reports read the
987
+ * name live, so `company.members`, `company.purchases` and `company.spend`
988
+ * show the new name on earlier rows as well as later ones.
989
+ *
990
+ * @param id - The Machine user id (`CompanyMachineUser.id`).
991
+ * @param body - A new `name`, a new `description` (`null` clears it), or both.
992
+ * @returns The updated Machine user.
993
+ * @throws {NotFoundError} When the Machine user is not in the caller's Company.
994
+ * @throws {LedewireError} With `statusCode === 409` when another active
995
+ * Machine user has this name, or this one is deactivated; with
996
+ * `statusCode === 422` when the name is blank or too long.
997
+ */
998
+ update(id: string, body: CompanyMachineUserUpdateRequest): Promise<CompanyMachineUser>;
949
999
  /**
950
1000
  * Deactivates a Machine user, **permanently**. In one step this closes its
951
1001
  * membership, revokes every key it holds, and ends its sessions. It cannot be
@@ -959,6 +1009,22 @@ declare class CompanyMachineUsersNamespace {
959
1009
  deactivate(id: string): Promise<CompanyMachineUser>;
960
1010
  }
961
1011
 
1012
+ /**
1013
+ * Request body for renaming a Machine user or changing its description. Give
1014
+ * at least one of the two. A `null` or blank `description` clears it; `name`
1015
+ * cannot be `null`, and is at most 100 characters.
1016
+ *
1017
+ * Hand-written: the spec expresses "at least one" as an `anyOf`, which the
1018
+ * generator widens to `unknown`.
1019
+ */
1020
+ export declare type CompanyMachineUserUpdateRequest = {
1021
+ name: string;
1022
+ description?: string | null;
1023
+ } | {
1024
+ name?: string;
1025
+ description: string | null;
1026
+ };
1027
+
962
1028
  /**
963
1029
  * An open Company membership as a Company admin sees it. `id` is the membership
964
1030
  * id the `company.members` methods take — not the member's `user_id`.
@@ -1106,7 +1172,7 @@ declare class CompanyNamespace {
1106
1172
  readonly members: CompanyMembersNamespace;
1107
1173
  /** Machine users and their Buyer keys and MCP API keys (admin). */
1108
1174
  readonly machineUsers: CompanyMachineUsersNamespace;
1109
- /** Fund the Company wallet and list unsettled top-ups (admin). */
1175
+ /** Read and fund the Company wallet, and list unsettled top-ups (admin). */
1110
1176
  readonly wallet: CompanyWalletNamespace;
1111
1177
  /** Everything the Company paid for, attributed to its members (admin). */
1112
1178
  readonly purchases: CompanyPurchasesNamespace;
@@ -1239,16 +1305,27 @@ declare class CompanySpendNamespace {
1239
1305
  export declare type CompanySpendParams = CompanyReportFilters;
1240
1306
 
1241
1307
  /**
1242
- * Fund the Company wallet and track top-ups that have not settled. Company
1243
- * admins only.
1308
+ * The Company wallet as a Company admin sees it: the spendable balance, what
1309
+ * in-flight Bulk acquisitions hold, and what top-ups are on their way. The only
1310
+ * response that carries the Company balance.
1311
+ */
1312
+ export declare type CompanyWallet = components['schemas']['CompanyWallet'];
1313
+
1314
+ /**
1315
+ * Read the Company wallet, fund it, and track top-ups that have not settled.
1316
+ * Company admins only.
1244
1317
  *
1245
1318
  * Members never see the Company balance and cannot fund the Company wallet; a
1246
- * member who runs short is refused at purchase and must ask an admin.
1319
+ * member who runs short is refused at purchase and must ask an admin. Even for
1320
+ * an admin, `wallet.balance()` reports no Company balance: {@link get} is the
1321
+ * only place it appears.
1247
1322
  *
1248
1323
  * Obtain via `client.company.wallet` — do not construct directly.
1249
1324
  *
1250
1325
  * @example
1251
1326
  * ```ts
1327
+ * const { balance_cents, held_cents, pending_top_up_cents } = await client.company.wallet.get()
1328
+ *
1252
1329
  * const session = await client.company.wallet.createPaymentSession({ amount_cents: 50000 })
1253
1330
  * // Confirm with session.client_secret in the payment widget, as for a personal top-up.
1254
1331
  *
@@ -1258,6 +1335,18 @@ export declare type CompanySpendParams = CompanyReportFilters;
1258
1335
  declare class CompanyWalletNamespace {
1259
1336
  private readonly http;
1260
1337
  /* Excluded from this release type: __constructor */
1338
+ /**
1339
+ * Reads the Company wallet: the spendable `balance_cents` (money held by
1340
+ * in-flight Bulk acquisitions is already out of it, and it goes negative when
1341
+ * a reversed top-up takes the wallet below zero), `held_cents` committed to
1342
+ * Company-paid Bulk acquisitions still in progress, and
1343
+ * `pending_top_up_cents`, the total of {@link listPendingTopUps}.
1344
+ *
1345
+ * @returns The Company wallet.
1346
+ * @throws {ForbiddenError} When the caller is not a Company admin.
1347
+ * @throws {NotFoundError} When the caller belongs to no Company.
1348
+ */
1349
+ get(): Promise<CompanyWallet>;
1261
1350
  /**
1262
1351
  * Starts a Company wallet top-up, by card or ACH (`us_bank_account`). Confirm
1263
1352
  * it client-side with the returned `client_secret`, as for a personal top-up.
@@ -1323,6 +1412,34 @@ declare interface components {
1323
1412
  * @description When the access token expires, about 30 minutes after it was issued. Equal to the token's `exp` claim. Refresh before then.
1324
1413
  */
1325
1414
  expires_at: string;
1415
+ /** @description Present only on `POST /v1/auth/login/google` for an account that already existed, when the call carried `invitation_token` or `company_invitation_token`. One entry per token sent. A refused invitation does not refuse the sign-in; it is reported here instead. */
1416
+ invitations?: {
1417
+ store?: components['schemas']['InvitationOutcome'];
1418
+ company?: components['schemas']['InvitationOutcome'];
1419
+ };
1420
+ };
1421
+ InvitationOutcome: {
1422
+ accepted: boolean;
1423
+ reason?: components['schemas']['InvitationRefusalReason'];
1424
+ /** @description The refusal in words, for display. Present when `accepted` is false. */
1425
+ message?: string;
1426
+ };
1427
+ /**
1428
+ * @description Why an invitation was not accepted. `not_found` also covers a Company invitation addressed to another email, deliberately indistinguishable; `expired` covers a withdrawn one; `wrong_email` is a store invitation sent to another address; `already_in_company` means the account belongs to another Company and must leave it first; `already_member` means it already belongs to the store; `invalid` is an invitation that could not be saved.
1429
+ * @enum {string}
1430
+ */
1431
+ InvitationRefusalReason: 'not_found' | 'already_accepted' | 'expired' | 'wrong_email' | 'already_in_company' | 'already_member' | 'invalid';
1432
+ /** @description An invitation refused. Signup and Google sign-in return it with HTTP 422 and name the `invitation`; `POST /v1/company/invitations/accept` returns it with its own status (404, 409 or 410) and no `invitation`. */
1433
+ InvitationNotAcceptedError: {
1434
+ error: {
1435
+ code: number;
1436
+ message: string;
1437
+ /** @enum {string} */
1438
+ type: 'invitation_not_accepted';
1439
+ };
1440
+ reason: components['schemas']['InvitationRefusalReason'];
1441
+ /** @enum {string} */
1442
+ invitation?: 'store' | 'company';
1326
1443
  };
1327
1444
  /** @description Token response for merchant authentication. Includes stores the user has access to so the client can prompt for store selection. */
1328
1445
  MerchantAuthenticationResponse: {
@@ -1390,16 +1507,20 @@ declare interface components {
1390
1507
  * @description Machine-readable reason, present on refusals that carry one. Branch on this rather than on `message`, which is prose and may be reworded. `retrieval_failed` is transient and worth retrying; `not_licensable` means report it undelivered; `price_drifted` means re-quote; `client_error` is ours to fix and must never be retried unchanged; `insufficient_funds` is cleared by funding the wallet and `daily_spend_cap_reached` deliberately is not.
1391
1508
  *
1392
1509
  * On the Bulk acquisition steps: `exclusions_unacknowledged` means post the acknowledgement first; `quote_not_ready` means keep polling a `pending` quote or re-quote a `failed` one (`quote_state` says which); `quote_expired` and `quote_in_progress` mean re-quote, and wait for the re-quote already running; `invalid_acquisition_state` means re-read the acquisition (`status` and `expected_status` are alongside); `nothing_to_hold` means every work was excluded and a different selection is needed; `run_not_started` means the run could not be queued, so nothing was held and the same authorization is safe to retry.
1510
+ *
1511
+ * `invitation_not_accepted` means a store or Company invitation was refused; `reason` alongside says why (see `InvitationNotAcceptedError`).
1393
1512
  * @enum {string}
1394
1513
  */
1395
- type?: 'retrieval_failed' | 'not_licensable' | 'price_drifted' | 'client_error' | 'insufficient_funds' | 'daily_spend_cap_reached' | 'exclusions_unacknowledged' | 'invalid_acquisition_state' | 'quote_not_ready' | 'nothing_to_hold' | 'quote_expired' | 'quote_in_progress' | 'run_not_started';
1514
+ type?: 'retrieval_failed' | 'not_licensable' | 'price_drifted' | 'client_error' | 'insufficient_funds' | 'daily_spend_cap_reached' | 'exclusions_unacknowledged' | 'invalid_acquisition_state' | 'quote_not_ready' | 'nothing_to_hold' | 'quote_expired' | 'quote_in_progress' | 'run_not_started' | 'invitation_not_accepted';
1396
1515
  };
1397
1516
  };
1398
1517
  AuthSignupRequest: {
1399
1518
  email: string;
1400
1519
  password: string;
1401
1520
  name: string;
1402
- /** @description The token from a Company invitation email. When it names a pending invitation addressed to this email, signup also accepts it and the new buyer joins the Company. Otherwise the account is created without a membership. */
1521
+ /** @description The token from a store invitation email. Signup also accepts it and the new account joins the store. If the invitation can't be accepted, nothing is created and the signup is refused with a 422 (`InvitationNotAcceptedError`). */
1522
+ invitation_token?: string;
1523
+ /** @description The token from a Company invitation email. Signup also accepts it and the new buyer joins the Company. If the invitation can't be accepted (unknown, addressed to another email, expired, withdrawn or already accepted), nothing is created and the signup is refused with a 422. A signup carrying both tokens joins both or neither. */
1403
1524
  company_invitation_token?: string;
1404
1525
  };
1405
1526
  AuthLoginEmailRequest: {
@@ -1408,6 +1529,10 @@ declare interface components {
1408
1529
  };
1409
1530
  AuthLoginOAuthRequest: {
1410
1531
  id_token?: string;
1532
+ /** @description The token from a store invitation email. The account joins the store. When this call creates the account and the invitation can't be accepted, nothing is created and the call is refused with a 422. See `company_invitation_token` for an existing account. */
1533
+ invitation_token?: string;
1534
+ /** @description The token from a Company invitation email. When this call creates the account, it also accepts the invitation and the new buyer joins the Company. If the invitation can't be accepted (unknown, addressed to another email, expired, withdrawn or already accepted), nothing is created and the call is refused with a 422. A call creating an account with both tokens joins both or neither. For an account that already exists, each token is accepted if it can be, the sign-in succeeds either way, and the response's `invitations` says what happened to each. */
1535
+ company_invitation_token?: string;
1411
1536
  };
1412
1537
  MerchantEmailLoginRequest: {
1413
1538
  email: string;
@@ -1557,6 +1682,7 @@ declare interface components {
1557
1682
  id: string;
1558
1683
  /** Format: uuid */
1559
1684
  user_id: string;
1685
+ /** @description The member's current name, read when the response is built. Renaming a Machine user (PATCH /v1/company/machine-users/{id}) relabels its earlier rows too; the audit trail keeps the old name. */
1560
1686
  name: string;
1561
1687
  /** @enum {string} */
1562
1688
  kind: 'human' | 'machine';
@@ -1607,6 +1733,11 @@ declare interface components {
1607
1733
  name: string;
1608
1734
  description?: string | null;
1609
1735
  };
1736
+ /** @description At least one of `name` and `description`. A null or blank `description` clears it; `name` cannot be null. */
1737
+ CompanyMachineUserUpdateRequest: {
1738
+ name?: string;
1739
+ description?: string | null;
1740
+ } | unknown | unknown;
1610
1741
  /** @description A Machine user's Buyer key as a Company admin sees it. It logs in through POST /v1/auth/login/buyer-api-key. Its limit is the Machine user's membership Spend cap. */
1611
1742
  CompanyMachineUserBuyerKey: {
1612
1743
  /** Format: uuid */
@@ -1675,6 +1806,18 @@ declare interface components {
1675
1806
  CompanyMemberList: {
1676
1807
  data: components['schemas']['CompanyMember'][];
1677
1808
  };
1809
+ /** @description The Company wallet, as a Company admin sees it. No member-facing response carries these figures; only this one does. */
1810
+ CompanyWallet: {
1811
+ /** @description Spendable now. Money held by in-flight Bulk acquisitions is already out of it. Negative when a reversed top-up has taken the wallet below zero; a purchase is refused whenever the balance does not cover its price. */
1812
+ balance_cents: number;
1813
+ /** @description Committed to Company-paid Bulk acquisitions still in progress, including those started by members who have since left the Company. When an acquisition settles or is cancelled, what it captured is charged and the rest is released back to the balance. */
1814
+ held_cents: number;
1815
+ /** @description The sum of top-ups not yet spendable: the same top-ups GET /v1/company/wallet/pending-top-ups lists. Not part of the balance until each settles. */
1816
+ pending_top_up_cents: number;
1817
+ /** @example usd */
1818
+ currency: string;
1819
+ company_name: string;
1820
+ };
1678
1821
  /** @description A Company wallet top-up that has not yet settled, as a Company admin sees it. */
1679
1822
  CompanyPendingTopUp: {
1680
1823
  /** Format: uuid */
@@ -3585,6 +3728,20 @@ declare interface HttpClientConfig {
3585
3728
  */
3586
3729
  export declare function init(config: BrowserClientConfig): BrowserClient;
3587
3730
 
3731
+ /**
3732
+ * What happened to one invitation token sent with `auth.loginWithGoogle()` for
3733
+ * an account that already existed. A refused invitation does not refuse the
3734
+ * sign-in; `accepted` is `false` and `reason` says why.
3735
+ */
3736
+ export declare type InvitationOutcome = components['schemas']['InvitationOutcome'];
3737
+
3738
+ /**
3739
+ * Why a store or Company invitation was not accepted. Carried by an
3740
+ * {@link InvitationOutcome}, and by a refused signup or Google sign-in as
3741
+ * `LedewireError.details.reason` (with `type === 'invitation_not_accepted'`).
3742
+ */
3743
+ export declare type InvitationRefusalReason = components['schemas']['InvitationRefusalReason'];
3744
+
3588
3745
  /**
3589
3746
  * Base error class for all LedeWire SDK errors.
3590
3747
  * All errors thrown by the SDK are instances of this class,
package/dist/index.js CHANGED
@@ -394,6 +394,9 @@ var S = class {
394
394
  async create(e) {
395
395
  return this.http.post("/v1/company/invitations", e);
396
396
  }
397
+ async revoke(e) {
398
+ return this.http.delete(`/v1/company/invitations/${encodeURIComponent(e)}`);
399
+ }
397
400
  async accept(e) {
398
401
  return this.http.post("/v1/company/invitations/accept", e);
399
402
  }
@@ -439,6 +442,9 @@ var M = class {
439
442
  async create(e) {
440
443
  return this.http.post("/v1/company/machine-users", e);
441
444
  }
445
+ async update(e, t) {
446
+ return this.http.patch(j(e), t);
447
+ }
442
448
  async deactivate(e) {
443
449
  return this.http.delete(j(e));
444
450
  }
@@ -483,6 +489,9 @@ var M = class {
483
489
  constructor(e) {
484
490
  a(this, "http", void 0), this.http = e;
485
491
  }
492
+ async get() {
493
+ return this.http.get("/v1/company/wallet");
494
+ }
486
495
  async createPaymentSession(e) {
487
496
  return this.http.post("/v1/company/wallet/payment-session", e);
488
497
  }