@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
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { generateIdempotencyKey } from "../idempotency.js";
|
|
2
|
+
/** Path ids must match this server-side pattern; we fail fast client-side. */
|
|
3
|
+
const PATH_ID = /^[A-Za-z0-9_]+$/;
|
|
4
|
+
export class DeliveryModule {
|
|
5
|
+
constructor(transport) {
|
|
6
|
+
this.transport = transport;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Create a delivery order. Returns 201 on first write, or 200 with
|
|
10
|
+
* `idempotent: true` when an Idempotency-Key replays an existing order.
|
|
11
|
+
*
|
|
12
|
+
* If you do not pass `idempotencyKey`, the SDK mints one for THIS call only —
|
|
13
|
+
* which is not retry-safe across a process restart. For offline-safe creates,
|
|
14
|
+
* mint and persist the key yourself (or use OfflineQueue).
|
|
15
|
+
*/
|
|
16
|
+
async create(input, opts = {}) {
|
|
17
|
+
if (!Number.isInteger(input.amount_minor) || input.amount_minor < 1) {
|
|
18
|
+
// Mirror the server's EDGE_INVALID_AMOUNT rule so obvious mistakes fail
|
|
19
|
+
// locally without burning a rate-limited request. Server remains the SoT.
|
|
20
|
+
throw new RangeError("amount_minor must be an integer >= 1 (minor units)");
|
|
21
|
+
}
|
|
22
|
+
const { body } = await this.transport.request({
|
|
23
|
+
method: "POST",
|
|
24
|
+
path: "/v1/delivery/orders",
|
|
25
|
+
body: input,
|
|
26
|
+
idempotencyKey: opts.idempotencyKey ?? generateIdempotencyKey("delivery"),
|
|
27
|
+
traceId: opts.traceId,
|
|
28
|
+
signal: opts.signal,
|
|
29
|
+
});
|
|
30
|
+
return body;
|
|
31
|
+
}
|
|
32
|
+
/** Read a delivery order by id. */
|
|
33
|
+
async get(id, opts = {}) {
|
|
34
|
+
if (!PATH_ID.test(id)) {
|
|
35
|
+
throw new RangeError(`invalid order id ${JSON.stringify(id)} (must match ${PATH_ID})`);
|
|
36
|
+
}
|
|
37
|
+
const { body } = await this.transport.request({
|
|
38
|
+
method: "GET",
|
|
39
|
+
path: `/v1/delivery/orders/${id}`,
|
|
40
|
+
traceId: opts.traceId,
|
|
41
|
+
signal: opts.signal,
|
|
42
|
+
});
|
|
43
|
+
return body;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=delivery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delivery.js","sourceRoot":"","sources":["../../src/modules/delivery.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,8EAA8E;AAC9E,MAAM,OAAO,GAAG,iBAAiB,CAAC;AAElC,MAAM,OAAO,cAAc;IACzB,YAA6B,SAAoB;QAApB,cAAS,GAAT,SAAS,CAAW;IAAG,CAAC;IAErD;;;;;;;OAOG;IACH,KAAK,CAAC,MAAM,CAAC,KAAkB,EAAE,OAAoB,EAAE;QACrD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;YACpE,wEAAwE;YACxE,0EAA0E;YAC1E,MAAM,IAAI,UAAU,CAAC,oDAAoD,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAgB;YAC3D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,qBAAqB;YAC3B,IAAI,EAAE,KAAK;YACX,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,sBAAsB,CAAC,UAAU,CAAC;YACzE,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mCAAmC;IACnC,KAAK,CAAC,GAAG,CAAC,EAAU,EAAE,OAAoB,EAAE;QAC1C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,UAAU,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,gBAAgB,OAAO,GAAG,CAAC,CAAC;QACzF,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAgB;YAC3D,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,uBAAuB,EAAE,EAAE;YACjC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kitchen — EXPERIMENTAL.
|
|
3
|
+
*
|
|
4
|
+
* @experimental Schema/golden-client-derived; not yet exercised by the Expo
|
|
5
|
+
* reference app. Shapes may change before they graduate to the stable contract.
|
|
6
|
+
* Promotion rule: experimental -> reference-app exercised -> stable.
|
|
7
|
+
*/
|
|
8
|
+
import type { Transport } from "../../transport.js";
|
|
9
|
+
import type { CallOptions } from "../../types.js";
|
|
10
|
+
export interface TicketCreate {
|
|
11
|
+
station: string;
|
|
12
|
+
items: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface TicketResponse {
|
|
15
|
+
ok: boolean;
|
|
16
|
+
idempotent?: boolean;
|
|
17
|
+
ticket: {
|
|
18
|
+
id: string;
|
|
19
|
+
[k: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export declare class KitchenModule {
|
|
23
|
+
private readonly transport;
|
|
24
|
+
constructor(transport: Transport);
|
|
25
|
+
/** @experimental */
|
|
26
|
+
createTicket(input: TicketCreate, opts?: CallOptions): Promise<TicketResponse>;
|
|
27
|
+
/** @experimental */
|
|
28
|
+
getTicket(id: string, opts?: CallOptions): Promise<TicketResponse>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=kitchen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kitchen.d.ts","sourceRoot":"","sources":["../../../src/modules/experimental/kitchen.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AACD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;CAC9C;AAID,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAEjD,oBAAoB;IACd,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,cAAc,CAAC;IAYxF,oBAAoB;IACd,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,cAAc,CAAC;CAU7E"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { generateIdempotencyKey } from "../../idempotency.js";
|
|
2
|
+
const PATH_ID = /^[A-Za-z0-9_]+$/;
|
|
3
|
+
export class KitchenModule {
|
|
4
|
+
constructor(transport) {
|
|
5
|
+
this.transport = transport;
|
|
6
|
+
}
|
|
7
|
+
/** @experimental */
|
|
8
|
+
async createTicket(input, opts = {}) {
|
|
9
|
+
const { body } = await this.transport.request({
|
|
10
|
+
method: "POST",
|
|
11
|
+
path: "/v1/kitchen/tickets",
|
|
12
|
+
body: input,
|
|
13
|
+
idempotencyKey: opts.idempotencyKey ?? generateIdempotencyKey("kitchen"),
|
|
14
|
+
traceId: opts.traceId,
|
|
15
|
+
signal: opts.signal,
|
|
16
|
+
});
|
|
17
|
+
return body;
|
|
18
|
+
}
|
|
19
|
+
/** @experimental */
|
|
20
|
+
async getTicket(id, opts = {}) {
|
|
21
|
+
if (!PATH_ID.test(id))
|
|
22
|
+
throw new RangeError(`invalid ticket id ${JSON.stringify(id)}`);
|
|
23
|
+
const { body } = await this.transport.request({
|
|
24
|
+
method: "GET",
|
|
25
|
+
path: `/v1/kitchen/tickets/${id}`,
|
|
26
|
+
traceId: opts.traceId,
|
|
27
|
+
signal: opts.signal,
|
|
28
|
+
});
|
|
29
|
+
return body;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=kitchen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kitchen.js","sourceRoot":"","sources":["../../../src/modules/experimental/kitchen.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAY9D,MAAM,OAAO,GAAG,iBAAiB,CAAC;AAElC,MAAM,OAAO,aAAa;IACxB,YAA6B,SAAoB;QAApB,cAAS,GAAT,SAAS,CAAW;IAAG,CAAC;IAErD,oBAAoB;IACpB,KAAK,CAAC,YAAY,CAAC,KAAmB,EAAE,OAAoB,EAAE;QAC5D,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAiB;YAC5D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,qBAAqB;YAC3B,IAAI,EAAE,KAAK;YACX,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,sBAAsB,CAAC,SAAS,CAAC;YACxE,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oBAAoB;IACpB,KAAK,CAAC,SAAS,CAAC,EAAU,EAAE,OAAoB,EAAE;QAChD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,qBAAqB,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACvF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAiB;YAC5D,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,uBAAuB,EAAE,EAAE;YACjC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loyalty — EXPERIMENTAL.
|
|
3
|
+
*
|
|
4
|
+
* @experimental Schema/golden-client-derived; not yet exercised by the Expo
|
|
5
|
+
* reference app. `earn` auto-provisions the member account. Member ids must
|
|
6
|
+
* match [A-Za-z0-9_]+ (no hyphens).
|
|
7
|
+
*/
|
|
8
|
+
import type { Transport } from "../../transport.js";
|
|
9
|
+
import type { CallOptions } from "../../types.js";
|
|
10
|
+
export interface EarnInput {
|
|
11
|
+
points: number;
|
|
12
|
+
reason?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface AccountResponse {
|
|
15
|
+
ok: boolean;
|
|
16
|
+
idempotent?: boolean;
|
|
17
|
+
account: {
|
|
18
|
+
balance: number;
|
|
19
|
+
[k: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export declare class LoyaltyModule {
|
|
23
|
+
private readonly transport;
|
|
24
|
+
constructor(transport: Transport);
|
|
25
|
+
/** @experimental */
|
|
26
|
+
earn(memberId: string, input: EarnInput, opts?: CallOptions): Promise<AccountResponse>;
|
|
27
|
+
/** @experimental */
|
|
28
|
+
getMember(memberId: string, opts?: CallOptions): Promise<AccountResponse>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=loyalty.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loyalty.d.ts","sourceRoot":"","sources":["../../../src/modules/experimental/loyalty.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;CACpD;AAID,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAEjD,oBAAoB;IACd,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAahG,oBAAoB;IACd,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;CAUpF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { generateIdempotencyKey } from "../../idempotency.js";
|
|
2
|
+
const MEMBER_ID = /^[A-Za-z0-9_]+$/;
|
|
3
|
+
export class LoyaltyModule {
|
|
4
|
+
constructor(transport) {
|
|
5
|
+
this.transport = transport;
|
|
6
|
+
}
|
|
7
|
+
/** @experimental */
|
|
8
|
+
async earn(memberId, input, opts = {}) {
|
|
9
|
+
if (!MEMBER_ID.test(memberId))
|
|
10
|
+
throw new RangeError(`invalid member id ${JSON.stringify(memberId)}`);
|
|
11
|
+
const { body } = await this.transport.request({
|
|
12
|
+
method: "POST",
|
|
13
|
+
path: `/v1/loyalty/members/${memberId}/earn`,
|
|
14
|
+
body: input,
|
|
15
|
+
idempotencyKey: opts.idempotencyKey ?? generateIdempotencyKey("loyalty"),
|
|
16
|
+
traceId: opts.traceId,
|
|
17
|
+
signal: opts.signal,
|
|
18
|
+
});
|
|
19
|
+
return body;
|
|
20
|
+
}
|
|
21
|
+
/** @experimental */
|
|
22
|
+
async getMember(memberId, opts = {}) {
|
|
23
|
+
if (!MEMBER_ID.test(memberId))
|
|
24
|
+
throw new RangeError(`invalid member id ${JSON.stringify(memberId)}`);
|
|
25
|
+
const { body } = await this.transport.request({
|
|
26
|
+
method: "GET",
|
|
27
|
+
path: `/v1/loyalty/members/${memberId}`,
|
|
28
|
+
traceId: opts.traceId,
|
|
29
|
+
signal: opts.signal,
|
|
30
|
+
});
|
|
31
|
+
return body;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=loyalty.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loyalty.js","sourceRoot":"","sources":["../../../src/modules/experimental/loyalty.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAY9D,MAAM,SAAS,GAAG,iBAAiB,CAAC;AAEpC,MAAM,OAAO,aAAa;IACxB,YAA6B,SAAoB;QAApB,cAAS,GAAT,SAAS,CAAW;IAAG,CAAC;IAErD,oBAAoB;IACpB,KAAK,CAAC,IAAI,CAAC,QAAgB,EAAE,KAAgB,EAAE,OAAoB,EAAE;QACnE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,qBAAqB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACrG,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAkB;YAC7D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,uBAAuB,QAAQ,OAAO;YAC5C,IAAI,EAAE,KAAK;YACX,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,sBAAsB,CAAC,SAAS,CAAC;YACxE,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oBAAoB;IACpB,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,OAAoB,EAAE;QACtD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,qBAAqB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACrG,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAkB;YAC7D,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,uBAAuB,QAAQ,EAAE;YACvC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marketplace — EXPERIMENTAL.
|
|
3
|
+
*
|
|
4
|
+
* @experimental Schema/golden-client-derived; not yet exercised by the Expo
|
|
5
|
+
* reference app. Money is integer minor units.
|
|
6
|
+
*/
|
|
7
|
+
import type { Transport } from "../../transport.js";
|
|
8
|
+
import type { CallOptions, Currency } from "../../types.js";
|
|
9
|
+
export interface ListingCreate {
|
|
10
|
+
title: string;
|
|
11
|
+
currency: Currency;
|
|
12
|
+
price_minor: number;
|
|
13
|
+
stock: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ListingResponse {
|
|
16
|
+
ok: boolean;
|
|
17
|
+
idempotent?: boolean;
|
|
18
|
+
listing: {
|
|
19
|
+
id: string;
|
|
20
|
+
[k: string]: unknown;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export declare class MarketplaceModule {
|
|
24
|
+
private readonly transport;
|
|
25
|
+
constructor(transport: Transport);
|
|
26
|
+
/** @experimental */
|
|
27
|
+
createListing(input: ListingCreate, opts?: CallOptions): Promise<ListingResponse>;
|
|
28
|
+
/** @experimental */
|
|
29
|
+
getListing(id: string, opts?: CallOptions): Promise<ListingResponse>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=marketplace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketplace.d.ts","sourceRoot":"","sources":["../../../src/modules/experimental/marketplace.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG5D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AACD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;CAC/C;AAID,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAEjD,oBAAoB;IACd,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAY3F,oBAAoB;IACd,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;CAU/E"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { generateIdempotencyKey } from "../../idempotency.js";
|
|
2
|
+
const PATH_ID = /^[A-Za-z0-9_]+$/;
|
|
3
|
+
export class MarketplaceModule {
|
|
4
|
+
constructor(transport) {
|
|
5
|
+
this.transport = transport;
|
|
6
|
+
}
|
|
7
|
+
/** @experimental */
|
|
8
|
+
async createListing(input, opts = {}) {
|
|
9
|
+
const { body } = await this.transport.request({
|
|
10
|
+
method: "POST",
|
|
11
|
+
path: "/v1/marketplace/listings",
|
|
12
|
+
body: input,
|
|
13
|
+
idempotencyKey: opts.idempotencyKey ?? generateIdempotencyKey("market"),
|
|
14
|
+
traceId: opts.traceId,
|
|
15
|
+
signal: opts.signal,
|
|
16
|
+
});
|
|
17
|
+
return body;
|
|
18
|
+
}
|
|
19
|
+
/** @experimental */
|
|
20
|
+
async getListing(id, opts = {}) {
|
|
21
|
+
if (!PATH_ID.test(id))
|
|
22
|
+
throw new RangeError(`invalid listing id ${JSON.stringify(id)}`);
|
|
23
|
+
const { body } = await this.transport.request({
|
|
24
|
+
method: "GET",
|
|
25
|
+
path: `/v1/marketplace/listings/${id}`,
|
|
26
|
+
traceId: opts.traceId,
|
|
27
|
+
signal: opts.signal,
|
|
28
|
+
});
|
|
29
|
+
return body;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=marketplace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketplace.js","sourceRoot":"","sources":["../../../src/modules/experimental/marketplace.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAc9D,MAAM,OAAO,GAAG,iBAAiB,CAAC;AAElC,MAAM,OAAO,iBAAiB;IAC5B,YAA6B,SAAoB;QAApB,cAAS,GAAT,SAAS,CAAW;IAAG,CAAC;IAErD,oBAAoB;IACpB,KAAK,CAAC,aAAa,CAAC,KAAoB,EAAE,OAAoB,EAAE;QAC9D,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAkB;YAC7D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,0BAA0B;YAChC,IAAI,EAAE,KAAK;YACX,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,sBAAsB,CAAC,QAAQ,CAAC;YACvE,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oBAAoB;IACpB,KAAK,CAAC,UAAU,CAAC,EAAU,EAAE,OAAoB,EAAE;QACjD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,sBAAsB,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACxF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAkB;YAC7D,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,4BAA4B,EAAE,EAAE;YACtC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rider — EXPERIMENTAL.
|
|
3
|
+
*
|
|
4
|
+
* @experimental Schema/golden-client-derived; not yet exercised by the Expo
|
|
5
|
+
* reference app.
|
|
6
|
+
*/
|
|
7
|
+
import type { Transport } from "../../transport.js";
|
|
8
|
+
import type { CallOptions } from "../../types.js";
|
|
9
|
+
export interface JobCreate {
|
|
10
|
+
pickup: string;
|
|
11
|
+
dropoff: string;
|
|
12
|
+
}
|
|
13
|
+
export interface JobResponse {
|
|
14
|
+
ok: boolean;
|
|
15
|
+
idempotent?: boolean;
|
|
16
|
+
job: {
|
|
17
|
+
id: string;
|
|
18
|
+
[k: string]: unknown;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare class RiderModule {
|
|
22
|
+
private readonly transport;
|
|
23
|
+
constructor(transport: Transport);
|
|
24
|
+
/** @experimental */
|
|
25
|
+
createJob(input: JobCreate, opts?: CallOptions): Promise<JobResponse>;
|
|
26
|
+
/** @experimental */
|
|
27
|
+
getJob(id: string, opts?: CallOptions): Promise<JobResponse>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=rider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rider.d.ts","sourceRoot":"","sources":["../../../src/modules/experimental/rider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;CAC3C;AAID,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,SAAS;IAEjD,oBAAoB;IACd,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IAY/E,oBAAoB;IACd,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;CAUvE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { generateIdempotencyKey } from "../../idempotency.js";
|
|
2
|
+
const PATH_ID = /^[A-Za-z0-9_]+$/;
|
|
3
|
+
export class RiderModule {
|
|
4
|
+
constructor(transport) {
|
|
5
|
+
this.transport = transport;
|
|
6
|
+
}
|
|
7
|
+
/** @experimental */
|
|
8
|
+
async createJob(input, opts = {}) {
|
|
9
|
+
const { body } = await this.transport.request({
|
|
10
|
+
method: "POST",
|
|
11
|
+
path: "/v1/rider/jobs",
|
|
12
|
+
body: input,
|
|
13
|
+
idempotencyKey: opts.idempotencyKey ?? generateIdempotencyKey("rider"),
|
|
14
|
+
traceId: opts.traceId,
|
|
15
|
+
signal: opts.signal,
|
|
16
|
+
});
|
|
17
|
+
return body;
|
|
18
|
+
}
|
|
19
|
+
/** @experimental */
|
|
20
|
+
async getJob(id, opts = {}) {
|
|
21
|
+
if (!PATH_ID.test(id))
|
|
22
|
+
throw new RangeError(`invalid job id ${JSON.stringify(id)}`);
|
|
23
|
+
const { body } = await this.transport.request({
|
|
24
|
+
method: "GET",
|
|
25
|
+
path: `/v1/rider/jobs/${id}`,
|
|
26
|
+
traceId: opts.traceId,
|
|
27
|
+
signal: opts.signal,
|
|
28
|
+
});
|
|
29
|
+
return body;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=rider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rider.js","sourceRoot":"","sources":["../../../src/modules/experimental/rider.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAY9D,MAAM,OAAO,GAAG,iBAAiB,CAAC;AAElC,MAAM,OAAO,WAAW;IACtB,YAA6B,SAAoB;QAApB,cAAS,GAAT,SAAS,CAAW;IAAG,CAAC;IAErD,oBAAoB;IACpB,KAAK,CAAC,SAAS,CAAC,KAAgB,EAAE,OAAoB,EAAE;QACtD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAc;YACzD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,KAAK;YACX,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,sBAAsB,CAAC,OAAO,CAAC;YACtE,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oBAAoB;IACpB,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,OAAoB,EAAE;QAC7C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,kBAAkB,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACpF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAc;YACzD,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,kBAAkB,EAAE,EAAE;YAC5B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
package/dist/queue.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OfflineQueue — durable, idempotency-owning mutation queue.
|
|
3
|
+
*
|
|
4
|
+
* This is the heart of the mobile design. The rule it enforces:
|
|
5
|
+
*
|
|
6
|
+
* The idempotency key is minted ONCE at enqueue() time, persisted with the
|
|
7
|
+
* payload, and reused on EVERY flush attempt — forever, until the server
|
|
8
|
+
* accepts it. This is what makes "press create in airplane mode, reconnect,
|
|
9
|
+
* sync" produce exactly one order rather than one-per-retry.
|
|
10
|
+
*
|
|
11
|
+
* Retry policy mirrors the SDK transport:
|
|
12
|
+
* - transport failure / 429 -> keep the item, try again next flush
|
|
13
|
+
* - any other non-2xx (4xx validation, etc.) -> the item can NEVER succeed,
|
|
14
|
+
* so it is removed and surfaced as a dead letter (do not loop forever)
|
|
15
|
+
*
|
|
16
|
+
* Storage is pluggable (AsyncStorage on RN, a file/Map in Node/tests) so the
|
|
17
|
+
* SDK core stays runtime-agnostic.
|
|
18
|
+
*/
|
|
19
|
+
import type { DeliveryModule } from "./modules/delivery.js";
|
|
20
|
+
import type { OrderCreate, OrderResponse } from "./types.js";
|
|
21
|
+
import { DoehApiError } from "./errors.js";
|
|
22
|
+
export interface QueueStorage {
|
|
23
|
+
load(): Promise<string | null>;
|
|
24
|
+
save(serialized: string): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/** An in-memory storage — handy for tests and as a reference implementation. */
|
|
27
|
+
export declare class MemoryStorage implements QueueStorage {
|
|
28
|
+
private value;
|
|
29
|
+
load(): Promise<string | null>;
|
|
30
|
+
save(serialized: string): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export interface QueuedMutation {
|
|
33
|
+
/** Local id (also the user-visible "pending order" handle). */
|
|
34
|
+
id: string;
|
|
35
|
+
/** Minted once at enqueue; reused on every attempt. */
|
|
36
|
+
idempotencyKey: string;
|
|
37
|
+
module: "delivery";
|
|
38
|
+
payload: OrderCreate;
|
|
39
|
+
createdAt: string;
|
|
40
|
+
attempts: number;
|
|
41
|
+
lastError?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface DeadLetter {
|
|
44
|
+
mutation: QueuedMutation;
|
|
45
|
+
error: DoehApiError;
|
|
46
|
+
}
|
|
47
|
+
export interface FlushResult {
|
|
48
|
+
/** Mutations the server accepted this flush. */
|
|
49
|
+
succeeded: {
|
|
50
|
+
mutation: QueuedMutation;
|
|
51
|
+
response: OrderResponse;
|
|
52
|
+
}[];
|
|
53
|
+
/** Mutations that can never succeed — removed from the queue. */
|
|
54
|
+
deadLettered: DeadLetter[];
|
|
55
|
+
/** Mutations still pending (transport/429) — remain queued. */
|
|
56
|
+
remaining: QueuedMutation[];
|
|
57
|
+
}
|
|
58
|
+
export declare class OfflineQueue {
|
|
59
|
+
private readonly delivery;
|
|
60
|
+
private readonly storage;
|
|
61
|
+
constructor(delivery: DeliveryModule, storage: QueueStorage);
|
|
62
|
+
private read;
|
|
63
|
+
private write;
|
|
64
|
+
/** Current pending items (read-only snapshot). */
|
|
65
|
+
pending(): Promise<QueuedMutation[]>;
|
|
66
|
+
/**
|
|
67
|
+
* Enqueue a delivery create. Mints and persists the idempotency key now;
|
|
68
|
+
* that key is never regenerated. Returns the local handle.
|
|
69
|
+
*/
|
|
70
|
+
enqueue(payload: OrderCreate): Promise<QueuedMutation>;
|
|
71
|
+
/**
|
|
72
|
+
* Attempt every pending mutation in FIFO order, reusing each stored key.
|
|
73
|
+
* Stops draining on the first retryable failure (likely still offline) so we
|
|
74
|
+
* don't hammer a dead network, but always persists progress.
|
|
75
|
+
*/
|
|
76
|
+
flush(): Promise<FlushResult>;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAe,MAAM,aAAa,CAAC;AAGxD,MAAM,WAAW,YAAY;IAC3B,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzC;AAED,gFAAgF;AAChF,qBAAa,aAAc,YAAW,YAAY;IAChD,OAAO,CAAC,KAAK,CAAuB;IAC9B,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAG9B,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9C;AAED,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,EAAE,EAAE,MAAM,CAAC;IACX,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,SAAS,EAAE;QAAE,QAAQ,EAAE,cAAc,CAAC;QAAC,QAAQ,EAAE,aAAa,CAAA;KAAE,EAAE,CAAC;IACnE,iEAAiE;IACjE,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,+DAA+D;IAC/D,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,YAAY;YAG1B,IAAI;YAWJ,KAAK;IAInB,kDAAkD;IAC5C,OAAO,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAI1C;;;OAGG;IACG,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC;IAe5D;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;CAyCpC"}
|
package/dist/queue.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { DoehApiError, isRetryable } from "./errors.js";
|
|
2
|
+
import { generateIdempotencyKey } from "./idempotency.js";
|
|
3
|
+
/** An in-memory storage — handy for tests and as a reference implementation. */
|
|
4
|
+
export class MemoryStorage {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.value = null;
|
|
7
|
+
}
|
|
8
|
+
async load() {
|
|
9
|
+
return this.value;
|
|
10
|
+
}
|
|
11
|
+
async save(serialized) {
|
|
12
|
+
this.value = serialized;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class OfflineQueue {
|
|
16
|
+
constructor(delivery, storage) {
|
|
17
|
+
this.delivery = delivery;
|
|
18
|
+
this.storage = storage;
|
|
19
|
+
}
|
|
20
|
+
async read() {
|
|
21
|
+
const raw = await this.storage.load();
|
|
22
|
+
if (!raw)
|
|
23
|
+
return [];
|
|
24
|
+
try {
|
|
25
|
+
const parsed = JSON.parse(raw);
|
|
26
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async write(items) {
|
|
33
|
+
await this.storage.save(JSON.stringify(items));
|
|
34
|
+
}
|
|
35
|
+
/** Current pending items (read-only snapshot). */
|
|
36
|
+
async pending() {
|
|
37
|
+
return this.read();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Enqueue a delivery create. Mints and persists the idempotency key now;
|
|
41
|
+
* that key is never regenerated. Returns the local handle.
|
|
42
|
+
*/
|
|
43
|
+
async enqueue(payload) {
|
|
44
|
+
const mutation = {
|
|
45
|
+
id: generateIdempotencyKey("local"),
|
|
46
|
+
idempotencyKey: generateIdempotencyKey("delivery"),
|
|
47
|
+
module: "delivery",
|
|
48
|
+
payload,
|
|
49
|
+
createdAt: new Date().toISOString(),
|
|
50
|
+
attempts: 0,
|
|
51
|
+
};
|
|
52
|
+
const items = await this.read();
|
|
53
|
+
items.push(mutation);
|
|
54
|
+
await this.write(items);
|
|
55
|
+
return mutation;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Attempt every pending mutation in FIFO order, reusing each stored key.
|
|
59
|
+
* Stops draining on the first retryable failure (likely still offline) so we
|
|
60
|
+
* don't hammer a dead network, but always persists progress.
|
|
61
|
+
*/
|
|
62
|
+
async flush() {
|
|
63
|
+
const items = await this.read();
|
|
64
|
+
const result = { succeeded: [], deadLettered: [], remaining: [] };
|
|
65
|
+
const keep = [];
|
|
66
|
+
let networkDown = false;
|
|
67
|
+
for (const m of items) {
|
|
68
|
+
if (networkDown) {
|
|
69
|
+
keep.push(m);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
m.attempts += 1;
|
|
73
|
+
try {
|
|
74
|
+
const response = await this.delivery.create(m.payload, {
|
|
75
|
+
idempotencyKey: m.idempotencyKey, // SAME key, every attempt
|
|
76
|
+
});
|
|
77
|
+
result.succeeded.push({ mutation: m, response });
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
if (isRetryable(err)) {
|
|
81
|
+
// Still offline / rate-limited — keep it and stop draining.
|
|
82
|
+
m.lastError = err.message;
|
|
83
|
+
keep.push(m);
|
|
84
|
+
networkDown = true;
|
|
85
|
+
}
|
|
86
|
+
else if (err instanceof DoehApiError) {
|
|
87
|
+
// Terminal: this payload will never be accepted. Dead-letter it.
|
|
88
|
+
result.deadLettered.push({ mutation: m, error: err });
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// A client-side guard (e.g. bad amount) — also terminal.
|
|
92
|
+
m.lastError = err.message;
|
|
93
|
+
result.deadLettered.push({
|
|
94
|
+
mutation: m,
|
|
95
|
+
error: new DoehApiError(0, "CLIENT_VALIDATION", { body: m.lastError }),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
result.remaining = keep;
|
|
101
|
+
await this.write(keep);
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Pluggable fetch (defaults to global; inject for RN or tests). */
|
|
2
|
+
export type FetchLike = typeof fetch;
|
|
3
|
+
export interface TransportConfig {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
apiKey: string;
|
|
6
|
+
userAgent: string;
|
|
7
|
+
fetch: FetchLike;
|
|
8
|
+
timeoutMs: number;
|
|
9
|
+
maxRetries: number;
|
|
10
|
+
backoffBaseMs: number;
|
|
11
|
+
/** Hook for tests to make backoff instant. */
|
|
12
|
+
sleep?: (ms: number) => Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export interface RequestSpec {
|
|
15
|
+
method: "GET" | "POST";
|
|
16
|
+
path: string;
|
|
17
|
+
body?: unknown;
|
|
18
|
+
idempotencyKey?: string;
|
|
19
|
+
traceId?: string;
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
/** Send no Authorization header (used only to prove the auth gate). */
|
|
22
|
+
anonymous?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface RawResponse<T> {
|
|
25
|
+
status: number;
|
|
26
|
+
body: T;
|
|
27
|
+
traceId: string;
|
|
28
|
+
}
|
|
29
|
+
export declare class Transport {
|
|
30
|
+
private readonly cfg;
|
|
31
|
+
constructor(cfg: TransportConfig);
|
|
32
|
+
/** Send one logical request, retrying transport errors and 429 only. */
|
|
33
|
+
request<T>(spec: RequestSpec): Promise<RawResponse<T>>;
|
|
34
|
+
private attempt;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAeA,oEAAoE;AACpE,MAAM,MAAM,SAAS,GAAG,OAAO,KAAK,CAAC;AAErC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,CAAC;IACR,OAAO,EAAE,MAAM,CAAC;CACjB;AAcD,qBAAa,SAAS;IACR,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,eAAe;IAEjD,wEAAwE;IAClE,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YAqB9C,OAAO;CA0CtB"}
|