@beyondplusmm/doehpos-sdk 0.1.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/CHANGELOG.md +26 -0
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/dist/client.d.ts +53 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +54 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +20 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +63 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +96 -0
- package/dist/errors.js.map +1 -0
- package/dist/idempotency.d.ts +17 -0
- package/dist/idempotency.d.ts.map +1 -0
- package/dist/idempotency.js +30 -0
- package/dist/idempotency.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/delivery.d.ts +26 -0
- package/dist/modules/delivery.d.ts.map +1 -0
- package/dist/modules/delivery.js +46 -0
- package/dist/modules/delivery.js.map +1 -0
- package/dist/modules/experimental/kitchen.d.ts +30 -0
- package/dist/modules/experimental/kitchen.d.ts.map +1 -0
- package/dist/modules/experimental/kitchen.js +32 -0
- package/dist/modules/experimental/kitchen.js.map +1 -0
- package/dist/modules/experimental/loyalty.d.ts +30 -0
- package/dist/modules/experimental/loyalty.d.ts.map +1 -0
- package/dist/modules/experimental/loyalty.js +34 -0
- package/dist/modules/experimental/loyalty.js.map +1 -0
- package/dist/modules/experimental/marketplace.d.ts +31 -0
- package/dist/modules/experimental/marketplace.d.ts.map +1 -0
- package/dist/modules/experimental/marketplace.js +32 -0
- package/dist/modules/experimental/marketplace.js.map +1 -0
- package/dist/modules/experimental/rider.d.ts +29 -0
- package/dist/modules/experimental/rider.d.ts.map +1 -0
- package/dist/modules/experimental/rider.js +32 -0
- package/dist/modules/experimental/rider.js.map +1 -0
- package/dist/queue.d.ts +78 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +105 -0
- package/dist/queue.js.map +1 -0
- package/dist/transport.d.ts +36 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +105 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
- package/src/client.ts +92 -0
- package/src/config.ts +30 -0
- package/src/errors.ts +119 -0
- package/src/idempotency.ts +33 -0
- package/src/index.ts +64 -0
- package/src/modules/delivery.ts +57 -0
- package/src/modules/experimental/kitchen.ts +51 -0
- package/src/modules/experimental/loyalty.ts +52 -0
- package/src/modules/experimental/marketplace.ts +52 -0
- package/src/modules/experimental/rider.ts +50 -0
- package/src/queue.ts +157 -0
- package/src/transport.ts +140 -0
- package/src/types.ts +65 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@beyondplusmm/doehpos-sdk` are documented here. This project adheres to
|
|
4
|
+
[Semantic Versioning](https://semver.org/). The stable surface is `delivery`;
|
|
5
|
+
`@experimental` modules may change in a minor release until they graduate.
|
|
6
|
+
|
|
7
|
+
## 0.1.0
|
|
8
|
+
|
|
9
|
+
Initial release — a typed port of the validated golden client.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `DoehClient` with `environment: "sandbox" | "production"` (cutover is config
|
|
14
|
+
only; no shop concept — scope is derived from the key).
|
|
15
|
+
- **delivery** module (stable): `create`, `get`.
|
|
16
|
+
- **kitchen / loyalty / marketplace / rider** modules (`@experimental`,
|
|
17
|
+
schema-derived, not yet reference-app-exercised).
|
|
18
|
+
- Typed error ABI: `ApiKeyInvalidError`, `ApiKeyExpiredError`,
|
|
19
|
+
`ApiKeyRevokedError`, `EnvMismatchError`, `ScopeDeniedError`,
|
|
20
|
+
`TransportDisabledError`, `OrderNotFoundError`, `ReplayError`,
|
|
21
|
+
`InvalidAmountError`, `UnsupportedCurrencyError`, `BadBodyError`,
|
|
22
|
+
`RateLimitedError`, plus `DoehTransportError`.
|
|
23
|
+
- `OfflineQueue` with pluggable `QueueStorage` — mints one idempotency key per
|
|
24
|
+
mutation and reuses it on every attempt; dead-letters terminal failures.
|
|
25
|
+
- Retry policy limited to transport failures and HTTP 429 (linear backoff).
|
|
26
|
+
- Mandatory `User-Agent`; `Idempotency-Key` and `Trace-Id` headers.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 bplusmyanmar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# @beyondplusmm/doehpos-sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript SDK for the **Doeh POS public API**. A typed port of the
|
|
4
|
+
validated [golden client](../../README.md#provenance) — the SDK exists so the
|
|
5
|
+
public integration surface can never drift from the contract that was proven
|
|
6
|
+
live (14/14) against the sandbox.
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { DoehClient } from "@beyondplusmm/doehpos-sdk";
|
|
10
|
+
|
|
11
|
+
const client = new DoehClient({ apiKey: "sk_test_…", environment: "sandbox" });
|
|
12
|
+
|
|
13
|
+
const { order } = await client.delivery.create({ currency: "MMK", amount_minor: 1500 });
|
|
14
|
+
const { order: same } = await client.delivery.get(order.id);
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Design invariants
|
|
18
|
+
|
|
19
|
+
1. **No shop concept.** Scope (shop/branch) is derived from the key server-side.
|
|
20
|
+
One key == one shop. There is no `shopId` argument anywhere — to act as a
|
|
21
|
+
different shop, use a different key.
|
|
22
|
+
2. **Money is integer minor units.** `1500` == `15.00`. Never a decimal.
|
|
23
|
+
3. **Idempotency is owned by the create.** Pass `idempotencyKey` to make a create
|
|
24
|
+
safely retryable. For offline-safe retries, mint the key **once** and reuse it
|
|
25
|
+
on every attempt — `OfflineQueue` does this for you.
|
|
26
|
+
4. **Retries are narrow.** Only transport failures and HTTP `429` (the fleet rate
|
|
27
|
+
limiter) are retried, with linear backoff. Every other status — including 4xx
|
|
28
|
+
validation and 5xx — is terminal and surfaces immediately.
|
|
29
|
+
5. **Typed error ABI.** Catch classes, never parse `code` strings:
|
|
30
|
+
`ApiKeyInvalidError`, `ApiKeyRevokedError`, `EnvMismatchError`,
|
|
31
|
+
`ScopeDeniedError`, `TransportDisabledError`, `OrderNotFoundError`,
|
|
32
|
+
`ReplayError`, `InvalidAmountError`, `UnsupportedCurrencyError`,
|
|
33
|
+
`BadBodyError`, `RateLimitedError`, plus `DoehTransportError`.
|
|
34
|
+
6. **Mandatory User-Agent.** The edge/WAF rejects default library agents; the SDK
|
|
35
|
+
always sends one. Pass `userAgent` to identify your app in server logs.
|
|
36
|
+
|
|
37
|
+
## Offline queue
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { OfflineQueue, MemoryStorage } from "@beyondplusmm/doehpos-sdk";
|
|
41
|
+
|
|
42
|
+
// On React Native, back this with an AsyncStorage-backed QueueStorage.
|
|
43
|
+
const queue = new OfflineQueue(client.delivery, new MemoryStorage());
|
|
44
|
+
|
|
45
|
+
await queue.enqueue({ currency: "MMK", amount_minor: 1500 }); // mints + persists the key
|
|
46
|
+
// ...later, when connectivity returns:
|
|
47
|
+
const result = await queue.flush(); // reuses the same key — exactly one order
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- `succeeded` — accepted this flush.
|
|
51
|
+
- `remaining` — still pending (offline / rate-limited); retried next flush.
|
|
52
|
+
- `deadLettered` — terminal failures (e.g. validation); removed, never looped.
|
|
53
|
+
|
|
54
|
+
## Stability
|
|
55
|
+
|
|
56
|
+
`delivery` is the **stable** surface. `kitchen`, `loyalty`, `marketplace`, and
|
|
57
|
+
`rider` are **`@experimental`** — generated from their OpenAPI specs and the
|
|
58
|
+
golden client, but not yet exercised by the reference app. They graduate
|
|
59
|
+
experimental → reference-app-exercised → stable. Evidence promotes an API;
|
|
60
|
+
a schema only permits it.
|
|
61
|
+
|
|
62
|
+
## Sandbox boundary
|
|
63
|
+
|
|
64
|
+
Against the sandbox, create + read-back + idempotency are fully real. Downstream
|
|
65
|
+
fulfillment propagation is intentionally absent, so an order's `status` does not
|
|
66
|
+
transition there. Cutover to production is `environment: "production"` + a
|
|
67
|
+
`sk_live_` key — no code change.
|
|
68
|
+
|
|
69
|
+
## Scripts
|
|
70
|
+
|
|
71
|
+
| command | what |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `pnpm build` | compile `src` → `dist` (ESM + types) |
|
|
74
|
+
| `pnpm test` | offline unit tests (fake fetch; no network) |
|
|
75
|
+
| `pnpm test:integration` | live delivery matrix against the sandbox (needs `DOEH_API_KEY`) |
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DoehClient — the public entry point.
|
|
3
|
+
*
|
|
4
|
+
* const client = new DoehClient({ apiKey: "sk_test_…", environment: "sandbox" });
|
|
5
|
+
* const { order } = await client.delivery.create({ currency: "MMK", amount_minor: 1500 });
|
|
6
|
+
*
|
|
7
|
+
* There is intentionally NO shop concept: scope is derived from the key. To act
|
|
8
|
+
* as a different shop, construct a client with a different key. Cutover from
|
|
9
|
+
* sandbox to production is `environment: "production"` + a `sk_live_` key — no
|
|
10
|
+
* code change.
|
|
11
|
+
*/
|
|
12
|
+
import { type Environment } from "./config.js";
|
|
13
|
+
import { Transport, type FetchLike } from "./transport.js";
|
|
14
|
+
import { DeliveryModule } from "./modules/delivery.js";
|
|
15
|
+
import { KitchenModule } from "./modules/experimental/kitchen.js";
|
|
16
|
+
import { LoyaltyModule } from "./modules/experimental/loyalty.js";
|
|
17
|
+
import { MarketplaceModule } from "./modules/experimental/marketplace.js";
|
|
18
|
+
import { RiderModule } from "./modules/experimental/rider.js";
|
|
19
|
+
export interface DoehClientOptions {
|
|
20
|
+
apiKey: string;
|
|
21
|
+
/** "sandbox" (default) or "production". Ignored if baseUrl is given. */
|
|
22
|
+
environment?: Environment;
|
|
23
|
+
/** Override the base URL entirely (advanced / self-host / tests). */
|
|
24
|
+
baseUrl?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Override the (mandatory) User-Agent. The SDK always sends one; supplying
|
|
27
|
+
* your own is encouraged so your app is identifiable in server logs, e.g.
|
|
28
|
+
* "MyMerchantApp/2.1". The SDK token is appended automatically.
|
|
29
|
+
*/
|
|
30
|
+
userAgent?: string;
|
|
31
|
+
/** Inject a fetch implementation (RN / undici / mock). Defaults to global. */
|
|
32
|
+
fetch?: FetchLike;
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
maxRetries?: number;
|
|
35
|
+
/** Test hook to make backoff instant. */
|
|
36
|
+
sleep?: (ms: number) => Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export declare class DoehClient {
|
|
39
|
+
readonly delivery: DeliveryModule;
|
|
40
|
+
/** @experimental Not yet exercised by the reference app. */
|
|
41
|
+
readonly kitchen: KitchenModule;
|
|
42
|
+
/** @experimental Not yet exercised by the reference app. */
|
|
43
|
+
readonly loyalty: LoyaltyModule;
|
|
44
|
+
/** @experimental Not yet exercised by the reference app. */
|
|
45
|
+
readonly marketplace: MarketplaceModule;
|
|
46
|
+
/** @experimental Not yet exercised by the reference app. */
|
|
47
|
+
readonly rider: RiderModule;
|
|
48
|
+
private readonly transport;
|
|
49
|
+
constructor(opts: DoehClientOptions);
|
|
50
|
+
/** Internal: the configured transport (used by OfflineQueue wiring/tests). */
|
|
51
|
+
get _transport(): Transport;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAoC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,qBAAa,UAAU;IACrB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAElC,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC;IACxC,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAE5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAE1B,IAAI,EAAE,iBAAiB;IAkCnC,8EAA8E;IAC9E,IAAI,UAAU,IAAI,SAAS,CAE1B;CACF"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DoehClient — the public entry point.
|
|
3
|
+
*
|
|
4
|
+
* const client = new DoehClient({ apiKey: "sk_test_…", environment: "sandbox" });
|
|
5
|
+
* const { order } = await client.delivery.create({ currency: "MMK", amount_minor: 1500 });
|
|
6
|
+
*
|
|
7
|
+
* There is intentionally NO shop concept: scope is derived from the key. To act
|
|
8
|
+
* as a different shop, construct a client with a different key. Cutover from
|
|
9
|
+
* sandbox to production is `environment: "production"` + a `sk_live_` key — no
|
|
10
|
+
* code change.
|
|
11
|
+
*/
|
|
12
|
+
import { BASE_URLS, DEFAULTS, SDK_VERSION } from "./config.js";
|
|
13
|
+
import { Transport } from "./transport.js";
|
|
14
|
+
import { DeliveryModule } from "./modules/delivery.js";
|
|
15
|
+
import { KitchenModule } from "./modules/experimental/kitchen.js";
|
|
16
|
+
import { LoyaltyModule } from "./modules/experimental/loyalty.js";
|
|
17
|
+
import { MarketplaceModule } from "./modules/experimental/marketplace.js";
|
|
18
|
+
import { RiderModule } from "./modules/experimental/rider.js";
|
|
19
|
+
export class DoehClient {
|
|
20
|
+
constructor(opts) {
|
|
21
|
+
if (!opts.apiKey)
|
|
22
|
+
throw new Error("DoehClient requires an apiKey");
|
|
23
|
+
const env = opts.environment ?? "sandbox";
|
|
24
|
+
const baseUrl = opts.baseUrl ?? BASE_URLS[env];
|
|
25
|
+
const userAgent = opts.userAgent
|
|
26
|
+
? `${opts.userAgent} doeh-sdk/${SDK_VERSION}`
|
|
27
|
+
: `doeh-sdk/${SDK_VERSION}`;
|
|
28
|
+
const fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
29
|
+
if (typeof fetchImpl !== "function") {
|
|
30
|
+
throw new Error("No fetch implementation available. Pass `fetch` in DoehClientOptions " +
|
|
31
|
+
"(e.g. from undici on older Node, or the RN global).");
|
|
32
|
+
}
|
|
33
|
+
this.transport = new Transport({
|
|
34
|
+
baseUrl,
|
|
35
|
+
apiKey: opts.apiKey,
|
|
36
|
+
userAgent,
|
|
37
|
+
fetch: fetchImpl,
|
|
38
|
+
timeoutMs: opts.timeoutMs ?? DEFAULTS.timeoutMs,
|
|
39
|
+
maxRetries: opts.maxRetries ?? DEFAULTS.maxRetries,
|
|
40
|
+
backoffBaseMs: DEFAULTS.backoffBaseMs,
|
|
41
|
+
sleep: opts.sleep,
|
|
42
|
+
});
|
|
43
|
+
this.delivery = new DeliveryModule(this.transport);
|
|
44
|
+
this.kitchen = new KitchenModule(this.transport);
|
|
45
|
+
this.loyalty = new LoyaltyModule(this.transport);
|
|
46
|
+
this.marketplace = new MarketplaceModule(this.transport);
|
|
47
|
+
this.rider = new RiderModule(this.transport);
|
|
48
|
+
}
|
|
49
|
+
/** Internal: the configured transport (used by OfflineQueue wiring/tests). */
|
|
50
|
+
get _transport() {
|
|
51
|
+
return this.transport;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAoB,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,SAAS,EAAkB,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAsB9D,MAAM,OAAO,UAAU;IAcrB,YAAY,IAAuB;QACjC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,IAAI,SAAS,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS;YAC9B,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,aAAa,WAAW,EAAE;YAC7C,CAAC,CAAC,YAAY,WAAW,EAAE,CAAC;QAE9B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,IAAK,UAAU,CAAC,KAA+B,CAAC;QAC5E,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CACb,uEAAuE;gBACrE,qDAAqD,CACxD,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,SAAS,CAAC;YAC7B,OAAO;YACP,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS;YACT,KAAK,EAAE,SAAS;YAChB,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS;YAC/C,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,QAAQ,CAAC,UAAU;YAClD,aAAa,EAAE,QAAQ,CAAC,aAAa;YACrC,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC,OAAO,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC,WAAW,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzD,IAAI,CAAC,KAAK,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;IAED,8EAA8E;IAC9E,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment configuration.
|
|
3
|
+
*
|
|
4
|
+
* "single shop" is NOT a config concept here. The shop/branch scope is derived
|
|
5
|
+
* from the API key server-side — the client never sends scope. One key == one
|
|
6
|
+
* shop. To act as a different shop, use a different key.
|
|
7
|
+
*/
|
|
8
|
+
export type Environment = "sandbox" | "production";
|
|
9
|
+
/** Base URLs per environment, taken verbatim from the validated golden client. */
|
|
10
|
+
export declare const BASE_URLS: Record<Environment, string>;
|
|
11
|
+
/** Default SDK version string surfaced in the (mandatory) User-Agent. */
|
|
12
|
+
export declare const SDK_VERSION = "0.1.0";
|
|
13
|
+
export declare const DEFAULTS: {
|
|
14
|
+
/** Per-request timeout. */
|
|
15
|
+
readonly timeoutMs: 15000;
|
|
16
|
+
/**
|
|
17
|
+
* Max retry attempts. Retries apply ONLY to transport failures and HTTP 429
|
|
18
|
+
* (the fleet rate limiter is a deliberately tight shared token bucket).
|
|
19
|
+
* No other status is ever retried.
|
|
20
|
+
*/
|
|
21
|
+
readonly maxRetries: 4;
|
|
22
|
+
/** Linear backoff base; attempt N waits roughly backoffBaseMs * N. */
|
|
23
|
+
readonly backoffBaseMs: 1000;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;AAEnD,kFAAkF;AAClF,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAGjD,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,WAAW,UAAU,CAAC;AAEnC,eAAO,MAAM,QAAQ;IACnB,2BAA2B;;IAE3B;;;;OAIG;;IAEH,sEAAsE;;CAE9D,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Base URLs per environment, taken verbatim from the validated golden client. */
|
|
2
|
+
export const BASE_URLS = {
|
|
3
|
+
sandbox: "https://sandbox-api.doehpos.com",
|
|
4
|
+
production: "https://api.doehpos.com",
|
|
5
|
+
};
|
|
6
|
+
/** Default SDK version string surfaced in the (mandatory) User-Agent. */
|
|
7
|
+
export const SDK_VERSION = "0.1.0";
|
|
8
|
+
export const DEFAULTS = {
|
|
9
|
+
/** Per-request timeout. */
|
|
10
|
+
timeoutMs: 15_000,
|
|
11
|
+
/**
|
|
12
|
+
* Max retry attempts. Retries apply ONLY to transport failures and HTTP 429
|
|
13
|
+
* (the fleet rate limiter is a deliberately tight shared token bucket).
|
|
14
|
+
* No other status is ever retried.
|
|
15
|
+
*/
|
|
16
|
+
maxRetries: 4,
|
|
17
|
+
/** Linear backoff base; attempt N waits roughly backoffBaseMs * N. */
|
|
18
|
+
backoffBaseMs: 1_000,
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AASA,kFAAkF;AAClF,MAAM,CAAC,MAAM,SAAS,GAAgC;IACpD,OAAO,EAAE,iCAAiC;IAC1C,UAAU,EAAE,yBAAyB;CACtC,CAAC;AAEF,yEAAyE;AACzE,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC;AAEnC,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,2BAA2B;IAC3B,SAAS,EAAE,MAAM;IACjB;;;;OAIG;IACH,UAAU,EAAE,CAAC;IACb,sEAAsE;IACtE,aAAa,EAAE,KAAK;CACZ,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** Base for everything thrown by the SDK. */
|
|
2
|
+
export declare class DoehError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The request never produced an HTTP response (network down, DNS, TLS, timeout,
|
|
7
|
+
* aborted). These are the failures the SDK retries.
|
|
8
|
+
*/
|
|
9
|
+
export declare class DoehTransportError extends DoehError {
|
|
10
|
+
readonly cause?: unknown;
|
|
11
|
+
/** True if the failure was a timeout/abort. */
|
|
12
|
+
readonly timeout: boolean;
|
|
13
|
+
constructor(message: string, opts?: {
|
|
14
|
+
cause?: unknown;
|
|
15
|
+
timeout?: boolean;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/** Any non-2xx HTTP response, carrying the stable `code` and correlation ids. */
|
|
19
|
+
export declare class DoehApiError extends DoehError {
|
|
20
|
+
readonly status: number;
|
|
21
|
+
readonly code: string;
|
|
22
|
+
readonly step?: string;
|
|
23
|
+
readonly traceId?: string;
|
|
24
|
+
readonly body: unknown;
|
|
25
|
+
constructor(status: number, code: string, opts?: {
|
|
26
|
+
step?: string;
|
|
27
|
+
traceId?: string;
|
|
28
|
+
body?: unknown;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export declare class ApiKeyInvalidError extends DoehApiError {
|
|
32
|
+
}
|
|
33
|
+
export declare class ApiKeyExpiredError extends DoehApiError {
|
|
34
|
+
}
|
|
35
|
+
export declare class ApiKeyRevokedError extends DoehApiError {
|
|
36
|
+
}
|
|
37
|
+
export declare class EnvMismatchError extends DoehApiError {
|
|
38
|
+
}
|
|
39
|
+
export declare class ScopeDeniedError extends DoehApiError {
|
|
40
|
+
}
|
|
41
|
+
export declare class TransportDisabledError extends DoehApiError {
|
|
42
|
+
}
|
|
43
|
+
export declare class OrderNotFoundError extends DoehApiError {
|
|
44
|
+
}
|
|
45
|
+
export declare class ReplayError extends DoehApiError {
|
|
46
|
+
}
|
|
47
|
+
export declare class InvalidAmountError extends DoehApiError {
|
|
48
|
+
}
|
|
49
|
+
export declare class UnsupportedCurrencyError extends DoehApiError {
|
|
50
|
+
}
|
|
51
|
+
export declare class BadBodyError extends DoehApiError {
|
|
52
|
+
}
|
|
53
|
+
export declare class RateLimitedError extends DoehApiError {
|
|
54
|
+
}
|
|
55
|
+
/** Build the right typed error from an HTTP status + parsed body. */
|
|
56
|
+
export declare function mapApiError(status: number, body: unknown, traceId?: string): DoehApiError;
|
|
57
|
+
/**
|
|
58
|
+
* The retry predicate, faithful to the golden client: retry ONLY transport
|
|
59
|
+
* failures and HTTP 429. Every other status (incl. 4xx validation and 5xx) is
|
|
60
|
+
* terminal and surfaces immediately.
|
|
61
|
+
*/
|
|
62
|
+
export declare function isRetryable(err: unknown): boolean;
|
|
63
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAcA,6CAA6C;AAC7C,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAM5B;AAED;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,SAAS;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;gBACd,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAO;CAK/E;AAED,iFAAiF;AACjF,qBAAa,YAAa,SAAQ,SAAS;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;gBAErB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAO;CASjE;AAGD,qBAAa,kBAAmB,SAAQ,YAAY;CAAG;AACvD,qBAAa,kBAAmB,SAAQ,YAAY;CAAG;AACvD,qBAAa,kBAAmB,SAAQ,YAAY;CAAG;AACvD,qBAAa,gBAAiB,SAAQ,YAAY;CAAG;AAGrD,qBAAa,gBAAiB,SAAQ,YAAY;CAAG;AACrD,qBAAa,sBAAuB,SAAQ,YAAY;CAAG;AAG3D,qBAAa,kBAAmB,SAAQ,YAAY;CAAG;AACvD,qBAAa,WAAY,SAAQ,YAAY;CAAG;AAChD,qBAAa,kBAAmB,SAAQ,YAAY;CAAG;AACvD,qBAAa,wBAAyB,SAAQ,YAAY;CAAG;AAC7D,qBAAa,YAAa,SAAQ,YAAY;CAAG;AAGjD,qBAAa,gBAAiB,SAAQ,YAAY;CAAG;AAiBrD,qEAAqE;AACrE,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE,MAAM,GACf,YAAY,CAOd;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAIjD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** Base for everything thrown by the SDK. */
|
|
2
|
+
export class DoehError extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = new.target.name;
|
|
6
|
+
// Restore prototype chain for transpiled-to-ES5 consumers.
|
|
7
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The request never produced an HTTP response (network down, DNS, TLS, timeout,
|
|
12
|
+
* aborted). These are the failures the SDK retries.
|
|
13
|
+
*/
|
|
14
|
+
export class DoehTransportError extends DoehError {
|
|
15
|
+
constructor(message, opts = {}) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.cause = opts.cause;
|
|
18
|
+
this.timeout = opts.timeout ?? false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Any non-2xx HTTP response, carrying the stable `code` and correlation ids. */
|
|
22
|
+
export class DoehApiError extends DoehError {
|
|
23
|
+
constructor(status, code, opts = {}) {
|
|
24
|
+
super(`HTTP ${status} ${code}`);
|
|
25
|
+
this.status = status;
|
|
26
|
+
this.code = code;
|
|
27
|
+
this.step = opts.step;
|
|
28
|
+
this.traceId = opts.traceId;
|
|
29
|
+
this.body = opts.body;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// ── 401 — authentication (API_KEY_* ABI) ─────────────────────────────────────
|
|
33
|
+
export class ApiKeyInvalidError extends DoehApiError {
|
|
34
|
+
}
|
|
35
|
+
export class ApiKeyExpiredError extends DoehApiError {
|
|
36
|
+
}
|
|
37
|
+
export class ApiKeyRevokedError extends DoehApiError {
|
|
38
|
+
}
|
|
39
|
+
export class EnvMismatchError extends DoehApiError {
|
|
40
|
+
} // API_KEY_ENV_MISMATCH
|
|
41
|
+
// ── 403 — authenticated but not permitted ────────────────────────────────────
|
|
42
|
+
export class ScopeDeniedError extends DoehApiError {
|
|
43
|
+
} // API_KEY_SCOPE_DENIED
|
|
44
|
+
export class TransportDisabledError extends DoehApiError {
|
|
45
|
+
} // EDGE_TRANSPORT_DISABLED
|
|
46
|
+
// ── 404 / 409 / 422 / 400 ────────────────────────────────────────────────────
|
|
47
|
+
export class OrderNotFoundError extends DoehApiError {
|
|
48
|
+
} // EDGE_ORDER_NOT_FOUND
|
|
49
|
+
export class ReplayError extends DoehApiError {
|
|
50
|
+
} // EDGE_REPLAYED
|
|
51
|
+
export class InvalidAmountError extends DoehApiError {
|
|
52
|
+
} // EDGE_INVALID_AMOUNT
|
|
53
|
+
export class UnsupportedCurrencyError extends DoehApiError {
|
|
54
|
+
} // EDGE_UNSUPPORTED_CURRENCY
|
|
55
|
+
export class BadBodyError extends DoehApiError {
|
|
56
|
+
} // EDGE_BAD_BODY
|
|
57
|
+
// ── 429 — rate limited (retried internally; only surfaced when retries exhaust)
|
|
58
|
+
export class RateLimitedError extends DoehApiError {
|
|
59
|
+
}
|
|
60
|
+
/** Map a stable error code to its typed class. Unknown codes -> DoehApiError. */
|
|
61
|
+
const CODE_TO_CLASS = {
|
|
62
|
+
API_KEY_INVALID: ApiKeyInvalidError,
|
|
63
|
+
API_KEY_EXPIRED: ApiKeyExpiredError,
|
|
64
|
+
API_KEY_REVOKED: ApiKeyRevokedError,
|
|
65
|
+
API_KEY_ENV_MISMATCH: EnvMismatchError,
|
|
66
|
+
API_KEY_SCOPE_DENIED: ScopeDeniedError,
|
|
67
|
+
EDGE_TRANSPORT_DISABLED: TransportDisabledError,
|
|
68
|
+
EDGE_ORDER_NOT_FOUND: OrderNotFoundError,
|
|
69
|
+
EDGE_REPLAYED: ReplayError,
|
|
70
|
+
EDGE_INVALID_AMOUNT: InvalidAmountError,
|
|
71
|
+
EDGE_UNSUPPORTED_CURRENCY: UnsupportedCurrencyError,
|
|
72
|
+
EDGE_BAD_BODY: BadBodyError,
|
|
73
|
+
};
|
|
74
|
+
/** Build the right typed error from an HTTP status + parsed body. */
|
|
75
|
+
export function mapApiError(status, body, traceId) {
|
|
76
|
+
const envelope = (body ?? {});
|
|
77
|
+
const code = typeof envelope.code === "string" ? envelope.code : `HTTP_${status}`;
|
|
78
|
+
const opts = { step: envelope.step, traceId, body };
|
|
79
|
+
if (status === 429)
|
|
80
|
+
return new RateLimitedError(status, code, opts);
|
|
81
|
+
const Cls = CODE_TO_CLASS[code] ?? DoehApiError;
|
|
82
|
+
return new Cls(status, code, opts);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The retry predicate, faithful to the golden client: retry ONLY transport
|
|
86
|
+
* failures and HTTP 429. Every other status (incl. 4xx validation and 5xx) is
|
|
87
|
+
* terminal and surfaces immediately.
|
|
88
|
+
*/
|
|
89
|
+
export function isRetryable(err) {
|
|
90
|
+
if (err instanceof DoehTransportError)
|
|
91
|
+
return true;
|
|
92
|
+
if (err instanceof RateLimitedError)
|
|
93
|
+
return true;
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Idempotency keys.
|
|
3
|
+
*
|
|
4
|
+
* The single most important mobile invariant: a create's idempotency key is
|
|
5
|
+
* minted ONCE — when the mutation is first created — and reused on every
|
|
6
|
+
* attempt, across process restarts and network boundaries. Regenerating a key
|
|
7
|
+
* per attempt produces duplicate orders the instant a retry happens. The
|
|
8
|
+
* OfflineQueue enforces this; callers doing manual retries must do the same.
|
|
9
|
+
*/
|
|
10
|
+
/** A UUID source. Defaults to the platform crypto; injectable for RN/tests. */
|
|
11
|
+
export type UuidFn = () => string;
|
|
12
|
+
/**
|
|
13
|
+
* Generate an idempotency key. The optional prefix makes server logs readable
|
|
14
|
+
* (e.g. "delivery"). Stays within the 200-char header limit.
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateIdempotencyKey(prefix?: string, uuid?: UuidFn): string;
|
|
17
|
+
//# sourceMappingURL=idempotency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,+EAA+E;AAC/E,MAAM,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;AAclC;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,GAAE,MAAqB,GAAG,MAAM,CAG3F"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Idempotency keys.
|
|
3
|
+
*
|
|
4
|
+
* The single most important mobile invariant: a create's idempotency key is
|
|
5
|
+
* minted ONCE — when the mutation is first created — and reused on every
|
|
6
|
+
* attempt, across process restarts and network boundaries. Regenerating a key
|
|
7
|
+
* per attempt produces duplicate orders the instant a retry happens. The
|
|
8
|
+
* OfflineQueue enforces this; callers doing manual retries must do the same.
|
|
9
|
+
*/
|
|
10
|
+
function platformUuid() {
|
|
11
|
+
const c = globalThis.crypto;
|
|
12
|
+
if (c?.randomUUID)
|
|
13
|
+
return c.randomUUID();
|
|
14
|
+
// Last-resort fallback (e.g. older RN without a crypto polyfill). Not
|
|
15
|
+
// cryptographically strong, but collision-safe enough for an idempotency key.
|
|
16
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (ch) => {
|
|
17
|
+
const r = (Math.random() * 16) | 0;
|
|
18
|
+
const v = ch === "x" ? r : (r & 0x3) | 0x8;
|
|
19
|
+
return v.toString(16);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Generate an idempotency key. The optional prefix makes server logs readable
|
|
24
|
+
* (e.g. "delivery"). Stays within the 200-char header limit.
|
|
25
|
+
*/
|
|
26
|
+
export function generateIdempotencyKey(prefix, uuid = platformUuid) {
|
|
27
|
+
const id = uuid();
|
|
28
|
+
return prefix ? `${prefix}-${id}` : id;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=idempotency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../src/idempotency.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,SAAS,YAAY;IACnB,MAAM,CAAC,GAAI,UAAyD,CAAC,MAAM,CAAC;IAC5E,IAAI,CAAC,EAAE,UAAU;QAAE,OAAO,CAAC,CAAC,UAAU,EAAE,CAAC;IACzC,sEAAsE;IACtE,8EAA8E;IAC9E,OAAO,sCAAsC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE;QACpE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;QAC3C,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACxB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAe,EAAE,OAAe,YAAY;IACjF,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC;IAClB,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACzC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @beyondplusmm/doehpos-sdk — official TypeScript SDK for the Doeh POS public API.
|
|
3
|
+
*
|
|
4
|
+
* A typed port of the validated golden client. The stable surface is `delivery`;
|
|
5
|
+
* kitchen/loyalty/marketplace/rider are @experimental until exercised by the
|
|
6
|
+
* reference app.
|
|
7
|
+
*/
|
|
8
|
+
export { DoehClient } from "./client.js";
|
|
9
|
+
export type { DoehClientOptions } from "./client.js";
|
|
10
|
+
export { BASE_URLS, SDK_VERSION, type Environment } from "./config.js";
|
|
11
|
+
export { generateIdempotencyKey, type UuidFn } from "./idempotency.js";
|
|
12
|
+
export { OfflineQueue, MemoryStorage, type QueueStorage, type QueuedMutation, type DeadLetter, type FlushResult, } from "./queue.js";
|
|
13
|
+
export type { Currency, OrderStatus, OrderCreate, Order, OrderResponse, ErrorBody, CallOptions, } from "./types.js";
|
|
14
|
+
export { DoehError, DoehTransportError, DoehApiError, ApiKeyInvalidError, ApiKeyExpiredError, ApiKeyRevokedError, EnvMismatchError, ScopeDeniedError, TransportDisabledError, OrderNotFoundError, ReplayError, InvalidAmountError, UnsupportedCurrencyError, BadBodyError, RateLimitedError, isRetryable, mapApiError, } from "./errors.js";
|
|
15
|
+
export { DeliveryModule } from "./modules/delivery.js";
|
|
16
|
+
export { KitchenModule, type TicketCreate, type TicketResponse } from "./modules/experimental/kitchen.js";
|
|
17
|
+
export { LoyaltyModule, type EarnInput, type AccountResponse } from "./modules/experimental/loyalty.js";
|
|
18
|
+
export { MarketplaceModule, type ListingCreate, type ListingResponse, } from "./modules/experimental/marketplace.js";
|
|
19
|
+
export { RiderModule, type JobCreate, type JobResponse } from "./modules/experimental/rider.js";
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvE,OAAO,EAAE,sBAAsB,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEvE,OAAO,EACL,YAAY,EACZ,aAAa,EACb,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,QAAQ,EACR,WAAW,EACX,WAAW,EACX,KAAK,EACL,aAAa,EACb,SAAS,EACT,WAAW,GACZ,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,wBAAwB,EACxB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,WAAW,GACZ,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAC1G,OAAO,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACxG,OAAO,EACL,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,iCAAiC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @beyondplusmm/doehpos-sdk — official TypeScript SDK for the Doeh POS public API.
|
|
3
|
+
*
|
|
4
|
+
* A typed port of the validated golden client. The stable surface is `delivery`;
|
|
5
|
+
* kitchen/loyalty/marketplace/rider are @experimental until exercised by the
|
|
6
|
+
* reference app.
|
|
7
|
+
*/
|
|
8
|
+
export { DoehClient } from "./client.js";
|
|
9
|
+
export { BASE_URLS, SDK_VERSION } from "./config.js";
|
|
10
|
+
export { generateIdempotencyKey } from "./idempotency.js";
|
|
11
|
+
export { OfflineQueue, MemoryStorage, } from "./queue.js";
|
|
12
|
+
// Error ABI — consumers catch these classes, never parse `code` strings.
|
|
13
|
+
export { DoehError, DoehTransportError, DoehApiError, ApiKeyInvalidError, ApiKeyExpiredError, ApiKeyRevokedError, EnvMismatchError, ScopeDeniedError, TransportDisabledError, OrderNotFoundError, ReplayError, InvalidAmountError, UnsupportedCurrencyError, BadBodyError, RateLimitedError, isRetryable, mapApiError, } from "./errors.js";
|
|
14
|
+
// Module classes + their types (handy for typing app code).
|
|
15
|
+
export { DeliveryModule } from "./modules/delivery.js";
|
|
16
|
+
export { KitchenModule } from "./modules/experimental/kitchen.js";
|
|
17
|
+
export { LoyaltyModule } from "./modules/experimental/loyalty.js";
|
|
18
|
+
export { MarketplaceModule, } from "./modules/experimental/marketplace.js";
|
|
19
|
+
export { RiderModule } from "./modules/experimental/rider.js";
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAoB,MAAM,aAAa,CAAC;AAEvE,OAAO,EAAE,sBAAsB,EAAe,MAAM,kBAAkB,CAAC;AAEvE,OAAO,EACL,YAAY,EACZ,aAAa,GAKd,MAAM,YAAY,CAAC;AAYpB,yEAAyE;AACzE,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,wBAAwB,EACxB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,4DAA4D;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAA0C,MAAM,mCAAmC,CAAC;AAC1G,OAAO,EAAE,aAAa,EAAwC,MAAM,mCAAmC,CAAC;AACxG,OAAO,EACL,iBAAiB,GAGlB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAoC,MAAM,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delivery — the stable, reference-app-exercised vertical.
|
|
3
|
+
*
|
|
4
|
+
* POST /v1/delivery/orders create (idempotent with an Idempotency-Key)
|
|
5
|
+
* GET /v1/delivery/orders/{id} read back
|
|
6
|
+
*
|
|
7
|
+
* Scope is derived from the key server-side; there is no shop/branch argument.
|
|
8
|
+
*/
|
|
9
|
+
import type { Transport } from "../transport.js";
|
|
10
|
+
import type { CallOptions, OrderCreate, OrderResponse } from "../types.js";
|
|
11
|
+
export declare class DeliveryModule {
|
|
12
|
+
private readonly transport;
|
|
13
|
+
constructor(transport: Transport);
|
|
14
|
+
/**
|
|
15
|
+
* Create a delivery order. Returns 201 on first write, or 200 with
|
|
16
|
+
* `idempotent: true` when an Idempotency-Key replays an existing order.
|
|
17
|
+
*
|
|
18
|
+
* If you do not pass `idempotencyKey`, the SDK mints one for THIS call only —
|
|
19
|
+
* which is not retry-safe across a process restart. For offline-safe creates,
|
|
20
|
+
* mint and persist the key yourself (or use OfflineQueue).
|
|
21
|
+
*/
|
|
22
|
+
create(input: OrderCreate, opts?: CallOptions): Promise<OrderResponse>;
|
|
23
|
+
/** Read a delivery order by id. */
|
|
24
|
+
get(id: string, opts?: CallOptions): Promise<OrderResponse>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=delivery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../src/modules/delivery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAM3E,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAEjD;;;;;;;OAOG;IACG,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,aAAa,CAAC;IAiBhF,mCAAmC;IAC7B,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,aAAa,CAAC;CAYtE"}
|