@legalize-dev/sdk 0.1.0 → 0.2.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 +21 -0
- package/README.md +25 -0
- package/dist/index.cjs +119 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -2
- package/dist/index.d.ts +77 -2
- package/dist/index.js +119 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -704,6 +704,47 @@ interface RequestOptions {
|
|
|
704
704
|
*/
|
|
705
705
|
idempotencyKey?: string;
|
|
706
706
|
}
|
|
707
|
+
interface RequestRawOptions extends Omit<RequestOptions, "json"> {
|
|
708
|
+
/**
|
|
709
|
+
* The wire format to negotiate via the `Accept` header. `"xml"` (the
|
|
710
|
+
* default) requests `application/xml`, `"json"` requests
|
|
711
|
+
* `application/json`, and any other value is sent verbatim as the
|
|
712
|
+
* media type (so `format: "text/xml"` works too). Empty falls back to
|
|
713
|
+
* XML.
|
|
714
|
+
*/
|
|
715
|
+
format?: string;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* A raw, non-JSON-decoded API response.
|
|
719
|
+
*
|
|
720
|
+
* Returned by {@link Legalize.requestRaw} for content negotiation — when
|
|
721
|
+
* you want the body in a specific wire format (e.g. XML) instead of the
|
|
722
|
+
* typed JSON model the resource methods return. The SDK has zero runtime
|
|
723
|
+
* dependencies and ships no XML parser: parse `.text` (or `.content`)
|
|
724
|
+
* with your own library (e.g. `fast-xml-parser`, `@xmldom/xmldom`).
|
|
725
|
+
*/
|
|
726
|
+
interface RawResponse {
|
|
727
|
+
/** HTTP status of the response. */
|
|
728
|
+
statusCode: number;
|
|
729
|
+
/** Raw response body as bytes. */
|
|
730
|
+
content: Uint8Array;
|
|
731
|
+
/** The body decoded to a string (server charset, default UTF-8). */
|
|
732
|
+
text: string;
|
|
733
|
+
/** The `Content-Type` header value (e.g. `application/xml; charset=utf-8`). */
|
|
734
|
+
contentType: string;
|
|
735
|
+
/** The response headers as a plain, lower-cased mapping. */
|
|
736
|
+
headers: Record<string, string>;
|
|
737
|
+
/** Parse the body as JSON (handy when `format: "json"`). */
|
|
738
|
+
json(): unknown;
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Map a `format` shorthand to an Accept media type.
|
|
742
|
+
*
|
|
743
|
+
* `"xml"` → `application/xml`, `"json"` → `application/json`. Any other
|
|
744
|
+
* value is treated as an explicit media type and sent as-is (so
|
|
745
|
+
* `format: "text/xml"` works too). Empty falls back to XML.
|
|
746
|
+
*/
|
|
747
|
+
declare function formatToAccept(format: string | undefined): string;
|
|
707
748
|
/**
|
|
708
749
|
* Synchronous-API, promise-based client for the Legalize API.
|
|
709
750
|
*
|
|
@@ -746,11 +787,45 @@ declare class Legalize {
|
|
|
746
787
|
* failure.
|
|
747
788
|
*/
|
|
748
789
|
request<T = unknown>(method: string, path: string, options?: RequestOptions): Promise<T>;
|
|
790
|
+
/**
|
|
791
|
+
* Execute a request and return the raw, non-JSON-decoded body.
|
|
792
|
+
*
|
|
793
|
+
* The escape hatch for content negotiation: the typed resource methods
|
|
794
|
+
* always return JSON models, but `requestRaw` lets you fetch any
|
|
795
|
+
* endpoint in another wire format. `format` controls the `Accept`
|
|
796
|
+
* header — `"xml"` (the default) requests `application/xml`, `"json"`
|
|
797
|
+
* requests `application/json`, and any other value is sent verbatim as
|
|
798
|
+
* the media type.
|
|
799
|
+
*
|
|
800
|
+
* The SDK has zero runtime deps and ships no XML parser — parse the
|
|
801
|
+
* returned `.text` (or `.content`) with your own library.
|
|
802
|
+
*
|
|
803
|
+
* Example:
|
|
804
|
+
*
|
|
805
|
+
* const res = await client.requestRaw("GET", "/api/v1/es/laws/BOE-A-1978-31229");
|
|
806
|
+
* res.contentType; // "application/xml; charset=utf-8"
|
|
807
|
+
* const xmlText = res.text; // already application/xml
|
|
808
|
+
*
|
|
809
|
+
* Throws the same APIError subclasses as {@link request} on a non-2xx
|
|
810
|
+
* response; the error body is in whatever format you negotiated.
|
|
811
|
+
*/
|
|
812
|
+
requestRaw(method: string, path: string, options?: RequestRawOptions): Promise<RawResponse>;
|
|
749
813
|
/** Release any resources held by the client. Kept for API symmetry. */
|
|
750
814
|
close(): Promise<void>;
|
|
751
815
|
/** TS 5.2+ `using` / `await using` support. */
|
|
752
816
|
[Symbol.asyncDispose](): Promise<void>;
|
|
753
817
|
private buildUrl;
|
|
818
|
+
/**
|
|
819
|
+
* Run the retry loop and return the raw 2xx `Response`.
|
|
820
|
+
*
|
|
821
|
+
* Shared by {@link request} (which then JSON-parses) and
|
|
822
|
+
* {@link requestRaw} (which builds a `RawResponse`). Applies the retry
|
|
823
|
+
* policy on transport errors and retryable statuses, populates
|
|
824
|
+
* `lastResponse` on the failing response before raising, and throws the
|
|
825
|
+
* typed `APIError` hierarchy on a final non-2xx. The returned response
|
|
826
|
+
* body is left unread for the caller to consume.
|
|
827
|
+
*/
|
|
828
|
+
private sendWithRetry;
|
|
754
829
|
private sendOnce;
|
|
755
830
|
}
|
|
756
831
|
/**
|
|
@@ -1007,6 +1082,6 @@ declare class Webhook {
|
|
|
1007
1082
|
* output without extra wiring, so we duplicate the literal here. The test
|
|
1008
1083
|
* suite asserts they match so drift is caught immediately.
|
|
1009
1084
|
*/
|
|
1010
|
-
declare const SDK_VERSION = "0.
|
|
1085
|
+
declare const SDK_VERSION = "0.2.0";
|
|
1011
1086
|
|
|
1012
|
-
export { APIConnectionError, APIError, type APIErrorOptions, APITimeoutError, type ApiValidationError, AuthenticationError, type Commit, type CommitsResponse, Countries, type CountryInfo, DEFAULT_API_VERSION, DEFAULT_BACKOFF_FACTOR, DEFAULT_BASE_URL, DEFAULT_INITIAL_DELAY, DEFAULT_MAX_DELAY, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, DEFAULT_TOLERANCE_SECONDS, type FetchImpl, ForbiddenError, type HTTPValidationError, IDEMPOTENT_METHODS, InvalidRequestError, type JurisdictionInfo, Jurisdictions, KEY_PREFIX, type LawAtCommitResponse, type LawDetail, type LawFilterOptions, type LawIterOptions, type LawListOptions, type LawMeta, type LawSearchOptions, type LawSearchResult, type LawSort, LawTypes, Laws, Legalize, LegalizeError, type LegalizeOptions, NotFoundError, OffsetIterator, PAGE_MAX, PageIterator, type PaginatedLaws, RETRY_STATUSES, RateLimitError, type Reform, type ReformIterOptions, type ReformListOptions, Reforms, type ReformsResponse, type RequestOptions, RetryPolicy, type RetryPolicyOptions, SDK_VERSION, ServerError, ServiceUnavailableError, Stats, type StatsOptions, type StatsResponse, ValidationError, Webhook, type WebhookCreateOptions, type WebhookDeliveriesOptions, type WebhookDeliveriesPage, type WebhookDelivery, type WebhookDeliveryStatus, type WebhookEndpoint, type WebhookEndpointCreate, type WebhookEndpointUpdate, type WebhookEvent, type WebhookUpdateOptions, WebhookVerificationError, type WebhookVerificationReason, type WebhookVerifyOptions, Webhooks, buildQueryString, defaultUserAgent, parseRetryAfter, resolveApiKey, resolveApiVersion, resolveBaseUrl, sleep };
|
|
1087
|
+
export { APIConnectionError, APIError, type APIErrorOptions, APITimeoutError, type ApiValidationError, AuthenticationError, type Commit, type CommitsResponse, Countries, type CountryInfo, DEFAULT_API_VERSION, DEFAULT_BACKOFF_FACTOR, DEFAULT_BASE_URL, DEFAULT_INITIAL_DELAY, DEFAULT_MAX_DELAY, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, DEFAULT_TOLERANCE_SECONDS, type FetchImpl, ForbiddenError, type HTTPValidationError, IDEMPOTENT_METHODS, InvalidRequestError, type JurisdictionInfo, Jurisdictions, KEY_PREFIX, type LawAtCommitResponse, type LawDetail, type LawFilterOptions, type LawIterOptions, type LawListOptions, type LawMeta, type LawSearchOptions, type LawSearchResult, type LawSort, LawTypes, Laws, Legalize, LegalizeError, type LegalizeOptions, NotFoundError, OffsetIterator, PAGE_MAX, PageIterator, type PaginatedLaws, RETRY_STATUSES, RateLimitError, type RawResponse, type Reform, type ReformIterOptions, type ReformListOptions, Reforms, type ReformsResponse, type RequestOptions, type RequestRawOptions, RetryPolicy, type RetryPolicyOptions, SDK_VERSION, ServerError, ServiceUnavailableError, Stats, type StatsOptions, type StatsResponse, ValidationError, Webhook, type WebhookCreateOptions, type WebhookDeliveriesOptions, type WebhookDeliveriesPage, type WebhookDelivery, type WebhookDeliveryStatus, type WebhookEndpoint, type WebhookEndpointCreate, type WebhookEndpointUpdate, type WebhookEvent, type WebhookUpdateOptions, WebhookVerificationError, type WebhookVerificationReason, type WebhookVerifyOptions, Webhooks, buildQueryString, defaultUserAgent, formatToAccept, parseRetryAfter, resolveApiKey, resolveApiVersion, resolveBaseUrl, sleep };
|
package/dist/index.js
CHANGED
|
@@ -722,7 +722,7 @@ var Webhooks = class {
|
|
|
722
722
|
};
|
|
723
723
|
|
|
724
724
|
// src/version.ts
|
|
725
|
-
var SDK_VERSION = "0.
|
|
725
|
+
var SDK_VERSION = "0.2.0";
|
|
726
726
|
|
|
727
727
|
// src/client.ts
|
|
728
728
|
function defaultUserAgent() {
|
|
@@ -733,6 +733,22 @@ function stripTrailingSlashes(s) {
|
|
|
733
733
|
while (end > 0 && s.charCodeAt(end - 1) === 47) end--;
|
|
734
734
|
return s.slice(0, end);
|
|
735
735
|
}
|
|
736
|
+
var FORMAT_ALIASES = {
|
|
737
|
+
xml: "application/xml",
|
|
738
|
+
json: "application/json"
|
|
739
|
+
};
|
|
740
|
+
function formatToAccept(format) {
|
|
741
|
+
const key = (format ?? "").trim().toLowerCase();
|
|
742
|
+
if (!key) return "application/xml";
|
|
743
|
+
return FORMAT_ALIASES[key] ?? format;
|
|
744
|
+
}
|
|
745
|
+
function headersToRecord(headers) {
|
|
746
|
+
const out = {};
|
|
747
|
+
headers.forEach((value, key) => {
|
|
748
|
+
out[key] = value;
|
|
749
|
+
});
|
|
750
|
+
return out;
|
|
751
|
+
}
|
|
736
752
|
var Legalize = class {
|
|
737
753
|
countries;
|
|
738
754
|
jurisdictions;
|
|
@@ -779,19 +795,100 @@ var Legalize = class {
|
|
|
779
795
|
*/
|
|
780
796
|
async request(method, path, options = {}) {
|
|
781
797
|
const upperMethod = method.toUpperCase();
|
|
782
|
-
const url = this.buildUrl(path, options.params);
|
|
783
798
|
const headers = { ...this._headers };
|
|
784
799
|
if (options.extraHeaders) Object.assign(headers, options.extraHeaders);
|
|
785
800
|
if (options.idempotencyKey) headers["Idempotency-Key"] = options.idempotencyKey;
|
|
786
801
|
const hasJson = options.json !== void 0;
|
|
787
802
|
if (hasJson) headers["Content-Type"] = "application/json";
|
|
803
|
+
const response = await this.sendWithRetry(upperMethod, path, headers, options, hasJson);
|
|
804
|
+
this._lastResponse = response;
|
|
805
|
+
if (response.status === 204) return null;
|
|
806
|
+
const text = await response.text();
|
|
807
|
+
if (!text) return null;
|
|
808
|
+
try {
|
|
809
|
+
return JSON.parse(text);
|
|
810
|
+
} catch (err) {
|
|
811
|
+
throw new APIError({
|
|
812
|
+
message: "Server returned non-JSON body",
|
|
813
|
+
statusCode: response.status,
|
|
814
|
+
body: text,
|
|
815
|
+
response,
|
|
816
|
+
cause: err
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Execute a request and return the raw, non-JSON-decoded body.
|
|
822
|
+
*
|
|
823
|
+
* The escape hatch for content negotiation: the typed resource methods
|
|
824
|
+
* always return JSON models, but `requestRaw` lets you fetch any
|
|
825
|
+
* endpoint in another wire format. `format` controls the `Accept`
|
|
826
|
+
* header — `"xml"` (the default) requests `application/xml`, `"json"`
|
|
827
|
+
* requests `application/json`, and any other value is sent verbatim as
|
|
828
|
+
* the media type.
|
|
829
|
+
*
|
|
830
|
+
* The SDK has zero runtime deps and ships no XML parser — parse the
|
|
831
|
+
* returned `.text` (or `.content`) with your own library.
|
|
832
|
+
*
|
|
833
|
+
* Example:
|
|
834
|
+
*
|
|
835
|
+
* const res = await client.requestRaw("GET", "/api/v1/es/laws/BOE-A-1978-31229");
|
|
836
|
+
* res.contentType; // "application/xml; charset=utf-8"
|
|
837
|
+
* const xmlText = res.text; // already application/xml
|
|
838
|
+
*
|
|
839
|
+
* Throws the same APIError subclasses as {@link request} on a non-2xx
|
|
840
|
+
* response; the error body is in whatever format you negotiated.
|
|
841
|
+
*/
|
|
842
|
+
async requestRaw(method, path, options = {}) {
|
|
843
|
+
const upperMethod = method.toUpperCase();
|
|
844
|
+
const headers = { ...this._headers };
|
|
845
|
+
headers["Accept"] = formatToAccept(options.format);
|
|
846
|
+
if (options.extraHeaders) Object.assign(headers, options.extraHeaders);
|
|
847
|
+
if (options.idempotencyKey) headers["Idempotency-Key"] = options.idempotencyKey;
|
|
848
|
+
const response = await this.sendWithRetry(upperMethod, path, headers, options, false);
|
|
849
|
+
this._lastResponse = response;
|
|
850
|
+
return rawFromResponse(response);
|
|
851
|
+
}
|
|
852
|
+
/** Release any resources held by the client. Kept for API symmetry. */
|
|
853
|
+
async close() {
|
|
854
|
+
}
|
|
855
|
+
/** TS 5.2+ `using` / `await using` support. */
|
|
856
|
+
async [Symbol.asyncDispose]() {
|
|
857
|
+
await this.close();
|
|
858
|
+
}
|
|
859
|
+
// ---- internals --------------------------------------------------------
|
|
860
|
+
buildUrl(path, params) {
|
|
861
|
+
let base;
|
|
862
|
+
if (path.startsWith("http://") || path.startsWith("https://")) {
|
|
863
|
+
base = path;
|
|
864
|
+
} else {
|
|
865
|
+
const p = path.startsWith("/") ? path : `/${path}`;
|
|
866
|
+
base = this._baseUrl + p;
|
|
867
|
+
}
|
|
868
|
+
if (!params) return base;
|
|
869
|
+
const query = buildQueryString(params);
|
|
870
|
+
if (!query) return base;
|
|
871
|
+
return base.includes("?") ? `${base}&${query}` : `${base}?${query}`;
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Run the retry loop and return the raw 2xx `Response`.
|
|
875
|
+
*
|
|
876
|
+
* Shared by {@link request} (which then JSON-parses) and
|
|
877
|
+
* {@link requestRaw} (which builds a `RawResponse`). Applies the retry
|
|
878
|
+
* policy on transport errors and retryable statuses, populates
|
|
879
|
+
* `lastResponse` on the failing response before raising, and throws the
|
|
880
|
+
* typed `APIError` hierarchy on a final non-2xx. The returned response
|
|
881
|
+
* body is left unread for the caller to consume.
|
|
882
|
+
*/
|
|
883
|
+
async sendWithRetry(method, path, headers, options, hasJson) {
|
|
884
|
+
const url = this.buildUrl(path, options.params);
|
|
788
885
|
let attempt = 0;
|
|
789
886
|
while (true) {
|
|
790
887
|
let response;
|
|
791
888
|
try {
|
|
792
|
-
response = await this.sendOnce(url,
|
|
889
|
+
response = await this.sendOnce(url, method, headers, options, hasJson);
|
|
793
890
|
} catch (err) {
|
|
794
|
-
const shouldRetry2 = this._retry.shouldRetry(attempt, { method
|
|
891
|
+
const shouldRetry2 = this._retry.shouldRetry(attempt, { method });
|
|
795
892
|
if (!shouldRetry2) {
|
|
796
893
|
throw wrapTransportError(err);
|
|
797
894
|
}
|
|
@@ -801,25 +898,11 @@ var Legalize = class {
|
|
|
801
898
|
continue;
|
|
802
899
|
}
|
|
803
900
|
if (response.status >= 200 && response.status < 300) {
|
|
804
|
-
|
|
805
|
-
if (response.status === 204) return null;
|
|
806
|
-
const text = await response.text();
|
|
807
|
-
if (!text) return null;
|
|
808
|
-
try {
|
|
809
|
-
return JSON.parse(text);
|
|
810
|
-
} catch (err) {
|
|
811
|
-
throw new APIError({
|
|
812
|
-
message: "Server returned non-JSON body",
|
|
813
|
-
statusCode: response.status,
|
|
814
|
-
body: text,
|
|
815
|
-
response,
|
|
816
|
-
cause: err
|
|
817
|
-
});
|
|
818
|
-
}
|
|
901
|
+
return response;
|
|
819
902
|
}
|
|
820
903
|
const shouldRetry = this._retry.shouldRetry(attempt, {
|
|
821
904
|
status: response.status,
|
|
822
|
-
method
|
|
905
|
+
method
|
|
823
906
|
});
|
|
824
907
|
if (!shouldRetry) {
|
|
825
908
|
this._lastResponse = response;
|
|
@@ -835,27 +918,6 @@ var Legalize = class {
|
|
|
835
918
|
attempt += 1;
|
|
836
919
|
}
|
|
837
920
|
}
|
|
838
|
-
/** Release any resources held by the client. Kept for API symmetry. */
|
|
839
|
-
async close() {
|
|
840
|
-
}
|
|
841
|
-
/** TS 5.2+ `using` / `await using` support. */
|
|
842
|
-
async [Symbol.asyncDispose]() {
|
|
843
|
-
await this.close();
|
|
844
|
-
}
|
|
845
|
-
// ---- internals --------------------------------------------------------
|
|
846
|
-
buildUrl(path, params) {
|
|
847
|
-
let base;
|
|
848
|
-
if (path.startsWith("http://") || path.startsWith("https://")) {
|
|
849
|
-
base = path;
|
|
850
|
-
} else {
|
|
851
|
-
const p = path.startsWith("/") ? path : `/${path}`;
|
|
852
|
-
base = this._baseUrl + p;
|
|
853
|
-
}
|
|
854
|
-
if (!params) return base;
|
|
855
|
-
const query = buildQueryString(params);
|
|
856
|
-
if (!query) return base;
|
|
857
|
-
return base.includes("?") ? `${base}&${query}` : `${base}?${query}`;
|
|
858
|
-
}
|
|
859
921
|
async sendOnce(url, method, headers, options, hasJson) {
|
|
860
922
|
const controller = new AbortController();
|
|
861
923
|
const timeoutMs = this._timeout;
|
|
@@ -933,6 +995,21 @@ async function errorFromResponse(response) {
|
|
|
933
995
|
}
|
|
934
996
|
return APIError.fromResponse(response, text, data);
|
|
935
997
|
}
|
|
998
|
+
async function rawFromResponse(response) {
|
|
999
|
+
const buffer = await response.arrayBuffer();
|
|
1000
|
+
const content = new Uint8Array(buffer);
|
|
1001
|
+
const text = new TextDecoder().decode(content);
|
|
1002
|
+
return {
|
|
1003
|
+
statusCode: response.status,
|
|
1004
|
+
content,
|
|
1005
|
+
text,
|
|
1006
|
+
contentType: response.headers.get("content-type") ?? "",
|
|
1007
|
+
headers: headersToRecord(response.headers),
|
|
1008
|
+
json() {
|
|
1009
|
+
return JSON.parse(text);
|
|
1010
|
+
}
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
936
1013
|
function wrapTransportError(err) {
|
|
937
1014
|
if (err instanceof Error) {
|
|
938
1015
|
const isAbort = err.name === "AbortError" || err.code === "ABORT_ERR";
|
|
@@ -1058,6 +1135,6 @@ function webhookEventFromPayload(payload) {
|
|
|
1058
1135
|
};
|
|
1059
1136
|
}
|
|
1060
1137
|
|
|
1061
|
-
export { APIConnectionError, APIError, APITimeoutError, AuthenticationError, Countries, DEFAULT_API_VERSION, DEFAULT_BACKOFF_FACTOR, DEFAULT_BASE_URL, DEFAULT_INITIAL_DELAY, DEFAULT_MAX_DELAY, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, DEFAULT_TOLERANCE_SECONDS, ForbiddenError, IDEMPOTENT_METHODS, InvalidRequestError, Jurisdictions, KEY_PREFIX, LawTypes, Laws, Legalize, LegalizeError, NotFoundError, OffsetIterator, PAGE_MAX, PageIterator, RETRY_STATUSES, RateLimitError, Reforms, RetryPolicy, SDK_VERSION, ServerError, ServiceUnavailableError, Stats, ValidationError, Webhook, WebhookVerificationError, Webhooks, buildQueryString, defaultUserAgent, parseRetryAfter, resolveApiKey, resolveApiVersion, resolveBaseUrl, sleep };
|
|
1138
|
+
export { APIConnectionError, APIError, APITimeoutError, AuthenticationError, Countries, DEFAULT_API_VERSION, DEFAULT_BACKOFF_FACTOR, DEFAULT_BASE_URL, DEFAULT_INITIAL_DELAY, DEFAULT_MAX_DELAY, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, DEFAULT_TOLERANCE_SECONDS, ForbiddenError, IDEMPOTENT_METHODS, InvalidRequestError, Jurisdictions, KEY_PREFIX, LawTypes, Laws, Legalize, LegalizeError, NotFoundError, OffsetIterator, PAGE_MAX, PageIterator, RETRY_STATUSES, RateLimitError, Reforms, RetryPolicy, SDK_VERSION, ServerError, ServiceUnavailableError, Stats, ValidationError, Webhook, WebhookVerificationError, Webhooks, buildQueryString, defaultUserAgent, formatToAccept, parseRetryAfter, resolveApiKey, resolveApiVersion, resolveBaseUrl, sleep };
|
|
1062
1139
|
//# sourceMappingURL=index.js.map
|
|
1063
1140
|
//# sourceMappingURL=index.js.map
|