@ssubedir/open-spanner 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/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # Open Spanner TypeScript SDK
2
+
3
+ Small TypeScript/JavaScript client stub for Open Spanner.
4
+
5
+ ```ts
6
+ import { OpenSpannerClient } from "@ssubedir/open-spanner";
7
+
8
+ const client = new OpenSpannerClient({
9
+ baseUrl: "http://localhost:18081",
10
+ });
11
+
12
+ await client.createUsage({
13
+ meter: "api_requests",
14
+ subject: "org_123",
15
+ quantity: 1,
16
+ });
17
+ ```
18
+
19
+ Types are generated from `../../docs/sdk-openapi.json` with `openapi-typescript`. The handwritten code is only a small `fetch` wrapper around those generated OpenAPI types.
@@ -0,0 +1,41 @@
1
+ import type { components, paths } from "./schema.js";
2
+ export interface OpenSpannerClientOptions {
3
+ baseUrl: string;
4
+ fetch?: typeof fetch;
5
+ headers?: HeadersInit;
6
+ }
7
+ export type ErrorBody = components["schemas"]["ErrorBody"];
8
+ export type ErrorResponse = components["schemas"]["ErrorResponse"];
9
+ export type Meter = components["schemas"]["Meter"];
10
+ export type MeterCreateRequest = components["schemas"]["MeterCreateRequest"];
11
+ export type MeterUpdateRequest = components["schemas"]["MeterUpdateRequest"];
12
+ export type MeterListResponse = components["schemas"]["MeterListResponse"];
13
+ export type UsageCreateRequest = components["schemas"]["UsageCreateRequest"];
14
+ export type UsageEvent = components["schemas"]["UsageEvent"];
15
+ export type UsageBulkResult = components["schemas"]["UsageBulkResult"];
16
+ export type UsageBucket = components["schemas"]["UsageBucket"];
17
+ export type UsageBucketListResponse = paths["/v1/usages"]["get"]["responses"]["200"]["content"]["application/json"];
18
+ export type ListMetersParams = NonNullable<paths["/v1/meters"]["get"]["parameters"]["query"]>;
19
+ export type ListUsageBucketsParams = NonNullable<paths["/v1/usages"]["get"]["parameters"]["query"]>;
20
+ export declare class OpenSpannerError extends Error {
21
+ readonly status: number;
22
+ readonly body: unknown;
23
+ constructor(status: number, body: unknown);
24
+ }
25
+ export declare class OpenSpannerClient {
26
+ private readonly baseUrl;
27
+ private readonly fetchFn;
28
+ private readonly headers?;
29
+ constructor(options: OpenSpannerClientOptions);
30
+ health(): Promise<void>;
31
+ createMeter(input: MeterCreateRequest): Promise<Meter>;
32
+ listMeters(params?: ListMetersParams): Promise<MeterListResponse>;
33
+ getMeter(name: string): Promise<Meter>;
34
+ updateMeter(name: string, input: MeterUpdateRequest): Promise<Meter>;
35
+ deleteMeter(name: string): Promise<void>;
36
+ createUsage(input: UsageCreateRequest): Promise<UsageEvent>;
37
+ createUsageBulk(input: UsageCreateRequest[]): Promise<UsageBulkResult>;
38
+ listUsageBuckets(params: ListUsageBucketsParams): Promise<UsageBucketListResponse>;
39
+ private request;
40
+ }
41
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,86 @@
1
+ export class OpenSpannerError extends Error {
2
+ status;
3
+ body;
4
+ constructor(status, body) {
5
+ super(`Open Spanner request failed with status ${status}`);
6
+ this.name = "OpenSpannerError";
7
+ this.status = status;
8
+ this.body = body;
9
+ }
10
+ }
11
+ export class OpenSpannerClient {
12
+ baseUrl;
13
+ fetchFn;
14
+ headers;
15
+ constructor(options) {
16
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
17
+ this.fetchFn = options.fetch ?? fetch;
18
+ this.headers = options.headers;
19
+ }
20
+ health() {
21
+ return this.request("GET", "/health");
22
+ }
23
+ createMeter(input) {
24
+ return this.request("POST", "/v1/meters", input);
25
+ }
26
+ listMeters(params = {}) {
27
+ return this.request("GET", `/v1/meters${toQuery(params)}`);
28
+ }
29
+ getMeter(name) {
30
+ return this.request("GET", `/v1/meters/${encodeURIComponent(name)}`);
31
+ }
32
+ updateMeter(name, input) {
33
+ return this.request("PUT", `/v1/meters/${encodeURIComponent(name)}`, input);
34
+ }
35
+ deleteMeter(name) {
36
+ return this.request("DELETE", `/v1/meters/${encodeURIComponent(name)}`);
37
+ }
38
+ createUsage(input) {
39
+ return this.request("POST", "/v1/usages", input);
40
+ }
41
+ createUsageBulk(input) {
42
+ return this.request("POST", "/v1/usages/bulk", input);
43
+ }
44
+ listUsageBuckets(params) {
45
+ return this.request("GET", `/v1/usages${toQuery(params)}`);
46
+ }
47
+ async request(method, path, body) {
48
+ const response = await this.fetchFn(`${this.baseUrl}${path}`, {
49
+ body: body === undefined ? undefined : JSON.stringify(body),
50
+ headers: {
51
+ ...this.headers,
52
+ ...(body === undefined ? {} : { "Content-Type": "application/json" }),
53
+ },
54
+ method,
55
+ });
56
+ if (!response.ok) {
57
+ throw new OpenSpannerError(response.status, await readBody(response));
58
+ }
59
+ if (response.status === 204) {
60
+ return undefined;
61
+ }
62
+ return (await response.json());
63
+ }
64
+ }
65
+ function toQuery(params) {
66
+ const query = new URLSearchParams();
67
+ for (const [key, value] of Object.entries(params)) {
68
+ if (typeof value === "string" && value !== "") {
69
+ query.set(key, value);
70
+ }
71
+ }
72
+ const encoded = query.toString();
73
+ return encoded ? `?${encoded}` : "";
74
+ }
75
+ async function readBody(response) {
76
+ const text = await response.text();
77
+ if (!text) {
78
+ return undefined;
79
+ }
80
+ try {
81
+ return JSON.parse(text);
82
+ }
83
+ catch {
84
+ return text;
85
+ }
86
+ }