@smess/networking 1.2.0 → 2.0.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 +211 -0
- package/README.md +165 -114
- package/dist/core/body.d.ts +10 -0
- package/dist/core/body.d.ts.map +1 -0
- package/dist/core/body.js +22 -0
- package/dist/core/body.js.map +1 -0
- package/dist/core/client.d.ts +74 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +124 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/decoders.d.ts +8 -0
- package/dist/core/decoders.d.ts.map +1 -0
- package/dist/core/decoders.js +26 -0
- package/dist/core/decoders.js.map +1 -0
- package/dist/core/endpoint.d.ts +69 -0
- package/dist/core/endpoint.d.ts.map +1 -0
- package/dist/core/endpoint.js +6 -0
- package/dist/core/endpoint.js.map +1 -0
- package/dist/core/hosts.d.ts +25 -0
- package/dist/core/hosts.d.ts.map +1 -0
- package/dist/core/hosts.js +22 -0
- package/dist/core/hosts.js.map +1 -0
- package/dist/core/pagination.d.ts +33 -0
- package/dist/core/pagination.d.ts.map +1 -0
- package/dist/core/pagination.js +23 -0
- package/dist/core/pagination.js.map +1 -0
- package/dist/core/pipeline.d.ts +25 -0
- package/dist/core/pipeline.d.ts.map +1 -0
- package/dist/core/pipeline.js +12 -0
- package/dist/core/pipeline.js.map +1 -0
- package/dist/core/retry.d.ts +18 -0
- package/dist/core/retry.d.ts.map +1 -0
- package/dist/core/retry.js +47 -0
- package/dist/core/retry.js.map +1 -0
- package/dist/core/transport.d.ts +30 -0
- package/dist/core/transport.d.ts.map +1 -0
- package/dist/core/transport.js +73 -0
- package/dist/core/transport.js.map +1 -0
- package/dist/core/types.d.ts +24 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/url.d.ts +15 -0
- package/dist/core/url.d.ts.map +1 -0
- package/dist/core/url.js +46 -0
- package/dist/core/url.js.map +1 -0
- package/dist/errors/parse-error-body.d.ts +20 -0
- package/dist/errors/parse-error-body.d.ts.map +1 -0
- package/dist/errors/parse-error-body.js +73 -0
- package/dist/errors/parse-error-body.js.map +1 -0
- package/dist/errors/smess-api-error.d.ts +70 -0
- package/dist/errors/smess-api-error.d.ts.map +1 -0
- package/dist/errors/smess-api-error.js +84 -0
- package/dist/errors/smess-api-error.js.map +1 -0
- package/dist/index.d.ts +27 -25
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -29
- package/dist/index.js.map +1 -0
- package/dist/modules/authentication/index.d.ts +89 -0
- package/dist/modules/authentication/index.d.ts.map +1 -0
- package/dist/modules/authentication/index.js +128 -0
- package/dist/modules/authentication/index.js.map +1 -0
- package/dist/modules/campaign/index.d.ts +212 -0
- package/dist/modules/campaign/index.d.ts.map +1 -0
- package/dist/modules/campaign/index.js +193 -0
- package/dist/modules/campaign/index.js.map +1 -0
- package/dist/modules/campaign/types.d.ts +562 -0
- package/dist/modules/campaign/types.d.ts.map +1 -0
- package/dist/modules/campaign/types.js +2 -0
- package/dist/modules/campaign/types.js.map +1 -0
- package/dist/modules/danara/index.d.ts +153 -0
- package/dist/modules/danara/index.d.ts.map +1 -0
- package/dist/modules/danara/index.js +144 -0
- package/dist/modules/danara/index.js.map +1 -0
- package/dist/modules/danara/types.d.ts +479 -0
- package/dist/modules/danara/types.d.ts.map +1 -0
- package/dist/modules/danara/types.js +2 -0
- package/dist/modules/danara/types.js.map +1 -0
- package/dist/modules/smeup-file/index.d.ts +27 -0
- package/dist/modules/smeup-file/index.d.ts.map +1 -0
- package/dist/modules/smeup-file/index.js +17 -0
- package/dist/modules/smeup-file/index.js.map +1 -0
- package/dist/modules/sso/index.d.ts +40 -0
- package/dist/modules/sso/index.d.ts.map +1 -0
- package/dist/modules/sso/index.js +41 -0
- package/dist/modules/sso/index.js.map +1 -0
- package/dist/rx/index.d.ts +11 -0
- package/dist/rx/index.d.ts.map +1 -0
- package/dist/rx/index.js +20 -0
- package/dist/rx/index.js.map +1 -0
- package/dist/session/auth-middleware.d.ts +27 -0
- package/dist/session/auth-middleware.d.ts.map +1 -0
- package/dist/session/auth-middleware.js +122 -0
- package/dist/session/auth-middleware.js.map +1 -0
- package/dist/session/jwt.d.ts +20 -0
- package/dist/session/jwt.d.ts.map +1 -0
- package/dist/session/jwt.js +25 -0
- package/dist/session/jwt.js.map +1 -0
- package/dist/session/stores.d.ts +19 -0
- package/dist/session/stores.d.ts.map +1 -0
- package/dist/session/stores.js +103 -0
- package/dist/session/stores.js.map +1 -0
- package/dist/session/types.d.ts +28 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +2 -0
- package/dist/session/types.js.map +1 -0
- package/package.json +80 -30
- package/dist/core/axios.d.ts +0 -51
- package/dist/core/axios.js +0 -65
- package/dist/core/axios.observable.d.ts +0 -11
- package/dist/core/axios.observable.js +0 -58
- package/dist/core/base.provider.advanced.test.d.ts +0 -1
- package/dist/core/base.provider.advanced.test.js +0 -29
- package/dist/core/base.provider.d.ts +0 -15
- package/dist/core/base.provider.js +0 -13
- package/dist/core/base.provider.test.d.ts +0 -1
- package/dist/core/base.provider.test.js +0 -36
- package/dist/core/base.service.wrapper.advanced.test.d.ts +0 -1
- package/dist/core/base.service.wrapper.advanced.test.js +0 -39
- package/dist/core/base.service.wrapper.d.ts +0 -7
- package/dist/core/base.service.wrapper.js +0 -11
- package/dist/core/base.service.wrapper.test.d.ts +0 -1
- package/dist/core/base.service.wrapper.test.js +0 -25
- package/dist/core/rx.http.service.d.ts +0 -51
- package/dist/core/rx.http.service.js +0 -65
- package/dist/services/auth.service.d.ts +0 -65
- package/dist/services/auth.service.js +0 -197
- package/dist/services/auth.service.test.d.ts +0 -1
- package/dist/services/auth.service.test.js +0 -334
- package/dist/services/cache.service.d.ts +0 -31
- package/dist/services/cache.service.js +0 -77
- package/dist/services/cache.service.test.d.ts +0 -1
- package/dist/services/cache.service.test.js +0 -88
- package/dist/services/customer.service.d.ts +0 -211
- package/dist/services/customer.service.js +0 -128
- package/dist/services/customer.service.test.d.ts +0 -1
- package/dist/services/customer.service.test.js +0 -430
- package/dist/services/employee.service.d.ts +0 -73
- package/dist/services/employee.service.js +0 -74
- package/dist/services/employee.service.test.d.ts +0 -1
- package/dist/services/employee.service.test.js +0 -127
- package/dist/services/logger.service.d.ts +0 -31
- package/dist/services/logger.service.js +0 -93
- package/dist/services/logger.service.test.d.ts +0 -1
- package/dist/services/logger.service.test.js +0 -31
- package/dist/services/order.service.d.ts +0 -73
- package/dist/services/order.service.js +0 -97
- package/dist/services/order.service.test.d.ts +0 -1
- package/dist/services/order.service.test.js +0 -163
- package/dist/services/product.service.d.ts +0 -21
- package/dist/services/product.service.js +0 -42
- package/dist/services/product.service.test.d.ts +0 -1
- package/dist/services/product.service.test.js +0 -61
- package/dist/services/smess.service.d.ts +0 -36
- package/dist/services/smess.service.js +0 -128
- package/dist/services/smess.service.test.d.ts +0 -1
- package/dist/services/smess.service.test.js +0 -103
- package/dist/services/store.cart.service.d.ts +0 -158
- package/dist/services/store.cart.service.js +0 -177
- package/dist/services/store.cart.service.test.d.ts +0 -1
- package/dist/services/store.cart.service.test.js +0 -394
- package/dist/services/store.product.service.d.ts +0 -124
- package/dist/services/store.product.service.js +0 -102
- package/dist/services/store.product.service.test.d.ts +0 -1
- package/dist/services/store.product.service.test.js +0 -319
- package/dist/services/store.service.d.ts +0 -79
- package/dist/services/store.service.js +0 -235
- package/dist/services/store.service.test.d.ts +0 -1
- package/dist/services/store.service.test.js +0 -274
- package/dist/services/storefront.cart.service.d.ts +0 -73
- package/dist/services/storefront.cart.service.js +0 -167
- package/dist/services/storefront.cart.service.test.d.ts +0 -1
- package/dist/services/storefront.cart.service.test.js +0 -211
- package/dist/services/storefront.checkout.service.d.ts +0 -62
- package/dist/services/storefront.checkout.service.js +0 -75
- package/dist/services/storefront.checkout.service.test.d.ts +0 -1
- package/dist/services/storefront.checkout.service.test.js +0 -158
- package/dist/services/storefront.customer.metadata.service.d.ts +0 -91
- package/dist/services/storefront.customer.metadata.service.js +0 -225
- package/dist/services/storefront.customer.metadata.service.test.d.ts +0 -1
- package/dist/services/storefront.customer.metadata.service.test.js +0 -271
- package/dist/services/storefront.order.service.d.ts +0 -45
- package/dist/services/storefront.order.service.js +0 -99
- package/dist/services/storefront.order.service.test.d.ts +0 -1
- package/dist/services/storefront.order.service.test.js +0 -158
- package/dist/services/storefront.product.service.d.ts +0 -52
- package/dist/services/storefront.product.service.js +0 -75
- package/dist/services/storefront.product.service.test.d.ts +0 -1
- package/dist/services/storefront.product.service.test.js +0 -120
- package/dist/services/storefront.store.service.d.ts +0 -54
- package/dist/services/storefront.store.service.js +0 -142
- package/dist/services/storefront.store.service.test.d.ts +0 -1
- package/dist/services/storefront.store.service.test.js +0 -90
- package/dist/services/user.service.d.ts +0 -16
- package/dist/services/user.service.js +0 -37
- package/dist/services/user.service.test.d.ts +0 -1
- package/dist/services/user.service.test.js +0 -52
- package/dist/services/utils/withAuthReset.d.ts +0 -3
- package/dist/services/utils/withAuthReset.js +0 -8
- package/dist/src/core/axios.d.ts +0 -51
- package/dist/src/core/axios.js +0 -65
- package/dist/src/core/axios.observable.d.ts +0 -11
- package/dist/src/core/axios.observable.js +0 -58
- package/dist/src/core/base.provider.advanced.test.d.ts +0 -1
- package/dist/src/core/base.provider.advanced.test.js +0 -29
- package/dist/src/core/base.provider.d.ts +0 -15
- package/dist/src/core/base.provider.js +0 -13
- package/dist/src/core/base.provider.test.d.ts +0 -1
- package/dist/src/core/base.provider.test.js +0 -36
- package/dist/src/core/base.service.wrapper.advanced.test.d.ts +0 -1
- package/dist/src/core/base.service.wrapper.advanced.test.js +0 -39
- package/dist/src/core/base.service.wrapper.d.ts +0 -7
- package/dist/src/core/base.service.wrapper.js +0 -11
- package/dist/src/core/base.service.wrapper.test.d.ts +0 -1
- package/dist/src/core/base.service.wrapper.test.js +0 -25
- package/dist/src/core/rx.http.service.d.ts +0 -51
- package/dist/src/core/rx.http.service.js +0 -65
- package/dist/src/index.d.ts +0 -25
- package/dist/src/index.js +0 -29
- package/dist/src/services/auth.service.d.ts +0 -65
- package/dist/src/services/auth.service.js +0 -197
- package/dist/src/services/auth.service.test.d.ts +0 -1
- package/dist/src/services/auth.service.test.js +0 -334
- package/dist/src/services/cache.service.d.ts +0 -31
- package/dist/src/services/cache.service.js +0 -77
- package/dist/src/services/cache.service.test.d.ts +0 -1
- package/dist/src/services/cache.service.test.js +0 -88
- package/dist/src/services/customer.service.d.ts +0 -199
- package/dist/src/services/customer.service.js +0 -114
- package/dist/src/services/customer.service.test.d.ts +0 -1
- package/dist/src/services/customer.service.test.js +0 -430
- package/dist/src/services/employee.service.d.ts +0 -73
- package/dist/src/services/employee.service.js +0 -74
- package/dist/src/services/employee.service.test.d.ts +0 -1
- package/dist/src/services/employee.service.test.js +0 -127
- package/dist/src/services/logger.service.d.ts +0 -31
- package/dist/src/services/logger.service.js +0 -93
- package/dist/src/services/logger.service.test.d.ts +0 -1
- package/dist/src/services/logger.service.test.js +0 -31
- package/dist/src/services/order.service.d.ts +0 -73
- package/dist/src/services/order.service.js +0 -97
- package/dist/src/services/order.service.test.d.ts +0 -1
- package/dist/src/services/order.service.test.js +0 -163
- package/dist/src/services/product.service.d.ts +0 -21
- package/dist/src/services/product.service.js +0 -42
- package/dist/src/services/product.service.test.d.ts +0 -1
- package/dist/src/services/product.service.test.js +0 -61
- package/dist/src/services/smess.service.d.ts +0 -36
- package/dist/src/services/smess.service.js +0 -128
- package/dist/src/services/smess.service.test.d.ts +0 -1
- package/dist/src/services/smess.service.test.js +0 -103
- package/dist/src/services/store.cart.service.d.ts +0 -158
- package/dist/src/services/store.cart.service.js +0 -177
- package/dist/src/services/store.cart.service.test.d.ts +0 -1
- package/dist/src/services/store.cart.service.test.js +0 -394
- package/dist/src/services/store.product.service.d.ts +0 -124
- package/dist/src/services/store.product.service.js +0 -102
- package/dist/src/services/store.product.service.test.d.ts +0 -1
- package/dist/src/services/store.product.service.test.js +0 -319
- package/dist/src/services/store.service.d.ts +0 -79
- package/dist/src/services/store.service.js +0 -235
- package/dist/src/services/store.service.test.d.ts +0 -1
- package/dist/src/services/store.service.test.js +0 -274
- package/dist/src/services/storefront.cart.service.d.ts +0 -73
- package/dist/src/services/storefront.cart.service.js +0 -167
- package/dist/src/services/storefront.cart.service.test.d.ts +0 -1
- package/dist/src/services/storefront.cart.service.test.js +0 -211
- package/dist/src/services/storefront.checkout.service.d.ts +0 -62
- package/dist/src/services/storefront.checkout.service.js +0 -75
- package/dist/src/services/storefront.checkout.service.test.d.ts +0 -1
- package/dist/src/services/storefront.checkout.service.test.js +0 -158
- package/dist/src/services/storefront.customer.metadata.service.d.ts +0 -91
- package/dist/src/services/storefront.customer.metadata.service.js +0 -225
- package/dist/src/services/storefront.customer.metadata.service.test.d.ts +0 -1
- package/dist/src/services/storefront.customer.metadata.service.test.js +0 -271
- package/dist/src/services/storefront.order.service.d.ts +0 -45
- package/dist/src/services/storefront.order.service.js +0 -99
- package/dist/src/services/storefront.order.service.test.d.ts +0 -1
- package/dist/src/services/storefront.order.service.test.js +0 -158
- package/dist/src/services/storefront.product.service.d.ts +0 -52
- package/dist/src/services/storefront.product.service.js +0 -75
- package/dist/src/services/storefront.product.service.test.d.ts +0 -1
- package/dist/src/services/storefront.product.service.test.js +0 -120
- package/dist/src/services/storefront.store.service.d.ts +0 -52
- package/dist/src/services/storefront.store.service.js +0 -140
- package/dist/src/services/storefront.store.service.test.d.ts +0 -1
- package/dist/src/services/storefront.store.service.test.js +0 -90
- package/dist/src/services/user.service.d.ts +0 -16
- package/dist/src/services/user.service.js +0 -37
- package/dist/src/services/user.service.test.d.ts +0 -1
- package/dist/src/services/user.service.test.js +0 -52
- package/dist/src/services/utils/withAuthReset.d.ts +0 -3
- package/dist/src/services/utils/withAuthReset.js +0 -8
- package/dist/src/types/types.d.ts +0 -93
- package/dist/src/types/types.js +0 -82
- package/dist/src/types/types.test.d.ts +0 -1
- package/dist/src/types/types.test.js +0 -25
- package/dist/src/utils/cache-import.d.ts +0 -3
- package/dist/src/utils/cache-import.js +0 -2
- package/dist/src/utils/networking-import.d.ts +0 -4
- package/dist/src/utils/networking-import.js +0 -3
- package/dist/src/utils/rxjs-import.d.ts +0 -5
- package/dist/src/utils/rxjs-import.js +0 -5
- package/dist/types/types.d.ts +0 -96
- package/dist/types/types.js +0 -82
- package/dist/types/types.test.d.ts +0 -1
- package/dist/types/types.test.js +0 -25
- package/dist/utils/cache-import.d.ts +0 -3
- package/dist/utils/cache-import.js +0 -2
- package/dist/utils/networking-import.d.ts +0 -4
- package/dist/utils/networking-import.js +0 -3
- package/dist/utils/rxjs-import.d.ts +0 -5
- package/dist/utils/rxjs-import.js +0 -5
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { parseErrorBody } from '../errors/parse-error-body.js';
|
|
2
|
+
import { SmessApiError, errorKindForStatus, parseRetryAfter } from '../errors/smess-api-error.js';
|
|
3
|
+
import { createAuthMiddleware } from '../session/auth-middleware.js';
|
|
4
|
+
import { decodeJwt } from '../session/jwt.js';
|
|
5
|
+
import { encodeBody } from './body.js';
|
|
6
|
+
import { composeMiddleware } from './pipeline.js';
|
|
7
|
+
import { createRetryMiddleware } from './retry.js';
|
|
8
|
+
import { createFetchTransport } from './transport.js';
|
|
9
|
+
import { buildPath, joinUrl, serializeQuery } from './url.js';
|
|
10
|
+
export const DEFAULT_TIMEOUT_MS = 30000;
|
|
11
|
+
export const DEFAULT_REFRESH_SKEW_MS = 30000;
|
|
12
|
+
function errorFromResponse(response, request) {
|
|
13
|
+
const parsed = parseErrorBody(response.data);
|
|
14
|
+
return new SmessApiError({
|
|
15
|
+
kind: response.status < 400 ? 'invalid_response' : errorKindForStatus(response.status),
|
|
16
|
+
status: response.status,
|
|
17
|
+
serverMessage: parsed.message,
|
|
18
|
+
code: parsed.code,
|
|
19
|
+
type: parsed.type,
|
|
20
|
+
param: parsed.param,
|
|
21
|
+
fields: parsed.fields,
|
|
22
|
+
retryAfter: parseRetryAfter(response.headers.get('Retry-After')),
|
|
23
|
+
body: response.data,
|
|
24
|
+
request,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export function createSmessClient(config) {
|
|
28
|
+
const store = config.session ?? null;
|
|
29
|
+
const transport = createFetchTransport(config.fetch);
|
|
30
|
+
const run = composeMiddleware([
|
|
31
|
+
...(config.middleware ?? []),
|
|
32
|
+
...(config.retry ? [createRetryMiddleware(config.retry)] : []),
|
|
33
|
+
createAuthMiddleware({
|
|
34
|
+
store,
|
|
35
|
+
refresh: config.refresh ?? null,
|
|
36
|
+
refreshSkewMs: config.refreshSkewMs ?? DEFAULT_REFRESH_SKEW_MS,
|
|
37
|
+
onSessionExpired: config.onSessionExpired,
|
|
38
|
+
// Refresh calls go through this same client; resolved lazily, after `client` is defined below.
|
|
39
|
+
client: () => client,
|
|
40
|
+
}),
|
|
41
|
+
], (context) => transport(context.request));
|
|
42
|
+
async function execute(spec) {
|
|
43
|
+
const info = { method: spec.method, url: spec.path, ...(spec.service && { service: spec.service }) };
|
|
44
|
+
const base = spec.baseUrl ?? (spec.service ? config.hosts[spec.service] : undefined);
|
|
45
|
+
if (!base) {
|
|
46
|
+
throw new SmessApiError({ kind: 'config', code: 'missing_host', message: `No host configured for service "${spec.service ?? '?'}".`, request: info });
|
|
47
|
+
}
|
|
48
|
+
if (spec.requiresTenant && !config.clientId) {
|
|
49
|
+
throw new SmessApiError({ kind: 'config', code: 'missing_client_id', message: `${spec.method} ${spec.path} needs a clientId (X-Client-Id).`, request: info });
|
|
50
|
+
}
|
|
51
|
+
const responseType = spec.responseType ?? 'json';
|
|
52
|
+
const headers = new Headers({ Accept: responseType === 'json' ? 'application/json' : '*/*' });
|
|
53
|
+
for (const [name, value] of Object.entries(config.headers ?? {}))
|
|
54
|
+
headers.set(name, value);
|
|
55
|
+
if (config.clientId)
|
|
56
|
+
headers.set('X-Client-Id', config.clientId);
|
|
57
|
+
const encoded = encodeBody(spec.body);
|
|
58
|
+
if (encoded.contentType)
|
|
59
|
+
headers.set('Content-Type', encoded.contentType);
|
|
60
|
+
if (spec.idempotencyKey)
|
|
61
|
+
headers.set('Idempotency-Key', spec.idempotencyKey);
|
|
62
|
+
for (const [name, value] of Object.entries(spec.headers ?? {}))
|
|
63
|
+
headers.set(name, value);
|
|
64
|
+
const request = {
|
|
65
|
+
method: spec.method,
|
|
66
|
+
url: joinUrl(base, buildPath(spec.path, spec.pathParams)) + serializeQuery(spec.query),
|
|
67
|
+
headers,
|
|
68
|
+
body: encoded.body,
|
|
69
|
+
replayable: encoded.replayable,
|
|
70
|
+
signal: spec.signal,
|
|
71
|
+
timeoutMs: spec.timeoutMs ?? config.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
72
|
+
responseType,
|
|
73
|
+
fetchOptions: { ...config.fetchOptions, ...spec.fetchOptions },
|
|
74
|
+
};
|
|
75
|
+
const response = await run({
|
|
76
|
+
endpoint: { service: spec.service, method: spec.method, path: spec.path, auth: spec.auth },
|
|
77
|
+
request,
|
|
78
|
+
meta: {},
|
|
79
|
+
});
|
|
80
|
+
const finalInfo = { ...info, url: request.url };
|
|
81
|
+
if (!response.ok)
|
|
82
|
+
throw errorFromResponse(response, finalInfo);
|
|
83
|
+
if (response.unparsable) {
|
|
84
|
+
throw new SmessApiError({ kind: 'invalid_response', status: response.status, message: 'The server did not return JSON.', body: response.data, request: finalInfo });
|
|
85
|
+
}
|
|
86
|
+
return spec.decode ? spec.decode(response.data, response) : response.data;
|
|
87
|
+
}
|
|
88
|
+
const client = {
|
|
89
|
+
config,
|
|
90
|
+
call(endpoint, ...args) {
|
|
91
|
+
const input = (args[0] ?? {});
|
|
92
|
+
return execute({
|
|
93
|
+
...input,
|
|
94
|
+
service: endpoint.service,
|
|
95
|
+
method: endpoint.method,
|
|
96
|
+
path: endpoint.path,
|
|
97
|
+
pathParams: input.path,
|
|
98
|
+
auth: endpoint.auth,
|
|
99
|
+
requiresTenant: endpoint.requiresTenant,
|
|
100
|
+
responseType: endpoint.responseType,
|
|
101
|
+
decode: endpoint.decode,
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
request: (raw) => execute(raw),
|
|
105
|
+
with: (overrides) => createSmessClient({ ...config, ...overrides, headers: { ...config.headers, ...overrides.headers } }),
|
|
106
|
+
session: {
|
|
107
|
+
get: async () => (store ? await store.get() : null),
|
|
108
|
+
set: async (session) => {
|
|
109
|
+
if (store)
|
|
110
|
+
await store.set(session);
|
|
111
|
+
},
|
|
112
|
+
clear: async () => {
|
|
113
|
+
if (store)
|
|
114
|
+
await store.clear();
|
|
115
|
+
},
|
|
116
|
+
claims: async () => {
|
|
117
|
+
const session = store ? await store.get() : null;
|
|
118
|
+
return session ? decodeJwt(session.accessToken) : null;
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
return client;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HttpResponse } from './transport.js';
|
|
2
|
+
/** `{"data": X}` → X. Fails with `invalid_response` when the wrapper is missing. */
|
|
3
|
+
export declare function unwrapData<T>(data: unknown, response: HttpResponse): T;
|
|
4
|
+
/** `{}` / empty body → `undefined`; for endpoints that only acknowledge (`new JsonResponse()` is `{}`). */
|
|
5
|
+
export declare function ignoreBody(): undefined;
|
|
6
|
+
/** `{}` (Symfony's encoding of `JsonResponse(null)`) or an empty body → null; anything else unchanged. */
|
|
7
|
+
export declare function emptyObjectAsNull<T>(data: unknown): T | null;
|
|
8
|
+
//# sourceMappingURL=decoders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decoders.d.ts","sourceRoot":"","sources":["../../src/core/decoders.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,GAAG,CAAC,CAQtE;AAED,2GAA2G;AAC3G,wBAAgB,UAAU,IAAI,SAAS,CAEtC;AAED,0GAA0G;AAC1G,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC,GAAG,IAAI,CAI5D"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SmessApiError } from '../errors/smess-api-error.js';
|
|
2
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
3
|
+
/** `{"data": X}` → X. Fails with `invalid_response` when the wrapper is missing. */
|
|
4
|
+
export function unwrapData(data, response) {
|
|
5
|
+
if (isRecord(data) && 'data' in data)
|
|
6
|
+
return data.data;
|
|
7
|
+
throw new SmessApiError({
|
|
8
|
+
kind: 'invalid_response',
|
|
9
|
+
status: response.status,
|
|
10
|
+
message: 'Expected a {"data": …} response.',
|
|
11
|
+
body: data,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
/** `{}` / empty body → `undefined`; for endpoints that only acknowledge (`new JsonResponse()` is `{}`). */
|
|
15
|
+
export function ignoreBody() {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
/** `{}` (Symfony's encoding of `JsonResponse(null)`) or an empty body → null; anything else unchanged. */
|
|
19
|
+
export function emptyObjectAsNull(data) {
|
|
20
|
+
if (data === undefined || data === null)
|
|
21
|
+
return null;
|
|
22
|
+
if (isRecord(data) && Object.keys(data).length === 0)
|
|
23
|
+
return null;
|
|
24
|
+
return data;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=decoders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decoders.js","sourceRoot":"","sources":["../../src/core/decoders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CACpE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAEvE,oFAAoF;AACpF,MAAM,UAAU,UAAU,CAAI,IAAa,EAAE,QAAsB;IACjE,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,MAAM,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC,IAAS,CAAC;IAC5D,MAAM,IAAI,aAAa,CAAC;QACtB,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,OAAO,EAAE,kCAAkC;QAC3C,IAAI,EAAE,IAAI;KACX,CAAC,CAAC;AACL,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,UAAU;IACxB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,0GAA0G;AAC1G,MAAM,UAAU,iBAAiB,CAAI,IAAa;IAChD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACrD,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAClE,OAAO,IAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ServiceKey } from './hosts.js';
|
|
2
|
+
import type { HttpResponse } from './transport.js';
|
|
3
|
+
import type { AuthMode, FetchOptions, HttpMethod, QueryParams, ResponseType } from './types.js';
|
|
4
|
+
import type { HasPathParams, PathParams } from './url.js';
|
|
5
|
+
/**
|
|
6
|
+
* One core-services route, declared as data. Modules are built from these; tests assert them; a later
|
|
7
|
+
* OpenAPI generator can emit them.
|
|
8
|
+
*/
|
|
9
|
+
export interface Endpoint<P extends string = string, TBody = unknown, TQuery = unknown, TResult = unknown> {
|
|
10
|
+
readonly service: ServiceKey;
|
|
11
|
+
readonly method: HttpMethod;
|
|
12
|
+
/** Absolute path with `{name}` placeholders, e.g. `/v1/campaigns/email/templates/{id}`. */
|
|
13
|
+
readonly path: P;
|
|
14
|
+
readonly auth: AuthMode;
|
|
15
|
+
/** The route rejects requests without `X-Client-Id`; calling it on a client without `clientId` fails fast. */
|
|
16
|
+
readonly requiresTenant?: boolean;
|
|
17
|
+
readonly responseType?: ResponseType;
|
|
18
|
+
/** Turns the response body into the result; default: the parsed body. */
|
|
19
|
+
readonly decode?: (data: unknown, response: HttpResponse) => TResult;
|
|
20
|
+
/** Type-only carrier, never set at runtime. */
|
|
21
|
+
readonly __types?: {
|
|
22
|
+
readonly body: TBody;
|
|
23
|
+
readonly query: TQuery;
|
|
24
|
+
readonly result: TResult;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** A "none" marker for endpoints that take no body or no query. */
|
|
28
|
+
export type None = never;
|
|
29
|
+
/**
|
|
30
|
+
* Declares an endpoint. Curried so the result/body/query types are explicit while the path literal is
|
|
31
|
+
* inferred: `defineEndpoint<Template, TemplateInput>()({ service, method: 'POST', path: '/v1/x/{id}', auth })`.
|
|
32
|
+
*/
|
|
33
|
+
export declare const defineEndpoint: <TResult = unknown, TBody = None, TQuery = None>() => <const P extends string>(definition: Omit<Endpoint<P, TBody, TQuery, TResult>, "__types">) => Endpoint<P, TBody, TQuery, TResult>;
|
|
34
|
+
/** Per-call options every request accepts. */
|
|
35
|
+
export interface CallOptions {
|
|
36
|
+
signal?: AbortSignal;
|
|
37
|
+
/** Overrides the client's timeout for this call; 0 disables it. */
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
/** Extra headers; they win over client defaults (but `auth: 'none'` still strips Authorization). */
|
|
40
|
+
headers?: Readonly<Record<string, string>>;
|
|
41
|
+
/** Sent as `Idempotency-Key`. Browsers: only on hosts whose CORS config allows the header. */
|
|
42
|
+
idempotencyKey?: string;
|
|
43
|
+
fetchOptions?: FetchOptions;
|
|
44
|
+
}
|
|
45
|
+
type PathPart<P extends string> = HasPathParams<P> extends true ? {
|
|
46
|
+
path: PathParams<P>;
|
|
47
|
+
} : {
|
|
48
|
+
path?: undefined;
|
|
49
|
+
};
|
|
50
|
+
type BodyPart<B> = [B] extends [never] ? {
|
|
51
|
+
body?: undefined;
|
|
52
|
+
} : {
|
|
53
|
+
body: B;
|
|
54
|
+
};
|
|
55
|
+
type QueryPart<Q> = [Q] extends [never] ? {
|
|
56
|
+
query?: undefined;
|
|
57
|
+
} : {
|
|
58
|
+
query?: Q;
|
|
59
|
+
};
|
|
60
|
+
export type CallInput<E> = E extends Endpoint<infer P, infer B, infer Q, unknown> ? CallOptions & PathPart<P> & BodyPart<B> & QueryPart<Q> : never;
|
|
61
|
+
export type EndpointResult<E> = E extends Endpoint<string, unknown, unknown, infer R> ? R : never;
|
|
62
|
+
type RequiredKeys<T> = {
|
|
63
|
+
[K in keyof T]-?: Record<never, never> extends Pick<T, K> ? never : K;
|
|
64
|
+
}[keyof T];
|
|
65
|
+
/** `[input?]` when every input field is optional, `[input]` otherwise. */
|
|
66
|
+
export type CallArgs<E> = [RequiredKeys<CallInput<E>>] extends [never] ? [input?: CallInput<E>] : [input: CallInput<E>];
|
|
67
|
+
export type AnyEndpoint = Endpoint<string, any, any, any>;
|
|
68
|
+
export type { QueryParams };
|
|
69
|
+
//# sourceMappingURL=endpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.d.ts","sourceRoot":"","sources":["../../src/core/endpoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declares an endpoint. Curried so the result/body/query types are explicit while the path literal is
|
|
3
|
+
* inferred: `defineEndpoint<Template, TemplateInput>()({ service, method: 'POST', path: '/v1/x/{id}', auth })`.
|
|
4
|
+
*/
|
|
5
|
+
export const defineEndpoint = () => (definition) => definition;
|
|
6
|
+
//# sourceMappingURL=endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../../src/core/endpoint.ts"],"names":[],"mappings":"AA2BA;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GACzB,GAAmD,EAAE,CACrD,CAAyB,UAAgE,EAAuC,EAAE,CAChI,UAAU,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core-services is one codebase served on many hosts: every module's routes are bound to a
|
|
3
|
+
* `%app.<name>_host%` parameter. A service key names one of those hosts; endpoints refer to the key,
|
|
4
|
+
* never to a URL, so each app maps keys to the environment it talks to.
|
|
5
|
+
*/
|
|
6
|
+
export declare const PRODUCTION_HOSTS: {
|
|
7
|
+
/** `app.authentication_host`: login, refresh, OTP, password reset. */
|
|
8
|
+
readonly authentication: "https://auth.smess.vn";
|
|
9
|
+
/** `app.campaign_api_host`: the smeup.email campaign API (`/v1/campaigns/*`). */
|
|
10
|
+
readonly campaignApi: "https://api.smess.vn";
|
|
11
|
+
/** `app.smeup_file_host`: file uploads (`/v1/smeup-files/*`). */
|
|
12
|
+
readonly smeupFile: "https://api.smess.vn";
|
|
13
|
+
/** `app.sso_host`: company single sign-on (`/v1/sso/*`). */
|
|
14
|
+
readonly sso: "https://sso.smess.vn";
|
|
15
|
+
/** `app.danara_host`: the Danara rentals API. */
|
|
16
|
+
readonly danara: "https://api.danara.vn";
|
|
17
|
+
/** `app.mobile_host`: the SMEUp mobile BFF. */
|
|
18
|
+
readonly mobile: "https://mobile.smess.vn";
|
|
19
|
+
/** `app.public_api_host`: the API-key public API (`/v1/public/*`). */
|
|
20
|
+
readonly publicApi: "https://open.smess.vn";
|
|
21
|
+
};
|
|
22
|
+
export type ServiceKey = keyof typeof PRODUCTION_HOSTS;
|
|
23
|
+
/** Base URL per service. A value may carry a path prefix (`https://proxy.example/api`); no trailing slash needed. */
|
|
24
|
+
export type HostMap = Readonly<Partial<Record<ServiceKey, string>>>;
|
|
25
|
+
//# sourceMappingURL=hosts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosts.d.ts","sourceRoot":"","sources":["../../src/core/hosts.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;IAC3B,sEAAsE;;IAEtE,iFAAiF;;IAEjF,iEAAiE;;IAEjE,4DAA4D;;IAE5D,iDAAiD;;IAEjD,+CAA+C;;IAE/C,sEAAsE;;CAE9D,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,gBAAgB,CAAC;AAEvD,qHAAqH;AACrH,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core-services is one codebase served on many hosts: every module's routes are bound to a
|
|
3
|
+
* `%app.<name>_host%` parameter. A service key names one of those hosts; endpoints refer to the key,
|
|
4
|
+
* never to a URL, so each app maps keys to the environment it talks to.
|
|
5
|
+
*/
|
|
6
|
+
export const PRODUCTION_HOSTS = {
|
|
7
|
+
/** `app.authentication_host`: login, refresh, OTP, password reset. */
|
|
8
|
+
authentication: 'https://auth.smess.vn',
|
|
9
|
+
/** `app.campaign_api_host`: the smeup.email campaign API (`/v1/campaigns/*`). */
|
|
10
|
+
campaignApi: 'https://api.smess.vn',
|
|
11
|
+
/** `app.smeup_file_host`: file uploads (`/v1/smeup-files/*`). */
|
|
12
|
+
smeupFile: 'https://api.smess.vn',
|
|
13
|
+
/** `app.sso_host`: company single sign-on (`/v1/sso/*`). */
|
|
14
|
+
sso: 'https://sso.smess.vn',
|
|
15
|
+
/** `app.danara_host`: the Danara rentals API. */
|
|
16
|
+
danara: 'https://api.danara.vn',
|
|
17
|
+
/** `app.mobile_host`: the SMEUp mobile BFF. */
|
|
18
|
+
mobile: 'https://mobile.smess.vn',
|
|
19
|
+
/** `app.public_api_host`: the API-key public API (`/v1/public/*`). */
|
|
20
|
+
publicApi: 'https://open.smess.vn',
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=hosts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosts.js","sourceRoot":"","sources":["../../src/core/hosts.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,sEAAsE;IACtE,cAAc,EAAE,uBAAuB;IACvC,iFAAiF;IACjF,WAAW,EAAE,sBAAsB;IACnC,iEAAiE;IACjE,SAAS,EAAE,sBAAsB;IACjC,4DAA4D;IAC5D,GAAG,EAAE,sBAAsB;IAC3B,iDAAiD;IACjD,MAAM,EAAE,uBAAuB;IAC/B,+CAA+C;IAC/C,MAAM,EAAE,yBAAyB;IACjC,sEAAsE;IACtE,SAAS,EAAE,uBAAuB;CAC1B,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List envelopes are returned exactly as the server sends them: they carry the pagination state.
|
|
3
|
+
* Single objects wrapped in `{"data": …}` are unwrapped by the modules.
|
|
4
|
+
*/
|
|
5
|
+
/** Stripe-style list (`CampaignListGetDto` and the other new-style modules). */
|
|
6
|
+
export interface ApiList<T> {
|
|
7
|
+
readonly object: 'list';
|
|
8
|
+
readonly data: T[];
|
|
9
|
+
readonly has_more: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Total matching rows where the handler counts them (e.g. audience contacts); many handlers set it to
|
|
12
|
+
* `data.length` because they return everything.
|
|
13
|
+
*/
|
|
14
|
+
readonly total_count: number;
|
|
15
|
+
}
|
|
16
|
+
/** Page-number envelope (Danara listings and sales). */
|
|
17
|
+
export interface PagedList<T> {
|
|
18
|
+
readonly data: T[];
|
|
19
|
+
readonly meta: {
|
|
20
|
+
readonly page: number;
|
|
21
|
+
readonly limit: number;
|
|
22
|
+
readonly total: number;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Walks a cursor-paginated (`limit` + `starting_after`) list item by item.
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* for await (const r of paginate((after) => email.campaigns.recipients(id, { starting_after: after }), (r) => r.id)) { … }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function paginate<T, C extends string | number>(fetchPage: (startingAfter: C | undefined) => Promise<ApiList<T>>, cursorOf: (item: T) => C): AsyncGenerator<T, void, undefined>;
|
|
33
|
+
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../src/core/pagination.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,gFAAgF;AAChF,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,wDAAwD;AACxD,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1F;AAED;;;;;;GAMG;AACH,wBAAuB,QAAQ,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAC1D,SAAS,EAAE,CAAC,aAAa,EAAE,CAAC,GAAG,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAChE,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GACvB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CASpC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List envelopes are returned exactly as the server sends them: they carry the pagination state.
|
|
3
|
+
* Single objects wrapped in `{"data": …}` are unwrapped by the modules.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Walks a cursor-paginated (`limit` + `starting_after`) list item by item.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* for await (const r of paginate((after) => email.campaigns.recipients(id, { starting_after: after }), (r) => r.id)) { … }
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export async function* paginate(fetchPage, cursorOf) {
|
|
13
|
+
let cursor;
|
|
14
|
+
for (;;) {
|
|
15
|
+
const page = await fetchPage(cursor);
|
|
16
|
+
yield* page.data;
|
|
17
|
+
const last = page.data[page.data.length - 1];
|
|
18
|
+
if (!page.has_more || last === undefined)
|
|
19
|
+
return;
|
|
20
|
+
cursor = cursorOf(last);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/core/pagination.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoBH;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,QAAQ,CAC7B,SAAgE,EAChE,QAAwB;IAExB,IAAI,MAAqB,CAAC;IAC1B,SAAS,CAAC;QACR,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;QACrC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACjB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO;QACjD,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ServiceKey } from './hosts.js';
|
|
2
|
+
import type { HttpResponse, TransportRequest } from './transport.js';
|
|
3
|
+
import type { AuthMode, HttpMethod } from './types.js';
|
|
4
|
+
/** The endpoint a request belongs to, as middleware sees it. */
|
|
5
|
+
export interface EndpointInfo {
|
|
6
|
+
readonly service: ServiceKey | undefined;
|
|
7
|
+
readonly method: HttpMethod;
|
|
8
|
+
/** The path template (`/v1/campaigns/email/templates/{id}`), useful for logging and metrics. */
|
|
9
|
+
readonly path: string;
|
|
10
|
+
readonly auth: AuthMode;
|
|
11
|
+
}
|
|
12
|
+
export interface RequestContext {
|
|
13
|
+
readonly endpoint: EndpointInfo;
|
|
14
|
+
/** Mutable: middleware may change headers, URL, timeout before calling `next()`. */
|
|
15
|
+
readonly request: TransportRequest;
|
|
16
|
+
/** Free-form storage shared by middleware for one call. */
|
|
17
|
+
readonly meta: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Koa-style middleware. Call `next()` to continue (more than once to retry), or return a response to
|
|
21
|
+
* short-circuit. Throw a `SmessApiError` to fail the call.
|
|
22
|
+
*/
|
|
23
|
+
export type Middleware = (context: RequestContext, next: () => Promise<HttpResponse>) => Promise<HttpResponse>;
|
|
24
|
+
export declare function composeMiddleware(middleware: readonly Middleware[], terminal: (context: RequestContext) => Promise<HttpResponse>): (context: RequestContext) => Promise<HttpResponse>;
|
|
25
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEvD,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,gGAAgG;IAChG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,oFAAoF;IACpF,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAE/G,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,SAAS,UAAU,EAAE,EACjC,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,YAAY,CAAC,GAC3D,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,YAAY,CAAC,CASpD"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function composeMiddleware(middleware, terminal) {
|
|
2
|
+
return (context) => {
|
|
3
|
+
const dispatch = (index) => {
|
|
4
|
+
const current = middleware[index];
|
|
5
|
+
if (!current)
|
|
6
|
+
return terminal(context);
|
|
7
|
+
return current(context, () => dispatch(index + 1));
|
|
8
|
+
};
|
|
9
|
+
return dispatch(0);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"AA2BA,MAAM,UAAU,iBAAiB,CAC/B,UAAiC,EACjC,QAA4D;IAE5D,OAAO,CAAC,OAAO,EAAE,EAAE;QACjB,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAyB,EAAE;YACxD,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YAClC,IAAI,CAAC,OAAO;gBAAE,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC;YACvC,OAAO,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;QACrD,CAAC,CAAC;QACF,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Middleware } from './pipeline.js';
|
|
2
|
+
import type { HttpMethod } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Opt-in retries for transient failures. Off by default: core-services runs on a small VPS, and blind
|
|
5
|
+
* retries add load exactly when it is struggling.
|
|
6
|
+
*/
|
|
7
|
+
export interface RetryOptions {
|
|
8
|
+
/** Extra attempts after the first. */
|
|
9
|
+
retries: number;
|
|
10
|
+
/** Default `['GET']`. Only add methods whose endpoints are idempotent. */
|
|
11
|
+
methods?: readonly HttpMethod[];
|
|
12
|
+
/** Default 300 ms, doubled each attempt, with jitter. */
|
|
13
|
+
baseDelayMs?: number;
|
|
14
|
+
/** Default 5000 ms. A longer `Retry-After` is not waited for: the error is returned instead. */
|
|
15
|
+
maxDelayMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function createRetryMiddleware(options: RetryOptions): Middleware;
|
|
18
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/core/retry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAChC,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAmBD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,YAAY,GAAG,UAAU,CAyBvE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { SmessApiError, parseRetryAfter } from '../errors/smess-api-error.js';
|
|
2
|
+
const RETRY_STATUSES = new Set([429, 502, 503, 504]);
|
|
3
|
+
function sleep(ms, signal) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
if (signal?.aborted)
|
|
6
|
+
return reject(new SmessApiError({ kind: 'aborted', cause: signal.reason }));
|
|
7
|
+
const timer = setTimeout(() => {
|
|
8
|
+
signal?.removeEventListener('abort', onAbort);
|
|
9
|
+
resolve();
|
|
10
|
+
}, ms);
|
|
11
|
+
const onAbort = () => {
|
|
12
|
+
clearTimeout(timer);
|
|
13
|
+
reject(new SmessApiError({ kind: 'aborted', cause: signal?.reason }));
|
|
14
|
+
};
|
|
15
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
export function createRetryMiddleware(options) {
|
|
19
|
+
const methods = new Set(options.methods ?? ['GET']);
|
|
20
|
+
const base = options.baseDelayMs ?? 300;
|
|
21
|
+
const max = options.maxDelayMs ?? 5000;
|
|
22
|
+
return async (context, next) => {
|
|
23
|
+
const { request } = context;
|
|
24
|
+
if (options.retries <= 0 || !methods.has(request.method) || !request.replayable)
|
|
25
|
+
return next();
|
|
26
|
+
for (let attempt = 0;; attempt++) {
|
|
27
|
+
const backoff = Math.min(max, base * 2 ** attempt) * (0.5 + Math.random() / 2);
|
|
28
|
+
try {
|
|
29
|
+
const response = await next();
|
|
30
|
+
if (attempt >= options.retries || !RETRY_STATUSES.has(response.status))
|
|
31
|
+
return response;
|
|
32
|
+
const retryAfter = parseRetryAfter(response.headers.get('Retry-After'));
|
|
33
|
+
const delay = retryAfter === undefined ? backoff : retryAfter * 1000;
|
|
34
|
+
if (delay > max)
|
|
35
|
+
return response;
|
|
36
|
+
await sleep(delay, request.signal);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const transient = SmessApiError.is(error) && (error.kind === 'network' || error.kind === 'timeout');
|
|
40
|
+
if (!transient || attempt >= options.retries)
|
|
41
|
+
throw error;
|
|
42
|
+
await sleep(backoff, request.signal);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/core/retry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { FetchFunction, FetchOptions, HttpMethod, ResponseType } from './types.js';
|
|
2
|
+
/** One HTTP exchange, ready to send. Middleware may change any field before calling `next()`. */
|
|
3
|
+
export interface TransportRequest {
|
|
4
|
+
method: HttpMethod;
|
|
5
|
+
url: string;
|
|
6
|
+
headers: Headers;
|
|
7
|
+
body?: BodyInit;
|
|
8
|
+
/** False when the body is a one-shot stream: retries are then skipped. */
|
|
9
|
+
replayable: boolean;
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
/** 0 or undefined disables the timeout. */
|
|
12
|
+
timeoutMs?: number;
|
|
13
|
+
responseType: ResponseType;
|
|
14
|
+
fetchOptions?: FetchOptions;
|
|
15
|
+
}
|
|
16
|
+
/** A response with its body already read (any status; errors are decided by the client layer). */
|
|
17
|
+
export interface HttpResponse {
|
|
18
|
+
readonly status: number;
|
|
19
|
+
readonly ok: boolean;
|
|
20
|
+
readonly headers: Headers;
|
|
21
|
+
readonly url: string;
|
|
22
|
+
/** Parsed JSON, raw text (when not JSON), a Blob (`responseType: 'blob'` on 2xx), or undefined (empty body). */
|
|
23
|
+
readonly data: unknown;
|
|
24
|
+
/** True when `responseType` is `json` but the body was not valid JSON (`data` then holds the text). */
|
|
25
|
+
readonly unparsable: boolean;
|
|
26
|
+
}
|
|
27
|
+
export type Transport = (request: TransportRequest) => Promise<HttpResponse>;
|
|
28
|
+
/** The default transport, on the platform `fetch` (browsers, Node 20+, Next.js server and edge, React Native). */
|
|
29
|
+
export declare function createFetchTransport(fetchImpl?: FetchFunction): Transport;
|
|
30
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/core/transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAExF,iGAAiG;AACjG,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,0EAA0E;IAC1E,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,kGAAkG;AAClG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,gHAAgH;IAChH,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,uGAAuG;IACvG,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAoC7E,kHAAkH;AAClH,wBAAgB,oBAAoB,CAAC,SAAS,CAAC,EAAE,aAAa,GAAG,SAAS,CA2BzE"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { SmessApiError } from '../errors/smess-api-error.js';
|
|
2
|
+
const TIMEOUT = Symbol('smess-timeout');
|
|
3
|
+
function linkSignals(signal, timeoutMs) {
|
|
4
|
+
const controller = new AbortController();
|
|
5
|
+
let timer;
|
|
6
|
+
const onAbort = () => controller.abort(signal?.reason);
|
|
7
|
+
if (signal?.aborted)
|
|
8
|
+
controller.abort(signal.reason);
|
|
9
|
+
else
|
|
10
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
11
|
+
if (timeoutMs && timeoutMs > 0 && !controller.signal.aborted) {
|
|
12
|
+
timer = setTimeout(() => controller.abort(TIMEOUT), timeoutMs);
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
signal: controller.signal,
|
|
16
|
+
timedOut: () => controller.signal.aborted && controller.signal.reason === TIMEOUT,
|
|
17
|
+
cleanup: () => {
|
|
18
|
+
if (timer !== undefined)
|
|
19
|
+
clearTimeout(timer);
|
|
20
|
+
signal?.removeEventListener('abort', onAbort);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async function readBody(response, responseType) {
|
|
25
|
+
if (response.ok && responseType === 'blob')
|
|
26
|
+
return { data: await response.blob(), unparsable: false };
|
|
27
|
+
const raw = await response.text();
|
|
28
|
+
if (responseType === 'text' && response.ok)
|
|
29
|
+
return { data: raw, unparsable: false };
|
|
30
|
+
if (raw.trim() === '')
|
|
31
|
+
return { data: undefined, unparsable: false };
|
|
32
|
+
// Parse whatever the Content-Type says: some core subscribers send JSON without `application/json`.
|
|
33
|
+
try {
|
|
34
|
+
return { data: JSON.parse(raw), unparsable: false };
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return { data: raw, unparsable: true };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** The default transport, on the platform `fetch` (browsers, Node 20+, Next.js server and edge, React Native). */
|
|
41
|
+
export function createFetchTransport(fetchImpl) {
|
|
42
|
+
return async (request) => {
|
|
43
|
+
// Resolve at call time and call unbound-safe: `window.fetch` throws "Illegal invocation" when detached.
|
|
44
|
+
const doFetch = fetchImpl ?? ((input, init) => globalThis.fetch(input, init));
|
|
45
|
+
const link = linkSignals(request.signal, request.timeoutMs);
|
|
46
|
+
const info = { method: request.method, url: request.url };
|
|
47
|
+
try {
|
|
48
|
+
const response = await doFetch(request.url, {
|
|
49
|
+
...request.fetchOptions,
|
|
50
|
+
method: request.method,
|
|
51
|
+
headers: request.headers,
|
|
52
|
+
body: request.body ?? null,
|
|
53
|
+
signal: link.signal,
|
|
54
|
+
});
|
|
55
|
+
const { data, unparsable } = await readBody(response, request.responseType);
|
|
56
|
+
return { status: response.status, ok: response.ok, headers: response.headers, url: response.url || request.url, data, unparsable };
|
|
57
|
+
}
|
|
58
|
+
catch (cause) {
|
|
59
|
+
if (SmessApiError.is(cause))
|
|
60
|
+
throw cause;
|
|
61
|
+
if (link.timedOut()) {
|
|
62
|
+
throw new SmessApiError({ kind: 'timeout', message: `Request timed out after ${request.timeoutMs} ms.`, request: info, cause });
|
|
63
|
+
}
|
|
64
|
+
if (link.signal.aborted)
|
|
65
|
+
throw new SmessApiError({ kind: 'aborted', request: info, cause });
|
|
66
|
+
throw new SmessApiError({ kind: 'network', request: info, cause });
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
link.cleanup();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=transport.js.map
|