@centia-io/sdk 0.0.43 → 0.0.45

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.
@@ -5,1007 +5,1178 @@
5
5
  })(this, function(exports) {
6
6
 
7
7
  //#region src/util/jwt-decode.ts
8
- var InvalidTokenError = class extends Error {};
9
- InvalidTokenError.prototype.name = "InvalidTokenError";
10
- function b64DecodeUnicode(str) {
11
- return decodeURIComponent(atob(str).replace(/(.)/g, (m, p) => {
12
- let code = p.charCodeAt(0).toString(16).toUpperCase();
13
- if (code.length < 2) code = "0" + code;
14
- return "%" + code;
15
- }));
16
- }
17
- function base64UrlDecode(str) {
18
- let output = str.replace(/-/g, "+").replace(/_/g, "/");
19
- switch (output.length % 4) {
20
- case 0: break;
21
- case 2:
22
- output += "==";
23
- break;
24
- case 3:
25
- output += "=";
26
- break;
27
- default: throw new Error("base64 string is not of the correct length");
28
- }
29
- try {
30
- return b64DecodeUnicode(output);
31
- } catch (err) {
32
- return atob(output);
33
- }
34
- }
35
- function jwtDecode(token, options) {
36
- if (typeof token !== "string") throw new InvalidTokenError("Invalid token specified: must be a string");
37
- options ||= {};
38
- const pos = options.header === true ? 0 : 1;
39
- const part = token.split(".")[pos];
40
- if (typeof part !== "string") throw new InvalidTokenError(`Invalid token specified: missing part #${pos + 1}`);
41
- let decoded;
42
- try {
43
- decoded = base64UrlDecode(part);
44
- } catch (e) {
45
- throw new InvalidTokenError(`Invalid token specified: invalid base64 for part #${pos + 1} (${e.message})`);
8
+ var InvalidTokenError = class extends Error {};
9
+ InvalidTokenError.prototype.name = "InvalidTokenError";
10
+ function b64DecodeUnicode(str) {
11
+ return decodeURIComponent(atob(str).replace(/(.)/g, (m, p) => {
12
+ let code = p.charCodeAt(0).toString(16).toUpperCase();
13
+ if (code.length < 2) code = "0" + code;
14
+ return "%" + code;
15
+ }));
16
+ }
17
+ function base64UrlDecode(str) {
18
+ let output = str.replace(/-/g, "+").replace(/_/g, "/");
19
+ switch (output.length % 4) {
20
+ case 0: break;
21
+ case 2:
22
+ output += "==";
23
+ break;
24
+ case 3:
25
+ output += "=";
26
+ break;
27
+ default: throw new Error("base64 string is not of the correct length");
28
+ }
29
+ try {
30
+ return b64DecodeUnicode(output);
31
+ } catch (err) {
32
+ return atob(output);
33
+ }
46
34
  }
47
- try {
48
- return JSON.parse(decoded);
49
- } catch (e) {
50
- throw new InvalidTokenError(`Invalid token specified: invalid json for part #${pos + 1} (${e.message})`);
35
+ function jwtDecode(token, options) {
36
+ if (typeof token !== "string") throw new InvalidTokenError("Invalid token specified: must be a string");
37
+ options ||= {};
38
+ const pos = options.header === true ? 0 : 1;
39
+ const part = token.split(".")[pos];
40
+ if (typeof part !== "string") throw new InvalidTokenError(`Invalid token specified: missing part #${pos + 1}`);
41
+ let decoded;
42
+ try {
43
+ decoded = base64UrlDecode(part);
44
+ } catch (e) {
45
+ throw new InvalidTokenError(`Invalid token specified: invalid base64 for part #${pos + 1} (${e.message})`);
46
+ }
47
+ try {
48
+ return JSON.parse(decoded);
49
+ } catch (e) {
50
+ throw new InvalidTokenError(`Invalid token specified: invalid json for part #${pos + 1} (${e.message})`);
51
+ }
51
52
  }
52
- }
53
53
 
54
54
  //#endregion
55
55
  //#region src/util/storage.ts
56
- var MemoryStorage = class {
57
- constructor() {
58
- this.store = /* @__PURE__ */ new Map();
59
- }
60
- getItem(key) {
61
- return this.store.has(key) ? this.store.get(key) : null;
62
- }
63
- setItem(key, value) {
64
- this.store.set(key, String(value));
65
- }
66
- removeItem(key) {
67
- this.store.delete(key);
56
+ var MemoryStorage = class {
57
+ constructor() {
58
+ this.store = /* @__PURE__ */ new Map();
59
+ }
60
+ getItem(key) {
61
+ return this.store.has(key) ? this.store.get(key) : null;
62
+ }
63
+ setItem(key, value) {
64
+ this.store.set(key, String(value));
65
+ }
66
+ removeItem(key) {
67
+ this.store.delete(key);
68
+ }
69
+ };
70
+ let cached = null;
71
+ function getStorage() {
72
+ if (cached) return cached;
73
+ try {
74
+ const g$1 = typeof globalThis !== "undefined" ? globalThis : window;
75
+ if (g$1 && g$1.localStorage && typeof g$1.localStorage.getItem === "function") {
76
+ cached = g$1.localStorage;
77
+ return cached;
78
+ }
79
+ } catch (e) {}
80
+ const g = typeof globalThis !== "undefined" ? globalThis : {};
81
+ if (!g.__gc2_memory_storage) g.__gc2_memory_storage = new MemoryStorage();
82
+ cached = g.__gc2_memory_storage;
83
+ return cached;
68
84
  }
69
- };
70
- let cached = null;
71
- function getStorage() {
72
- if (cached) return cached;
73
- try {
74
- const g$1 = typeof globalThis !== "undefined" ? globalThis : window;
75
- if (g$1 && g$1.localStorage && typeof g$1.localStorage.getItem === "function") {
76
- cached = g$1.localStorage;
77
- return cached;
78
- }
79
- } catch (e) {}
80
- const g = typeof globalThis !== "undefined" ? globalThis : {};
81
- if (!g.__gc2_memory_storage) g.__gc2_memory_storage = new MemoryStorage();
82
- cached = g.__gc2_memory_storage;
83
- return cached;
84
- }
85
85
 
86
86
  //#endregion
87
87
  //#region src/util/utils.ts
88
- const generatePkceChallenge = async () => {
89
- const generateRandomString = () => {
90
- const array = new Uint32Array(28);
91
- crypto.getRandomValues(array);
92
- return Array.from(array, (dec) => ("0" + dec.toString(16)).substr(-2)).join("");
88
+ /**
89
+ * @author Martin Høgh <mh@mapcentia.com>
90
+ * @copyright 2013-2026 MapCentia ApS
91
+ * @license https://opensource.org/license/mit The MIT License
92
+ *
93
+ */
94
+ const generatePkceChallenge = async () => {
95
+ const generateRandomString = () => {
96
+ const array = new Uint32Array(28);
97
+ crypto.getRandomValues(array);
98
+ return Array.from(array, (dec) => ("0" + dec.toString(16)).substr(-2)).join("");
99
+ };
100
+ const sha256 = (plain) => {
101
+ const data = new TextEncoder().encode(plain);
102
+ return crypto.subtle.digest("SHA-256", data);
103
+ };
104
+ const base64urlEncode = (str) => {
105
+ return btoa(String.fromCharCode.apply(null, [...new Uint8Array(str)])).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
106
+ };
107
+ async function pkceChallengeFromVerifier(v) {
108
+ return base64urlEncode(await sha256(v));
109
+ }
110
+ const { state, codeVerifier } = {
111
+ state: generateRandomString(),
112
+ codeVerifier: generateRandomString()
113
+ };
114
+ return {
115
+ state,
116
+ codeVerifier,
117
+ codeChallenge: await pkceChallengeFromVerifier(codeVerifier)
118
+ };
93
119
  };
94
- const sha256 = (plain) => {
95
- const data = new TextEncoder().encode(plain);
96
- return crypto.subtle.digest("SHA-256", data);
120
+ const isTokenExpired = (token) => {
121
+ let isJwtExpired = false;
122
+ const { exp } = jwtDecode(token);
123
+ const currentTime = (/* @__PURE__ */ new Date()).getTime() / 1e3;
124
+ if (exp) {
125
+ if (currentTime > exp) isJwtExpired = true;
126
+ }
127
+ return isJwtExpired;
97
128
  };
98
- const base64urlEncode = (str) => {
99
- return btoa(String.fromCharCode.apply(null, [...new Uint8Array(str)])).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
129
+ const claims = (token) => {
130
+ return jwtDecode(token);
100
131
  };
101
- async function pkceChallengeFromVerifier(v) {
102
- return base64urlEncode(await sha256(v));
103
- }
104
- const { state, codeVerifier } = {
105
- state: generateRandomString(),
106
- codeVerifier: generateRandomString()
132
+ const isLogin = async (gc2) => {
133
+ const { accessToken, refreshToken } = getTokens();
134
+ if (!accessToken && !refreshToken) return false;
135
+ if (!accessToken || accessToken && isTokenExpired(accessToken)) {
136
+ if (refreshToken && isTokenExpired(refreshToken)) {
137
+ clearTokens();
138
+ clearOptions();
139
+ throw new Error("Refresh token has expired. Please login again.");
140
+ }
141
+ if (refreshToken) try {
142
+ const data = await gc2.getRefreshToken(refreshToken);
143
+ setTokens({
144
+ accessToken: data.access_token,
145
+ refreshToken,
146
+ idToken: data?.id_token
147
+ });
148
+ console.log("Access token refreshed");
149
+ } catch (e) {
150
+ throw new Error("Could not get refresh token.");
151
+ }
152
+ }
153
+ return true;
107
154
  };
108
- return {
109
- state,
110
- codeVerifier,
111
- codeChallenge: await pkceChallengeFromVerifier(codeVerifier)
155
+ const setTokens = (tokens) => {
156
+ getStorage().setItem("gc2_tokens", JSON.stringify({
157
+ "accessToken": tokens.accessToken,
158
+ "refreshToken": tokens.refreshToken,
159
+ "idToken": tokens?.idToken || ""
160
+ }));
112
161
  };
113
- };
114
- const isTokenExpired = (token) => {
115
- let isJwtExpired = false;
116
- const { exp } = jwtDecode(token);
117
- const currentTime = (/* @__PURE__ */ new Date()).getTime() / 1e3;
118
- if (exp) {
119
- if (currentTime > exp) isJwtExpired = true;
120
- }
121
- return isJwtExpired;
122
- };
123
- const claims = (token) => {
124
- return jwtDecode(token);
125
- };
126
- const isLogin = async (gc2) => {
127
- const { accessToken, refreshToken } = getTokens();
128
- if (!accessToken && !refreshToken) return false;
129
- if (!accessToken || accessToken && isTokenExpired(accessToken)) {
130
- if (refreshToken && isTokenExpired(refreshToken)) {
131
- clearTokens();
132
- clearOptions();
133
- throw new Error("Refresh token has expired. Please login again.");
134
- }
135
- if (refreshToken) try {
136
- const data = await gc2.getRefreshToken(refreshToken);
137
- setTokens({
138
- accessToken: data.access_token,
139
- refreshToken,
140
- idToken: data?.id_token
141
- });
142
- console.log("Access token refreshed");
143
- } catch (e) {
144
- throw new Error("Could not get refresh token.");
145
- }
146
- }
147
- return true;
148
- };
149
- const setTokens = (tokens) => {
150
- getStorage().setItem("gc2_tokens", JSON.stringify({
151
- "accessToken": tokens.accessToken,
152
- "refreshToken": tokens.refreshToken,
153
- "idToken": tokens?.idToken || ""
154
- }));
155
- };
156
- const getTokens = () => {
157
- const str = getStorage().getItem("gc2_tokens");
158
- const tokens = str ? JSON.parse(str) : {};
159
- return {
160
- accessToken: tokens?.accessToken || "",
161
- refreshToken: tokens?.refreshToken || "",
162
- idToken: tokens?.idToken || ""
162
+ const getTokens = () => {
163
+ const str = getStorage().getItem("gc2_tokens");
164
+ const tokens = str ? JSON.parse(str) : {};
165
+ return {
166
+ accessToken: tokens?.accessToken || "",
167
+ refreshToken: tokens?.refreshToken || "",
168
+ idToken: tokens?.idToken || ""
169
+ };
170
+ };
171
+ const setOptions = (options) => {
172
+ getStorage().setItem("gc2_options", JSON.stringify({
173
+ "clientId": options.clientId,
174
+ "host": options.host,
175
+ "redirectUri": options.redirectUri,
176
+ "clientSecret": options.clientSecret || null
177
+ }));
178
+ };
179
+ const getOptions = () => {
180
+ const str = getStorage().getItem("gc2_options");
181
+ const options = str ? JSON.parse(str) : {};
182
+ return {
183
+ clientId: options?.clientId || "",
184
+ host: options?.host || "",
185
+ redirectUri: options?.redirectUri || ""
186
+ };
163
187
  };
164
- };
165
- const setOptions = (options) => {
166
- getStorage().setItem("gc2_options", JSON.stringify({
167
- "clientId": options.clientId,
168
- "host": options.host,
169
- "redirectUri": options.redirectUri
170
- }));
171
- };
172
- const getOptions = () => {
173
- const str = getStorage().getItem("gc2_options");
174
- const options = str ? JSON.parse(str) : {};
175
- return {
176
- clientId: options?.clientId || "",
177
- host: options?.host || "",
178
- redirectUri: options?.redirectUri || ""
188
+ const clearTokens = () => {
189
+ getStorage().removeItem("gc2_tokens");
190
+ };
191
+ const clearOptions = () => {
192
+ getStorage().removeItem("gc2_options");
193
+ };
194
+ const getNonce = () => {
195
+ return getStorage().getItem("gc2_nonce");
196
+ };
197
+ const clearNonce = () => {
198
+ getStorage().removeItem("gc2_nonce");
179
199
  };
180
- };
181
- const clearTokens = () => {
182
- getStorage().removeItem("gc2_tokens");
183
- };
184
- const clearOptions = () => {
185
- getStorage().removeItem("gc2_options");
186
- };
187
- const getNonce = () => {
188
- return getStorage().getItem("gc2_nonce");
189
- };
190
- const clearNonce = () => {
191
- getStorage().removeItem("gc2_nonce");
192
- };
193
200
 
194
201
  //#endregion
195
202
  //#region src/services/gc2.services.ts
196
- var Gc2Service = class {
197
- constructor(options) {
198
- this.options = options;
199
- this.host = options.host;
200
- }
201
- isCodeFlowOptions(options) {
202
- return "redirectUri" in options;
203
- }
204
- isPasswordFlowOptions(options) {
205
- return "username" in options;
206
- }
207
- isSignUpOptions(options) {
208
- return "parentDb" in options;
209
- }
210
- buildUrl(path) {
211
- if (path.startsWith("http://") || path.startsWith("https://")) return path;
212
- return `${this.host}${path}`;
213
- }
214
- async request(url, method, body, contentType = "application/json") {
215
- const headers = { "Content-Type": contentType };
216
- let payload;
217
- if (contentType === "application/json") payload = JSON.stringify(body);
218
- else payload = new URLSearchParams(body).toString();
219
- const response = await fetch(url, {
220
- method,
221
- headers,
222
- body: payload
223
- });
224
- if (!response.ok) {
225
- const errText = await response.text();
226
- throw new Error(`HTTP error ${response.status}: ${errText}`);
203
+ /**
204
+ * @author Martin Høgh <mh@mapcentia.com>
205
+ * @copyright 2013-2026 MapCentia ApS
206
+ * @license https://opensource.org/license/mit The MIT License
207
+ *
208
+ */
209
+ var Gc2Service = class {
210
+ constructor(options) {
211
+ this.options = options;
212
+ this.host = options.host;
227
213
  }
228
- return response.json();
229
- }
230
- async getDeviceCode() {
231
- const path = this.options.deviceUri ?? `${this.host}/api/v4/oauth/device`;
232
- return this.request(this.buildUrl(path), "POST", { client_id: this.options.clientId });
233
- }
234
- async pollToken(deviceCode, interval) {
235
- const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
236
- const getToken = async () => {
237
- try {
238
- return await this.request(this.buildUrl(path), "POST", {
239
- client_id: this.options.clientId,
240
- device_code: deviceCode,
241
- grant_type: "device_code"
242
- });
243
- } catch (e) {
244
- const err = JSON.parse(e.message.split(": ")[1]);
245
- if (err.error === "authorization_pending") return null;
246
- return err.error_description;
214
+ isCodeFlowOptions(options) {
215
+ return "redirectUri" in options;
216
+ }
217
+ isPasswordFlowOptions(options) {
218
+ return "username" in options;
219
+ }
220
+ isSignUpOptions(options) {
221
+ return "parentDb" in options;
222
+ }
223
+ buildUrl(path) {
224
+ if (path.startsWith("http://") || path.startsWith("https://")) return path;
225
+ return `${this.host}${path}`;
226
+ }
227
+ async request(url, method, body, contentType = "application/json") {
228
+ const headers = { "Content-Type": contentType };
229
+ let payload;
230
+ if (contentType === "application/json") payload = JSON.stringify(body);
231
+ else payload = new URLSearchParams(body).toString();
232
+ const response = await fetch(url, {
233
+ method,
234
+ headers,
235
+ body: payload
236
+ });
237
+ if (!response.ok) {
238
+ const errText = await response.text();
239
+ throw new Error(`HTTP error ${response.status}: ${errText}`);
247
240
  }
248
- };
249
- let response = await getToken();
250
- while (response === null) {
251
- await new Promise((resolve) => setTimeout(resolve, interval * 1100));
252
- response = await getToken();
241
+ return response.json();
253
242
  }
254
- if (typeof response === "string") throw new Error(response);
255
- return response;
256
- }
257
- getAuthorizationCodeURL(codeChallenge, state) {
258
- let redirectUri;
259
- if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
260
- else throw new Error("CodeFlow options required for this operation");
261
- const base = this.options.authUri ?? `${this.host}/auth/`;
262
- const params = new URLSearchParams();
263
- const nonce = getNonce();
264
- params.set("response_type", "code");
265
- params.set("client_id", this.options.clientId);
266
- params.set("redirect_uri", redirectUri);
267
- params.set("state", state);
268
- params.set("code_challenge", codeChallenge);
269
- params.set("code_challenge_method", "S256");
270
- if (nonce) params.set("nonce", nonce);
271
- if (this.options.scope) params.set("scope", this.options.scope);
272
- return `${base}?${params.toString()}`;
273
- }
274
- getSignUpURL() {
275
- if (!this.isSignUpOptions(this.options)) throw new Error("CodeFlow options required for this operation");
276
- const base = this.options.authUri ?? `${this.host}/signup/`;
277
- const params = new URLSearchParams();
278
- params.set("client_id", this.options.clientId);
279
- params.set("parentdb", this.options.parentDb);
280
- params.set("redirect_uri", this.options.redirectUri);
281
- return `${base}?${params.toString()}`;
282
- }
283
- async getAuthorizationCodeToken(code, codeVerifier) {
284
- let redirectUri;
285
- if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
286
- else throw new Error("CodeFlow options required for this operation");
287
- const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
288
- return this.request(this.buildUrl(path), "POST", {
289
- client_id: this.options.clientId,
290
- redirect_uri: redirectUri,
291
- grant_type: "authorization_code",
292
- code,
293
- code_verifier: codeVerifier
294
- }, "application/x-www-form-urlencoded");
295
- }
296
- async getPasswordToken() {
297
- let username, password, database;
298
- if (this.isPasswordFlowOptions(this.options)) {
299
- username = this.options.username;
300
- password = this.options.password;
301
- database = this.options.database;
302
- } else throw new Error("PasswordFlow options required for this operation");
303
- const path = `${this.host}/api/v4/oauth`;
304
- return this.request(this.buildUrl(path), "POST", {
305
- client_id: this.options.clientId,
306
- grant_type: "password",
307
- username,
308
- password,
309
- database
310
- });
311
- }
312
- async getRefreshToken(token) {
313
- const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
314
- return this.request(this.buildUrl(path), "POST", {
315
- client_id: this.options.clientId,
316
- grant_type: "refresh_token",
317
- refresh_token: token
318
- });
319
- }
320
- getSignOutURL() {
321
- let redirectUri;
322
- if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
323
- else throw new Error("CodeFlow options required for this operation");
324
- const params = new URLSearchParams({ redirect_uri: redirectUri });
325
- return this.options.logoutUri ?? `${this.host}/signout?${params.toString()}`;
326
- }
327
- };
243
+ async getDeviceCode() {
244
+ const path = this.options.deviceUri ?? `${this.host}/api/v4/oauth/device`;
245
+ return this.request(this.buildUrl(path), "POST", { client_id: this.options.clientId });
246
+ }
247
+ async pollToken(deviceCode, interval) {
248
+ const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
249
+ const getToken = async () => {
250
+ try {
251
+ return await this.request(this.buildUrl(path), "POST", {
252
+ client_id: this.options.clientId,
253
+ device_code: deviceCode,
254
+ grant_type: "device_code"
255
+ });
256
+ } catch (e) {
257
+ const err = JSON.parse(e.message.split(": ")[1]);
258
+ if (err.error === "authorization_pending") return null;
259
+ return err.error_description;
260
+ }
261
+ };
262
+ let response = await getToken();
263
+ while (response === null) {
264
+ await new Promise((resolve) => setTimeout(resolve, interval * 1100));
265
+ response = await getToken();
266
+ }
267
+ if (typeof response === "string") throw new Error(response);
268
+ return response;
269
+ }
270
+ getAuthorizationCodeURL(codeChallenge, state) {
271
+ let redirectUri;
272
+ if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
273
+ else throw new Error("CodeFlow options required for this operation");
274
+ const base = this.options.authUri ?? `${this.host}/auth/`;
275
+ const params = new URLSearchParams();
276
+ const nonce = getNonce();
277
+ params.set("response_type", "code");
278
+ params.set("client_id", this.options.clientId);
279
+ params.set("redirect_uri", redirectUri);
280
+ params.set("state", state);
281
+ params.set("code_challenge", codeChallenge);
282
+ params.set("code_challenge_method", "S256");
283
+ if (nonce) params.set("nonce", nonce);
284
+ if (this.options.scope) params.set("scope", this.options.scope);
285
+ return `${base}?${params.toString()}`;
286
+ }
287
+ getSignUpURL() {
288
+ if (!this.isSignUpOptions(this.options)) throw new Error("CodeFlow options required for this operation");
289
+ const base = this.options.authUri ?? `${this.host}/signup/`;
290
+ const params = new URLSearchParams();
291
+ params.set("client_id", this.options.clientId);
292
+ params.set("parentdb", this.options.parentDb);
293
+ params.set("redirect_uri", this.options.redirectUri);
294
+ return `${base}?${params.toString()}`;
295
+ }
296
+ async getAuthorizationCodeToken(code, codeVerifier) {
297
+ let redirectUri;
298
+ if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
299
+ else throw new Error("CodeFlow options required for this operation");
300
+ const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
301
+ return this.request(this.buildUrl(path), "POST", {
302
+ client_id: this.options.clientId,
303
+ redirect_uri: redirectUri,
304
+ grant_type: "authorization_code",
305
+ code,
306
+ code_verifier: codeVerifier
307
+ }, "application/x-www-form-urlencoded");
308
+ }
309
+ async getPasswordToken() {
310
+ let username, password, database;
311
+ if (this.isPasswordFlowOptions(this.options)) {
312
+ username = this.options.username;
313
+ password = this.options.password;
314
+ database = this.options.database;
315
+ } else throw new Error("PasswordFlow options required for this operation");
316
+ const path = `${this.host}/api/v4/oauth`;
317
+ return this.request(this.buildUrl(path), "POST", {
318
+ client_id: this.options.clientId,
319
+ client_secret: this.options.clientSecret,
320
+ grant_type: "password",
321
+ username,
322
+ password,
323
+ database
324
+ });
325
+ }
326
+ async getRefreshToken(token) {
327
+ const path = this.options.tokenUri ?? `${this.host}/api/v4/oauth`;
328
+ return this.request(this.buildUrl(path), "POST", {
329
+ client_id: this.options.clientId,
330
+ grant_type: "refresh_token",
331
+ refresh_token: token
332
+ });
333
+ }
334
+ getSignOutURL() {
335
+ let redirectUri;
336
+ if (this.isCodeFlowOptions(this.options)) redirectUri = this.options.redirectUri;
337
+ else throw new Error("CodeFlow options required for this operation");
338
+ const params = new URLSearchParams({ redirect_uri: redirectUri });
339
+ return this.options.logoutUri ?? `${this.host}/signout?${params.toString()}`;
340
+ }
341
+ };
328
342
 
329
343
  //#endregion
330
344
  //#region src/CodeFlow.ts
331
- var CodeFlow = class {
332
- constructor(options) {
333
- this.options = options;
334
- this.service = new Gc2Service(options);
335
- }
336
- async redirectHandle() {
337
- const url = window.location.search;
338
- const queryParams = new URLSearchParams(url);
339
- if (queryParams.get("error")) throw new Error(`Failed to redirect: ${url}`);
340
- const code = queryParams.get("code");
341
- if (code) {
342
- if (queryParams.get("state") !== getStorage().getItem("state")) throw new Error("Possible CSRF attack. Aborting login!");
343
- try {
344
- const { access_token, refresh_token, id_token } = await this.service.getAuthorizationCodeToken(code, getStorage().getItem("codeVerifier"));
345
- setTokens({
346
- accessToken: access_token,
347
- refreshToken: refresh_token,
348
- idToken: id_token
349
- });
350
- setOptions({
351
- clientId: this.options.clientId,
352
- host: this.options.host,
353
- redirectUri: this.options.redirectUri
354
- });
355
- getStorage().removeItem("state");
356
- getStorage().removeItem("codeVerifier");
357
- const params = new URLSearchParams(window.location.search);
358
- params.delete("code");
359
- params.delete("state");
360
- const loc = window.location;
361
- const newUrl = loc.origin + loc.pathname + (params.size > 0 ? "?" + params.toString() : "");
362
- history.pushState(null, "", newUrl);
363
- return Promise.resolve(true);
364
- } catch (e) {
365
- throw new Error(e.message);
345
+ /**
346
+ * @author Martin Høgh <mh@mapcentia.com>
347
+ * @copyright 2013-2026 MapCentia ApS
348
+ * @license https://opensource.org/license/mit The MIT License
349
+ *
350
+ */
351
+ var CodeFlow = class {
352
+ constructor(options) {
353
+ this.options = options;
354
+ this.service = new Gc2Service(options);
355
+ }
356
+ async redirectHandle() {
357
+ const url = window.location.search;
358
+ const queryParams = new URLSearchParams(url);
359
+ if (queryParams.get("error")) throw new Error(`Failed to redirect: ${url}`);
360
+ const code = queryParams.get("code");
361
+ if (code) {
362
+ if (queryParams.get("state") !== getStorage().getItem("state")) throw new Error("Possible CSRF attack. Aborting login!");
363
+ try {
364
+ const { access_token, refresh_token, id_token } = await this.service.getAuthorizationCodeToken(code, getStorage().getItem("codeVerifier"));
365
+ setTokens({
366
+ accessToken: access_token,
367
+ refreshToken: refresh_token,
368
+ idToken: id_token
369
+ });
370
+ setOptions({
371
+ clientId: this.options.clientId,
372
+ host: this.options.host,
373
+ redirectUri: this.options.redirectUri
374
+ });
375
+ getStorage().removeItem("state");
376
+ getStorage().removeItem("codeVerifier");
377
+ const params = new URLSearchParams(window.location.search);
378
+ params.delete("code");
379
+ params.delete("state");
380
+ const loc = window.location;
381
+ const newUrl = loc.origin + loc.pathname + (params.size > 0 ? "?" + params.toString() : "");
382
+ history.pushState(null, "", newUrl);
383
+ return Promise.resolve(true);
384
+ } catch (e) {
385
+ throw new Error(e.message);
386
+ }
366
387
  }
388
+ return await isLogin(this.service);
367
389
  }
368
- return await isLogin(this.service);
369
- }
370
- async signIn() {
371
- const { state, codeVerifier, codeChallenge } = await generatePkceChallenge();
372
- getStorage().setItem("state", state);
373
- getStorage().setItem("codeVerifier", codeVerifier);
374
- window.location.assign(this.service.getAuthorizationCodeURL(codeChallenge, state));
375
- }
376
- signOut() {
377
- this.clear();
378
- window.location.assign(this.service.getSignOutURL());
379
- }
380
- clear() {
381
- clearTokens();
382
- clearOptions();
383
- clearNonce();
384
- }
385
- };
390
+ async signIn() {
391
+ const { state, codeVerifier, codeChallenge } = await generatePkceChallenge();
392
+ getStorage().setItem("state", state);
393
+ getStorage().setItem("codeVerifier", codeVerifier);
394
+ window.location.assign(this.service.getAuthorizationCodeURL(codeChallenge, state));
395
+ }
396
+ signOut() {
397
+ this.clear();
398
+ window.location.assign(this.service.getSignOutURL());
399
+ }
400
+ clear() {
401
+ clearTokens();
402
+ clearOptions();
403
+ clearNonce();
404
+ }
405
+ };
386
406
 
387
407
  //#endregion
388
408
  //#region src/PasswordFlow.ts
389
- var PasswordFlow = class {
390
- constructor(options) {
391
- this.options = options;
392
- this.service = new Gc2Service(options);
393
- }
394
- async signIn() {
395
- const { access_token, refresh_token } = await this.service.getPasswordToken();
396
- setTokens({
397
- accessToken: access_token,
398
- refreshToken: refresh_token
399
- });
400
- setOptions({
401
- clientId: this.options.clientId,
402
- host: this.options.host,
403
- redirectUri: ""
404
- });
405
- }
406
- signOut() {
407
- this.clear();
408
- }
409
- clear() {
410
- clearTokens();
411
- clearOptions();
412
- clearNonce();
413
- }
414
- };
409
+ /**
410
+ * @author Martin Høgh <mh@mapcentia.com>
411
+ * @copyright 2013-2026 MapCentia ApS
412
+ * @license https://opensource.org/license/mit The MIT License
413
+ *
414
+ */
415
+ var PasswordFlow = class {
416
+ constructor(options) {
417
+ this.options = options;
418
+ this.service = new Gc2Service(options);
419
+ }
420
+ async signIn() {
421
+ const { access_token, refresh_token } = await this.service.getPasswordToken();
422
+ setTokens({
423
+ accessToken: access_token,
424
+ refreshToken: refresh_token
425
+ });
426
+ setOptions({
427
+ clientId: this.options.clientId,
428
+ host: this.options.host,
429
+ redirectUri: "",
430
+ clientSecret: this.options.clientSecret
431
+ });
432
+ }
433
+ signOut() {
434
+ this.clear();
435
+ }
436
+ clear() {
437
+ clearTokens();
438
+ clearOptions();
439
+ clearNonce();
440
+ }
441
+ };
415
442
 
416
443
  //#endregion
417
- //#region src/util/request-headers.ts
418
- const getHeaders = async (contentType = "application/json") => {
419
- if (!await isLogin(new Gc2Service(getOptions()))) return Promise.reject("Is not logged in");
420
- const { accessToken } = getTokens();
421
- const headers = {
422
- Accept: "application/json",
423
- Cookie: "XDEBUG_SESSION=XDEBUG_ECLIPSE",
424
- Authorization: accessToken ? "Bearer " + accessToken : null
444
+ //#region src/http/errors.ts
445
+ /**
446
+ * Normalized error thrown by all SDK HTTP operations.
447
+ * CLI and Web should catch this type for consistent error handling.
448
+ */
449
+ var CentiaApiError = class extends Error {
450
+ constructor(opts) {
451
+ super(opts.message);
452
+ this.name = "CentiaApiError";
453
+ if (opts.cause !== void 0) this.cause = opts.cause;
454
+ this.status = opts.status;
455
+ this.code = opts.code;
456
+ this.details = opts.details;
457
+ this.requestId = opts.requestId;
458
+ this.method = opts.method;
459
+ this.url = opts.url;
460
+ }
425
461
  };
426
- if (contentType) headers["Content-Type"] = contentType;
427
- return headers;
428
- };
429
- var request_headers_default = getHeaders;
462
+ /** Type guard for CentiaApiError. */
463
+ function isCentiaApiError(e) {
464
+ return e instanceof CentiaApiError;
465
+ }
430
466
 
431
467
  //#endregion
432
- //#region src/util/make-request.ts
433
- const make = async (version, resource, method, payload, contentType = "application/json") => {
434
- const options = getOptions();
435
- let request = {
436
- method,
437
- headers: await request_headers_default(contentType),
438
- redirect: "manual"
468
+ //#region src/http/client.ts
469
+ /**
470
+ * Unified HTTP client for the Centia API.
471
+ * Works in both Node.js and browser environments.
472
+ */
473
+ var CentiaHttpClient = class {
474
+ constructor(config) {
475
+ this.baseUrl = config.baseUrl.replace(/\/+$/, "");
476
+ this.auth = config.auth ?? {};
477
+ this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
478
+ this.userAgent = config.userAgent;
479
+ }
480
+ /**
481
+ * Execute an HTTP request against the Centia API.
482
+ * Returns parsed JSON on success. Throws CentiaApiError on non-expected status.
483
+ */
484
+ async request(opts) {
485
+ return (await this.requestFull(opts)).body;
486
+ }
487
+ /**
488
+ * Execute an HTTP request and return the full response including headers.
489
+ * Useful for operations that return Location headers (POST 201, PATCH 303).
490
+ */
491
+ async requestFull(opts) {
492
+ const url = this.buildUrl(opts.path, opts.query);
493
+ const headers = await this.buildHeaders(opts);
494
+ const init = {
495
+ method: opts.method,
496
+ headers,
497
+ redirect: "manual"
498
+ };
499
+ if (opts.body !== void 0 && opts.body !== null) init.body = this.resolveContentType(opts.contentType) === "application/json" ? JSON.stringify(opts.body) : opts.body;
500
+ const response = await this.fetchFn(url, init);
501
+ if (response.type === "opaqueredirect") {
502
+ if ((opts.expectedStatus ?? 200) === 303) return {
503
+ body: null,
504
+ status: 303,
505
+ getHeader: (name) => name.toLowerCase() === "location" ? response.url : null
506
+ };
507
+ }
508
+ return {
509
+ body: await this.handleResponse(response, opts, url),
510
+ status: response.status,
511
+ getHeader: (name) => response.headers.get(name)
512
+ };
513
+ }
514
+ buildUrl(path, query) {
515
+ const cleanPath = path.replace(/^\/+/, "");
516
+ let url = `${this.baseUrl}/${cleanPath}`;
517
+ if (query) {
518
+ const params = new URLSearchParams(query);
519
+ url += `?${params.toString()}`;
520
+ }
521
+ return url;
522
+ }
523
+ async buildHeaders(opts) {
524
+ const headers = { "Accept": opts.accept ?? "application/json" };
525
+ if (this.auth.getAccessToken) {
526
+ const token = await this.auth.getAccessToken();
527
+ if (token) headers["Authorization"] = `Bearer ${token}`;
528
+ }
529
+ if (this.auth.getHeaders) {
530
+ const authHeaders = await this.auth.getHeaders();
531
+ Object.assign(headers, authHeaders);
532
+ }
533
+ if (this.userAgent && typeof navigator === "undefined") headers["User-Agent"] = this.userAgent;
534
+ const ct = this.resolveContentType(opts.contentType);
535
+ if (ct) headers["Content-Type"] = ct;
536
+ return headers;
537
+ }
538
+ resolveContentType(contentType) {
539
+ if (contentType === null) return null;
540
+ return contentType ?? "application/json";
541
+ }
542
+ async handleResponse(response, opts, url) {
543
+ const expectedStatus = opts.expectedStatus ?? 200;
544
+ let bodyText = "";
545
+ try {
546
+ bodyText = await response.text();
547
+ } catch {}
548
+ let parsed = null;
549
+ if (bodyText) try {
550
+ parsed = JSON.parse(bodyText);
551
+ } catch {}
552
+ if (response.status !== expectedStatus) throw new CentiaApiError({
553
+ message: (parsed?.message ?? parsed?.error ?? bodyText) || `Unexpected status ${response.status}`,
554
+ status: response.status,
555
+ code: parsed?.code,
556
+ details: parsed,
557
+ requestId: response.headers.get("x-request-id") ?? void 0,
558
+ method: opts.method,
559
+ url
560
+ });
561
+ return parsed ?? (bodyText || null);
562
+ }
439
563
  };
440
- if (payload) request.body = contentType === "application/json" ? JSON.stringify(payload) : payload;
441
- return await fetch(options.host + `/api/v${version}/${resource}`, request);
442
- };
443
- var make_request_default = make;
564
+ /**
565
+ * Create a new Centia HTTP client.
566
+ *
567
+ * Node.js usage:
568
+ * ```ts
569
+ * const client = createCentiaClient({
570
+ * baseUrl: 'https://example.centia.io',
571
+ * auth: { getAccessToken: async () => process.env.CENTIA_TOKEN },
572
+ * });
573
+ * ```
574
+ *
575
+ * Browser usage:
576
+ * ```ts
577
+ * const client = createCentiaClient({
578
+ * baseUrl: 'https://example.centia.io',
579
+ * auth: { getAccessToken: async () => getStoredToken() },
580
+ * });
581
+ * ```
582
+ */
583
+ function createCentiaClient(config) {
584
+ return new CentiaHttpClient(config);
585
+ }
444
586
 
445
587
  //#endregion
446
- //#region src/util/get-response.ts
447
- const get = async (response, expectedCode) => {
448
- let res = null;
449
- let bodyText = "";
450
- try {
451
- bodyText = await response.text();
452
- } catch (e) {}
453
- if (bodyText) try {
454
- res = JSON.parse(bodyText);
455
- } catch (e) {}
456
- if (response.status !== expectedCode) {
457
- const msg = res && (res.message || res.error) || bodyText || `Unexpected status ${response.status}`;
458
- throw new Error(msg);
588
+ //#region src/http/legacy.ts
589
+ /**
590
+ * @author Martin Høgh <mh@mapcentia.com>
591
+ * @copyright 2013-2026 MapCentia ApS
592
+ * @license https://opensource.org/license/mit The MIT License
593
+ *
594
+ * Legacy bridge: creates a CentiaHttpClient from storage-based options/tokens.
595
+ * Used by existing SDK modules when no explicit client is provided.
596
+ */
597
+ /**
598
+ * Create a CentiaHttpClient backed by the legacy storage-based auth.
599
+ * The auth callback reads fresh tokens from storage on each request
600
+ * and auto-refreshes expired access tokens via the refresh token.
601
+ */
602
+ function getLegacyClient() {
603
+ return new CentiaHttpClient({
604
+ baseUrl: getOptions().host,
605
+ auth: { getAccessToken: async () => {
606
+ if (!await isLogin(new Gc2Service(getOptions()))) return;
607
+ return getTokens().accessToken || void 0;
608
+ } }
609
+ });
459
610
  }
460
- return res;
461
- };
462
- var get_response_default = get;
463
611
 
464
612
  //#endregion
465
613
  //#region src/Sql.ts
466
- var Sql = class {
467
- async exec(request) {
468
- return await get_response_default(await make_request_default("4", `sql`, "POST", request), 200);
469
- }
470
- };
614
+ var Sql = class {
615
+ constructor(client) {
616
+ this.client = client ?? getLegacyClient();
617
+ }
618
+ async exec(request) {
619
+ return this.client.request({
620
+ path: "api/v4/sql",
621
+ method: "POST",
622
+ body: request
623
+ });
624
+ }
625
+ };
471
626
 
472
627
  //#endregion
473
628
  //#region src/Rpc.ts
474
- var Rpc = class {
475
- async call(request) {
476
- return await get_response_default(await make_request_default("4", `call`, "POST", request), 200);
477
- }
478
- };
629
+ var Rpc = class {
630
+ constructor(client) {
631
+ this.client = client ?? getLegacyClient();
632
+ }
633
+ async call(request) {
634
+ return this.client.request({
635
+ path: "api/v4/call",
636
+ method: "POST",
637
+ body: request
638
+ });
639
+ }
640
+ };
641
+
642
+ //#endregion
643
+ //#region src/Gql.ts
644
+ var Gql = class {
645
+ constructor(schema, client) {
646
+ this.schema = schema;
647
+ this.client = client ?? getLegacyClient();
648
+ }
649
+ async request(request) {
650
+ return this.client.request({
651
+ path: `api/graphql/schema/${this.schema}`,
652
+ method: "POST",
653
+ body: request
654
+ });
655
+ }
656
+ };
479
657
 
480
658
  //#endregion
481
659
  //#region src/Meta.ts
482
- var Meta = class {
483
- async query(rel) {
484
- return await get_response_default(await make_request_default("3", `meta/${rel}`, "GET", null), 200);
485
- }
486
- };
660
+ var Meta = class {
661
+ constructor(client) {
662
+ this.client = client ?? getLegacyClient();
663
+ }
664
+ async query(rel) {
665
+ return this.client.request({
666
+ path: `api/v4/meta/${rel}`,
667
+ method: "GET"
668
+ });
669
+ }
670
+ };
487
671
 
488
672
  //#endregion
489
673
  //#region src/Status.ts
490
- var Status = class {
491
- isAuth() {
492
- const tokens = getTokens();
493
- return !(!tokens.accessToken && !tokens.refreshToken);
494
- }
495
- getTokens() {
496
- return getTokens();
497
- }
498
- };
674
+ /**
675
+ * @author Martin Høgh <mh@mapcentia.com>
676
+ * @copyright 2013-2026 MapCentia ApS
677
+ * @license https://opensource.org/license/mit The MIT License
678
+ *
679
+ */
680
+ var Status = class {
681
+ isAuth() {
682
+ const tokens = getTokens();
683
+ return !(!tokens.accessToken && !tokens.refreshToken);
684
+ }
685
+ getTokens() {
686
+ return getTokens();
687
+ }
688
+ };
499
689
 
500
690
  //#endregion
501
691
  //#region src/Claims.ts
502
- var Claims = class {
503
- get() {
504
- const tokens = getTokens().accessToken;
505
- return claims(tokens);
506
- }
507
- };
692
+ /**
693
+ * @author Martin Høgh <mh@mapcentia.com>
694
+ * @copyright 2013-2026 MapCentia ApS
695
+ * @license https://opensource.org/license/mit The MIT License
696
+ *
697
+ */
698
+ var Claims = class {
699
+ get() {
700
+ const tokens = getTokens().accessToken;
701
+ return claims(tokens);
702
+ }
703
+ };
508
704
 
509
705
  //#endregion
510
706
  //#region src/Users.ts
511
- var Users = class {
512
- async get(user) {
513
- return await get_response_default(await make_request_default("4", `users/${user}`, "GET", null), 200);
514
- }
515
- };
707
+ var Users = class {
708
+ constructor(client) {
709
+ this.client = client ?? getLegacyClient();
710
+ }
711
+ async get(user) {
712
+ return this.client.request({
713
+ path: `api/v4/users/${user}`,
714
+ method: "GET"
715
+ });
716
+ }
717
+ };
516
718
 
517
719
  //#endregion
518
720
  //#region src/Ws.ts
519
- var Ws = class {
520
- constructor(options) {
521
- this.options = options;
522
- this.options.wsClient = this.options?.wsClient ?? WebSocket;
523
- }
524
- connect() {
525
- const me = this;
526
- const { accessToken } = getTokens();
527
- const connect = () => {
528
- let queryString = `?token=` + accessToken;
529
- if (this.options?.rel) queryString = queryString + `&rel=` + this.options.rel;
530
- const WSClass = this.options.wsClient;
531
- const ws = new WSClass(this.options.host + `/` + queryString);
532
- ws.onopen = function() {
533
- console.log("WebSocket connected!");
534
- };
535
- ws.onmessage = function(event) {
536
- me.options.callBack(event.data);
537
- };
538
- ws.onclose = function(event) {
539
- if (accessToken !== "") {
540
- console.log("WebSocket closed, reconnecting in 3 seconds...", event.reason);
541
- setTimeout(connect, 3e3);
542
- }
543
- };
544
- ws.onerror = function(err) {
545
- console.error("WebSocket error observed:", err);
546
- ws.close();
721
+ /**
722
+ * @author Martin Høgh <mh@mapcentia.com>
723
+ * @copyright 2013-2026 MapCentia ApS
724
+ * @license https://opensource.org/license/mit The MIT License
725
+ *
726
+ */
727
+ var Ws = class {
728
+ constructor(options) {
729
+ this.options = options;
730
+ this.options.wsClient = this.options?.wsClient ?? WebSocket;
731
+ }
732
+ connect() {
733
+ const me = this;
734
+ const { accessToken } = getTokens();
735
+ const connect = () => {
736
+ let queryString = `?token=` + accessToken;
737
+ if (this.options?.rel) queryString = queryString + `&rel=` + this.options.rel;
738
+ const WSClass = this.options.wsClient;
739
+ const ws = new WSClass(this.options.host + `/` + queryString);
740
+ ws.onopen = function() {
741
+ console.log("WebSocket connected!");
742
+ };
743
+ ws.onmessage = function(event) {
744
+ me.options.callBack(event.data);
745
+ };
746
+ ws.onclose = function(event) {
747
+ if (accessToken !== "") {
748
+ console.log("WebSocket closed, reconnecting in 3 seconds...", event.reason);
749
+ setTimeout(connect, 3e3);
750
+ }
751
+ };
752
+ ws.onerror = function(err) {
753
+ console.error("WebSocket error observed:", err);
754
+ ws.close();
755
+ };
547
756
  };
548
- };
549
- if (accessToken !== "") connect();
550
- }
551
- };
757
+ if (accessToken !== "") connect();
758
+ }
759
+ };
552
760
 
553
761
  //#endregion
554
762
  //#region src/Stats.ts
555
- var Stats = class {
556
- async get() {
557
- return await get_response_default(await make_request_default("4", `stats`, "GET", null), 200);
558
- }
559
- };
763
+ var Stats = class {
764
+ constructor(client) {
765
+ this.client = client ?? getLegacyClient();
766
+ }
767
+ async get() {
768
+ return this.client.request({
769
+ path: "api/v4/stats",
770
+ method: "GET"
771
+ });
772
+ }
773
+ };
560
774
 
561
775
  //#endregion
562
776
  //#region src/Tables.ts
563
- var Tables = class {
564
- async get(schema, table) {
565
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "GET", null), 200);
566
- }
567
- async create(schema, table, payload) {
568
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "POST", payload), 200);
569
- }
570
- async patch(schema, table, payload) {
571
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "PATCH", payload), 200);
572
- }
573
- async delete(schema, table) {
574
- return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "DELETE", null), 204);
575
- }
576
- };
777
+ var Tables = class {
778
+ constructor(client) {
779
+ this.client = client ?? getLegacyClient();
780
+ }
781
+ async get(schema, table) {
782
+ return this.client.request({
783
+ path: `api/v4/schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`,
784
+ method: "GET"
785
+ });
786
+ }
787
+ async create(schema, table, payload) {
788
+ return this.client.request({
789
+ path: `api/v4/schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`,
790
+ method: "POST",
791
+ body: payload
792
+ });
793
+ }
794
+ async patch(schema, table, payload) {
795
+ return this.client.request({
796
+ path: `api/v4/schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`,
797
+ method: "PATCH",
798
+ body: payload
799
+ });
800
+ }
801
+ async delete(schema, table) {
802
+ return this.client.request({
803
+ path: `api/v4/schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`,
804
+ method: "DELETE",
805
+ expectedStatus: 204
806
+ });
807
+ }
808
+ };
577
809
 
578
810
  //#endregion
579
811
  //#region src/Api.ts
580
- function isPlainObject$1(v) {
581
- return typeof v === "object" && v !== null && !Array.isArray(v);
582
- }
583
- function validateParamsForMethod(method, params) {
584
- if (Array.isArray(params)) {
585
- const badIndex = params.findIndex((p) => !isPlainObject$1(p));
586
- if (badIndex !== -1) throw new TypeError(`createApi: Invalid argument at index ${badIndex} for RPC method "${method}". Expected a plain object.`);
812
+ function isPlainObject$1(v) {
813
+ return typeof v === "object" && v !== null && !Array.isArray(v);
814
+ }
815
+ function validateParamsForMethod(method, params) {
816
+ if (Array.isArray(params)) {
817
+ const badIndex = params.findIndex((p) => !isPlainObject$1(p));
818
+ if (badIndex !== -1) throw new TypeError(`createApi: Invalid argument at index ${badIndex} for RPC method "${method}". Expected a plain object.`);
819
+ return params;
820
+ }
821
+ if (params === void 0) return {};
822
+ if (!isPlainObject$1(params)) throw new TypeError(`createApi: Invalid argument for RPC method "${method}". Expected a plain object.`);
587
823
  return params;
588
824
  }
589
- if (params === void 0) return {};
590
- if (!isPlainObject$1(params)) throw new TypeError(`createApi: Invalid argument for RPC method "${method}". Expected a plain object.`);
591
- return params;
592
- }
593
- function extractDataFromResponse(method, res) {
594
- if (!res || typeof res !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected an object.`);
595
- if (res.jsonrpc !== "2.0") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing or invalid jsonrpc version.`);
596
- const err = res.error;
597
- if (err !== void 0) {
598
- if (!err || typeof err !== "object") throw new TypeError(`createApi: Invalid RPC error for method "${method}". Expected 'error' to be an object.`);
599
- const code = err.code;
600
- const message = err.message;
601
- const data$1 = err.data;
602
- const codeIsNum = typeof code === "number" && Number.isFinite(code);
603
- const details = typeof message === "string" && message.length > 0 ? message : "Unknown error";
604
- const e = /* @__PURE__ */ new Error(`createApi: RPC error for method "${method}"${codeIsNum ? ` (${code})` : ""}: ${details}`);
605
- e.code = code;
606
- if (data$1 !== void 0) e.data = data$1;
607
- e.method = method;
608
- e.name = "JsonRpcError";
609
- throw e;
610
- }
611
- const result = res.result;
612
- if (!result || typeof result !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing result object.`);
613
- const data = result.data;
614
- if (!Array.isArray(data)) throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected result.data to be an array.`);
615
- return data;
616
- }
617
- async function dispatch(name, paramsLike) {
618
- if (typeof name !== "string" || name.length === 0) throw new TypeError("createApi: RPC method name must be a non-empty string.");
619
- const params = validateParamsForMethod(String(name), paramsLike);
620
- const rpc = new Rpc();
621
- const request = {
622
- jsonrpc: "2.0",
623
- method: name,
624
- id: 1,
625
- params
626
- };
627
- const res = await rpc.call(request);
628
- return extractDataFromResponse(String(name), res);
629
- }
630
- function createApi() {
631
- return new Proxy({}, { get(_target, prop) {
632
- if (typeof prop !== "string") return void 0;
633
- return (...args) => {
634
- return dispatch(prop, args.length === 0 ? {} : args.length === 1 ? args[0] : args);
825
+ function extractDataFromResponse(method, res) {
826
+ if (!res || typeof res !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected an object.`);
827
+ if (res.jsonrpc !== "2.0") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing or invalid jsonrpc version.`);
828
+ const err = res.error;
829
+ if (err !== void 0) {
830
+ if (!err || typeof err !== "object") throw new TypeError(`createApi: Invalid RPC error for method "${method}". Expected 'error' to be an object.`);
831
+ const code = err.code;
832
+ const message = err.message;
833
+ const data = err.data;
834
+ const codeIsNum = typeof code === "number" && Number.isFinite(code);
835
+ const details = typeof message === "string" && message.length > 0 ? message : "Unknown error";
836
+ const e = /* @__PURE__ */ new Error(`createApi: RPC error for method "${method}"${codeIsNum ? ` (${code})` : ""}: ${details}`);
837
+ e.code = code;
838
+ if (data !== void 0) e.data = data;
839
+ e.method = method;
840
+ e.name = "JsonRpcError";
841
+ throw e;
842
+ }
843
+ const result = res.result;
844
+ if (!result || typeof result !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing result object.`);
845
+ const dataArr = result.data;
846
+ if (!Array.isArray(dataArr)) throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected result.data to be an array.`);
847
+ return dataArr;
848
+ }
849
+ async function dispatch(name, paramsLike, client) {
850
+ if (typeof name !== "string" || name.length === 0) throw new TypeError("createApi: RPC method name must be a non-empty string.");
851
+ const params = validateParamsForMethod(String(name), paramsLike);
852
+ const rpc = new Rpc(client);
853
+ const request = {
854
+ jsonrpc: "2.0",
855
+ method: name,
856
+ id: 1,
857
+ params
635
858
  };
636
- } });
637
- }
859
+ const res = await rpc.call(request);
860
+ return extractDataFromResponse(String(name), res);
861
+ }
862
+ function createApi(client) {
863
+ return new Proxy({}, { get(_target, prop) {
864
+ if (typeof prop !== "string") return void 0;
865
+ return (...args) => {
866
+ return dispatch(prop, args.length === 0 ? {} : args.length === 1 ? args[0] : args, client);
867
+ };
868
+ } });
869
+ }
638
870
 
639
871
  //#endregion
640
872
  //#region src/SignUp.ts
641
- var SignUp = class {
642
- constructor(options) {
643
- this.options = options;
644
- this.service = new Gc2Service(options);
645
- }
646
- async signUp() {
647
- window.location.assign(this.service.getSignUpURL());
648
- }
649
- };
873
+ /**
874
+ * @author Martin Høgh <mh@mapcentia.com>
875
+ * @copyright 2013-2026 MapCentia ApS
876
+ * @license https://opensource.org/license/mit The MIT License
877
+ *
878
+ */
879
+ var SignUp = class {
880
+ constructor(options) {
881
+ this.options = options;
882
+ this.service = new Gc2Service(options);
883
+ }
884
+ async signUp() {
885
+ window.location.assign(this.service.getSignUpURL());
886
+ }
887
+ };
650
888
 
651
889
  //#endregion
652
890
  //#region src/SqlBuilder.ts
653
- function findTable(schema, name) {
654
- const tbl = schema.tables.find((t) => t.name === name);
655
- if (!tbl) throw new Error(`Table not found in schema: ${name}`);
656
- return tbl;
657
- }
658
- function findColumn(table, name) {
659
- const col = table.columns.find((c) => c.name === name);
660
- if (!col) throw new Error(`Column not found in table ${table.name}: ${name}`);
661
- return col;
662
- }
663
- function getPrimaryKeyColumns(table) {
664
- const pk = (table.constraints || []).find((c) => c.constraint === "primary" && Array.isArray(c.columns) && c.columns.length > 0);
665
- return pk ? pk.columns.map(String) : [];
666
- }
667
- function typeNameToHint(typname, isArray) {
668
- if (!typname) return void 0;
669
- const base = typname;
670
- return isArray ? base + "[]" : base;
671
- }
672
- function addTypeHintForParam(typeHints, paramName, col, value) {
673
- let isArr = col._is_array;
674
- if (Array.isArray(value)) if (isArrayShapedGeomTypename(col._typname)) isArr = value.every(Array.isArray);
675
- else isArr = true;
676
- const hint = typeNameToHint(col._typname, isArr);
677
- if (hint) typeHints[paramName] = hint;
678
- }
679
- function expectedScalarKind(typname) {
680
- const t = typname.toLowerCase();
681
- if (t === "int2" || t === "int4" || t === "int8" || t === "float4" || t === "float8") return "number";
682
- if (t === "numeric" || t === "decimal") return "string";
683
- if (t === "varchar" || t === "text" || t === "bpchar" || t === "char" || t === "date" || t === "time" || t === "timetz" || t === "timestamp" || t === "timestamptz") return "string";
684
- if (t === "bool") return "boolean";
685
- if (t === "json" || t === "jsonb") return "json";
686
- if (t === "int4range" || t === "int8range" || t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "range";
687
- if (t === "interval") return "interval";
688
- if (t === "point" || t === "line" || t === "lseg" || t === "box" || t === "path" || t === "polygon" || t === "circle") return "geom";
689
- return "unknown";
690
- }
691
- function isArrayShapedGeomTypename(typname) {
692
- const t = typname.toLowerCase();
693
- return t === "path" || t === "polygon";
694
- }
695
- function isArrayShapedGeomScalarValue(col, value) {
696
- if (!Array.isArray(value)) return false;
697
- if (!isArrayShapedGeomTypename(col._typname)) return false;
698
- return !value.every(Array.isArray);
699
- }
700
- function expectedRangeInnerKind(typname) {
701
- const t = typname.toLowerCase();
702
- if (t === "int4range" || t === "int8range") return "number";
703
- if (t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "string";
704
- return "unknown";
705
- }
706
- function isPlainObject(v) {
707
- return typeof v === "object" && v !== null && !Array.isArray(v);
708
- }
709
- function isFiniteNumber(n) {
710
- return typeof n === "number" && Number.isFinite(n);
711
- }
712
- function isPointLike(v) {
713
- if (!isPlainObject(v)) return false;
714
- const x = v.x;
715
- const y = v.y;
716
- return isFiniteNumber(x) && isFiniteNumber(y);
717
- }
718
- function validateGeometryForColumn(col, value, context) {
719
- const t = col._typname.toLowerCase();
720
- if (t === "point") {
721
- if (!isPointLike(value)) throw new Error(`Invalid value for ${context}. Expected Point { x: number, y: number }`);
722
- return;
723
- }
724
- if (t === "line") {
725
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Line { A: number, B: number, C: number }`);
726
- const A = value.A, B = value.B, C = value.C;
727
- if (!isFiniteNumber(A) || !isFiniteNumber(B) || !isFiniteNumber(C)) throw new Error(`Invalid Line for ${context}. A, B, C must be finite numbers`);
728
- return;
729
- }
730
- if (t === "lseg" || t === "box") {
731
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected ${t.toUpperCase()} { start: Point, end: Point }`);
732
- const start = value.start;
733
- const end = value.end;
734
- if (!isPointLike(start) || !isPointLike(end)) throw new Error(`Invalid ${t} for ${context}. 'start' and 'end' must be Point { x, y }`);
735
- return;
736
- }
737
- if (t === "path") {
738
- if (!Array.isArray(value) || value.length < 1) throw new Error(`Invalid value for ${context}. Expected Path [isClosed: boolean, ...points: Point[]]`);
739
- const [isClosed, ...points] = value;
740
- if (typeof isClosed !== "boolean") throw new Error(`Invalid Path for ${context}. First element must be boolean (isClosed)`);
741
- for (let i = 0; i < points.length; i++) if (!isPointLike(points[i])) throw new Error(`Invalid Path for ${context}. Element at index ${i + 1} must be Point { x, y }`);
742
- return;
743
- }
744
- if (t === "polygon") {
745
- if (!Array.isArray(value)) throw new Error(`Invalid value for ${context}. Expected Polygon as Point[]`);
746
- for (let i = 0; i < value.length; i++) if (!isPointLike(value[i])) throw new Error(`Invalid Polygon for ${context}. Element at index ${i} must be Point { x, y }`);
747
- return;
748
- }
749
- if (t === "circle") {
750
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Circle { center: Point, radius: number }`);
751
- const center = value.center;
752
- const radius = value.radius;
753
- if (!isPointLike(center) || !isFiniteNumber(radius)) throw new Error(`Invalid Circle for ${context}. 'center' must be Point and 'radius' must be finite number`);
754
- return;
755
- }
756
- }
757
- function validateRangeForColumn(col, value, context) {
758
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected a range object for type ${col._typname}`);
759
- const r = value;
760
- const hasLower = Object.prototype.hasOwnProperty.call(r, "lower");
761
- const hasUpper = Object.prototype.hasOwnProperty.call(r, "upper");
762
- const hasLi = Object.prototype.hasOwnProperty.call(r, "lowerInclusive");
763
- const hasUi = Object.prototype.hasOwnProperty.call(r, "upperInclusive");
764
- if (!hasLower || !hasUpper || !hasLi || !hasUi) throw new Error(`Invalid range for ${context}. Required properties: lower, upper, lowerInclusive, upperInclusive`);
765
- if (typeof r.lowerInclusive !== "boolean" || typeof r.upperInclusive !== "boolean") throw new Error(`Invalid range for ${context}. lowerInclusive and upperInclusive must be boolean`);
766
- const inner = expectedRangeInnerKind(col._typname);
767
- if (inner === "number") {
768
- if (typeof r.lower !== "number" || !Number.isFinite(r.lower)) throw new Error(`Invalid range.lower for ${context}. Expected number for type ${col._typname}`);
769
- if (typeof r.upper !== "number" || !Number.isFinite(r.upper)) throw new Error(`Invalid range.upper for ${context}. Expected number for type ${col._typname}`);
770
- } else if (inner === "string") {
771
- if (typeof r.lower !== "string") throw new Error(`Invalid range.lower for ${context}. Expected string for type ${col._typname}`);
772
- if (typeof r.upper !== "string") throw new Error(`Invalid range.upper for ${context}. Expected string for type ${col._typname}`);
773
- }
774
- }
775
- function validateIntervalForColumn(col, value, context) {
776
- if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected an interval object for type ${col._typname}`);
777
- const v = value;
778
- for (const k of [
779
- "y",
780
- "m",
781
- "d",
782
- "h",
783
- "i",
784
- "s"
785
- ]) {
786
- if (!Object.prototype.hasOwnProperty.call(v, k)) throw new Error(`Invalid interval for ${context}. Missing property '${k}'`);
787
- const num = v[k];
788
- if (typeof num !== "number" || !Number.isFinite(num)) throw new Error(`Invalid interval.${String(k)} for ${context}. Expected finite number`);
789
- }
790
- }
791
- function isValidJsonLike(value) {
792
- return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "object" && value !== null;
793
- }
794
- function validateScalarForColumn(col, value, context) {
795
- const kind = expectedScalarKind(col._typname);
796
- if (kind === "unknown") return;
797
- if (kind === "number") {
798
- if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`Invalid value for ${context}. Expected number for type ${col._typname}, got ${typeof value}`);
799
- return;
800
- }
801
- if (kind === "string") {
802
- if (typeof value !== "string") throw new Error(`Invalid value for ${context}. Expected string for type ${col._typname}, got ${typeof value}`);
803
- return;
804
- }
805
- if (kind === "boolean") {
806
- if (typeof value !== "boolean") throw new Error(`Invalid value for ${context}. Expected boolean for type ${col._typname}, got ${typeof value}`);
807
- return;
808
- }
809
- if (kind === "json") {
810
- if (!isValidJsonLike(value)) throw new Error(`Invalid value for ${context}. Expected JSON-compatible value for type ${col._typname}`);
811
- return;
891
+ function findTable(schema, name) {
892
+ const tbl = schema.tables.find((t) => t.name === name);
893
+ if (!tbl) throw new Error(`Table not found in schema: ${name}`);
894
+ return tbl;
895
+ }
896
+ function findColumn(table, name) {
897
+ const col = table.columns.find((c) => c.name === name);
898
+ if (!col) throw new Error(`Column not found in table ${table.name}: ${name}`);
899
+ return col;
900
+ }
901
+ function getPrimaryKeyColumns(table) {
902
+ const pk = (table.constraints || []).find((c) => c.constraint === "primary" && Array.isArray(c.columns) && c.columns.length > 0);
903
+ return pk ? pk.columns.map(String) : [];
904
+ }
905
+ function typeNameToHint(typname, isArray) {
906
+ if (!typname) return void 0;
907
+ const base = typname;
908
+ return isArray ? base + "[]" : base;
909
+ }
910
+ function addTypeHintForParam(typeHints, paramName, col, value) {
911
+ let isArr = col._is_array;
912
+ if (Array.isArray(value)) if (isArrayShapedGeomTypename(col._typname)) isArr = value.every(Array.isArray);
913
+ else isArr = true;
914
+ const hint = typeNameToHint(col._typname, isArr);
915
+ if (hint) typeHints[paramName] = hint;
916
+ }
917
+ function expectedScalarKind(typname) {
918
+ const t = typname.toLowerCase();
919
+ if (t === "int2" || t === "int4" || t === "int8" || t === "float4" || t === "float8") return "number";
920
+ if (t === "numeric" || t === "decimal") return "string";
921
+ if (t === "varchar" || t === "text" || t === "bpchar" || t === "char" || t === "date" || t === "time" || t === "timetz" || t === "timestamp" || t === "timestamptz") return "string";
922
+ if (t === "bool") return "boolean";
923
+ if (t === "json" || t === "jsonb") return "json";
924
+ if (t === "int4range" || t === "int8range" || t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "range";
925
+ if (t === "interval") return "interval";
926
+ if (t === "point" || t === "line" || t === "lseg" || t === "box" || t === "path" || t === "polygon" || t === "circle") return "geom";
927
+ return "unknown";
928
+ }
929
+ function isArrayShapedGeomTypename(typname) {
930
+ const t = typname.toLowerCase();
931
+ return t === "path" || t === "polygon";
932
+ }
933
+ function isArrayShapedGeomScalarValue(col, value) {
934
+ if (!Array.isArray(value)) return false;
935
+ if (!isArrayShapedGeomTypename(col._typname)) return false;
936
+ return !value.every(Array.isArray);
937
+ }
938
+ function expectedRangeInnerKind(typname) {
939
+ const t = typname.toLowerCase();
940
+ if (t === "int4range" || t === "int8range") return "number";
941
+ if (t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "string";
942
+ return "unknown";
943
+ }
944
+ function isPlainObject(v) {
945
+ return typeof v === "object" && v !== null && !Array.isArray(v);
946
+ }
947
+ function isFiniteNumber(n) {
948
+ return typeof n === "number" && Number.isFinite(n);
949
+ }
950
+ function isPointLike(v) {
951
+ if (!isPlainObject(v)) return false;
952
+ const x = v.x;
953
+ const y = v.y;
954
+ return isFiniteNumber(x) && isFiniteNumber(y);
955
+ }
956
+ function validateGeometryForColumn(col, value, context) {
957
+ const t = col._typname.toLowerCase();
958
+ if (t === "point") {
959
+ if (!isPointLike(value)) throw new Error(`Invalid value for ${context}. Expected Point { x: number, y: number }`);
960
+ return;
961
+ }
962
+ if (t === "line") {
963
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Line { A: number, B: number, C: number }`);
964
+ const A = value.A, B = value.B, C = value.C;
965
+ if (!isFiniteNumber(A) || !isFiniteNumber(B) || !isFiniteNumber(C)) throw new Error(`Invalid Line for ${context}. A, B, C must be finite numbers`);
966
+ return;
967
+ }
968
+ if (t === "lseg" || t === "box") {
969
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected ${t.toUpperCase()} { start: Point, end: Point }`);
970
+ const start = value.start;
971
+ const end = value.end;
972
+ if (!isPointLike(start) || !isPointLike(end)) throw new Error(`Invalid ${t} for ${context}. 'start' and 'end' must be Point { x, y }`);
973
+ return;
974
+ }
975
+ if (t === "path") {
976
+ if (!Array.isArray(value) || value.length < 1) throw new Error(`Invalid value for ${context}. Expected Path [isClosed: boolean, ...points: Point[]]`);
977
+ const [isClosed, ...points] = value;
978
+ if (typeof isClosed !== "boolean") throw new Error(`Invalid Path for ${context}. First element must be boolean (isClosed)`);
979
+ for (let i = 0; i < points.length; i++) if (!isPointLike(points[i])) throw new Error(`Invalid Path for ${context}. Element at index ${i + 1} must be Point { x, y }`);
980
+ return;
981
+ }
982
+ if (t === "polygon") {
983
+ if (!Array.isArray(value)) throw new Error(`Invalid value for ${context}. Expected Polygon as Point[]`);
984
+ for (let i = 0; i < value.length; i++) if (!isPointLike(value[i])) throw new Error(`Invalid Polygon for ${context}. Element at index ${i} must be Point { x, y }`);
985
+ return;
986
+ }
987
+ if (t === "circle") {
988
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Circle { center: Point, radius: number }`);
989
+ const center = value.center;
990
+ const radius = value.radius;
991
+ if (!isPointLike(center) || !isFiniteNumber(radius)) throw new Error(`Invalid Circle for ${context}. 'center' must be Point and 'radius' must be finite number`);
992
+ return;
993
+ }
812
994
  }
813
- if (kind === "range") {
814
- validateRangeForColumn(col, value, context);
815
- return;
995
+ function validateRangeForColumn(col, value, context) {
996
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected a range object for type ${col._typname}`);
997
+ const r = value;
998
+ const hasLower = Object.prototype.hasOwnProperty.call(r, "lower");
999
+ const hasUpper = Object.prototype.hasOwnProperty.call(r, "upper");
1000
+ const hasLi = Object.prototype.hasOwnProperty.call(r, "lowerInclusive");
1001
+ const hasUi = Object.prototype.hasOwnProperty.call(r, "upperInclusive");
1002
+ if (!hasLower || !hasUpper || !hasLi || !hasUi) throw new Error(`Invalid range for ${context}. Required properties: lower, upper, lowerInclusive, upperInclusive`);
1003
+ if (typeof r.lowerInclusive !== "boolean" || typeof r.upperInclusive !== "boolean") throw new Error(`Invalid range for ${context}. lowerInclusive and upperInclusive must be boolean`);
1004
+ const inner = expectedRangeInnerKind(col._typname);
1005
+ if (inner === "number") {
1006
+ if (typeof r.lower !== "number" || !Number.isFinite(r.lower)) throw new Error(`Invalid range.lower for ${context}. Expected number for type ${col._typname}`);
1007
+ if (typeof r.upper !== "number" || !Number.isFinite(r.upper)) throw new Error(`Invalid range.upper for ${context}. Expected number for type ${col._typname}`);
1008
+ } else if (inner === "string") {
1009
+ if (typeof r.lower !== "string") throw new Error(`Invalid range.lower for ${context}. Expected string for type ${col._typname}`);
1010
+ if (typeof r.upper !== "string") throw new Error(`Invalid range.upper for ${context}. Expected string for type ${col._typname}`);
1011
+ }
816
1012
  }
817
- if (kind === "interval") {
818
- validateIntervalForColumn(col, value, context);
819
- return;
1013
+ function validateIntervalForColumn(col, value, context) {
1014
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected an interval object for type ${col._typname}`);
1015
+ const v = value;
1016
+ for (const k of [
1017
+ "y",
1018
+ "m",
1019
+ "d",
1020
+ "h",
1021
+ "i",
1022
+ "s"
1023
+ ]) {
1024
+ if (!Object.prototype.hasOwnProperty.call(v, k)) throw new Error(`Invalid interval for ${context}. Missing property '${k}'`);
1025
+ const num = v[k];
1026
+ if (typeof num !== "number" || !Number.isFinite(num)) throw new Error(`Invalid interval.${String(k)} for ${context}. Expected finite number`);
1027
+ }
820
1028
  }
821
- if (kind === "geom") {
822
- validateGeometryForColumn(col, value, context);
823
- return;
1029
+ function isValidJsonLike(value) {
1030
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "object" && value !== null;
824
1031
  }
825
- }
826
- function validateComparisonValue(col, key, value, op) {
827
- if (value === void 0 || value === null) throw new Error(`Operator ${op} on column ${key} requires a non-null value. Use isnull/notnull for null checks.`);
828
- if (col._is_array) {
829
- if (!Array.isArray(value)) throw new Error(`Operator ${op} on array column ${key} requires an array value`);
830
- for (const [i, v] of value.entries()) validateScalarForColumn(col, v, `column ${key}[${i}]`);
831
- } else {
832
- if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) throw new Error(`Operator ${op} on scalar column ${key} cannot accept an array value`);
833
- validateScalarForColumn(col, value, `column ${key}`);
1032
+ function validateScalarForColumn(col, value, context) {
1033
+ const kind = expectedScalarKind(col._typname);
1034
+ if (kind === "unknown") return;
1035
+ if (kind === "number") {
1036
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`Invalid value for ${context}. Expected number for type ${col._typname}, got ${typeof value}`);
1037
+ return;
1038
+ }
1039
+ if (kind === "string") {
1040
+ if (typeof value !== "string") throw new Error(`Invalid value for ${context}. Expected string for type ${col._typname}, got ${typeof value}`);
1041
+ return;
1042
+ }
1043
+ if (kind === "boolean") {
1044
+ if (typeof value !== "boolean") throw new Error(`Invalid value for ${context}. Expected boolean for type ${col._typname}, got ${typeof value}`);
1045
+ return;
1046
+ }
1047
+ if (kind === "json") {
1048
+ if (!isValidJsonLike(value)) throw new Error(`Invalid value for ${context}. Expected JSON-compatible value for type ${col._typname}`);
1049
+ return;
1050
+ }
1051
+ if (kind === "range") {
1052
+ validateRangeForColumn(col, value, context);
1053
+ return;
1054
+ }
1055
+ if (kind === "interval") {
1056
+ validateIntervalForColumn(col, value, context);
1057
+ return;
1058
+ }
1059
+ if (kind === "geom") {
1060
+ validateGeometryForColumn(col, value, context);
1061
+ return;
1062
+ }
834
1063
  }
835
- }
836
- function validateInArrayValues(col, key, values, op) {
837
- if (!col._is_array) {
838
- let idx = 0;
839
- for (const v of values) {
840
- validateScalarForColumn(col, v, `column ${key} (element ${idx})`);
841
- idx++;
1064
+ function validateComparisonValue(col, key, value, op) {
1065
+ if (value === void 0 || value === null) throw new Error(`Operator ${op} on column ${key} requires a non-null value. Use isnull/notnull for null checks.`);
1066
+ if (col._is_array) {
1067
+ if (!Array.isArray(value)) throw new Error(`Operator ${op} on array column ${key} requires an array value`);
1068
+ for (const [i, v] of value.entries()) validateScalarForColumn(col, v, `column ${key}[${i}]`);
1069
+ } else {
1070
+ if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) throw new Error(`Operator ${op} on scalar column ${key} cannot accept an array value`);
1071
+ validateScalarForColumn(col, value, `column ${key}`);
842
1072
  }
843
1073
  }
844
- }
845
- function findJoinOn(base, target) {
846
- const bc = base.constraints || [];
847
- const tc = target.constraints || [];
848
- for (const c of bc) if (c.constraint === "foreign" && c.referenced_table === target.name && c.columns?.length && c.referenced_columns?.length && c.columns.length === c.referenced_columns.length) return c.columns.map((col, i) => ({
849
- left: String(col),
850
- right: String(c.referenced_columns[i])
851
- }));
852
- for (const c of tc) if (c.constraint === "foreign" && c.referenced_table === base.name && c.columns?.length && c.referenced_columns?.length && c.columns.length === c.referenced_columns.length) return c.referenced_columns.map((rcol, i) => ({
853
- left: String(rcol),
854
- right: String(c.columns[i])
855
- }));
856
- return null;
857
- }
858
- var TableQueryImpl = class {
859
- constructor(schema, tableName) {
860
- this.schema = schema;
861
- this.table = findTable(schema, tableName);
1074
+ function validateInArrayValues(col, key, values, op) {
1075
+ if (!col._is_array) {
1076
+ let idx = 0;
1077
+ for (const v of values) {
1078
+ validateScalarForColumn(col, v, `column ${key} (element ${idx})`);
1079
+ idx++;
1080
+ }
1081
+ }
862
1082
  }
863
- select(cols) {
864
- const table = this.table;
865
- const schema = this.schema;
866
- const selected = cols && cols.length ? cols : ["*"];
867
- const state = {
868
- table,
869
- selected,
870
- where: {},
871
- orWhereGroups: [],
872
- andOps: [],
873
- orOpGroups: [],
874
- order: [],
875
- limit: void 0,
876
- offset: void 0,
877
- joins: [],
878
- joinSelections: []
879
- };
880
- return new class {
881
- constructor() {
882
- this.s = state;
883
- this.toSql = () => {
884
- const params = {};
885
- const type_hints = {};
886
- let p = 0;
887
- const parts = [];
888
- const selectParts = [];
889
- if (selected.length === 1 && selected[0] === "*") selectParts.push(`"${table.name}".*`);
890
- else {
891
- const sel = selected;
892
- for (const c of sel) findColumn(table, String(c));
893
- selectParts.push(sel.map((c) => `"${table.name}"."${c}"`).join(", "));
894
- }
895
- for (const js of state.joinSelections) if (js.selected.length === 1 && js.selected[0] === "*") selectParts.push(`"${js.target.name}".*`);
896
- else {
897
- const cols$1 = js.selected;
898
- for (const c of cols$1) findColumn(js.target, String(c));
899
- selectParts.push(cols$1.map((c) => `"${js.target.name}"."${c}"`).join(", "));
900
- }
901
- parts.push(`select ${selectParts.join(", ")} from "${schema.name}"."${table.name}"`);
902
- for (const j of state.joins) {
903
- const onExpr = j.on.map((p$1) => `"${j.source.name}"."${p$1.left}" = "${j.target.name}"."${p$1.right}"`).join(" and ");
904
- parts.push(`${j.type} join "${schema.name}"."${j.target.name}" on ${onExpr}`);
905
- }
906
- const andParts = [];
907
- for (const key in state.where) {
908
- const value = state.where[key];
909
- const col = findColumn(table, key);
910
- p += 1;
911
- const paramName = `${table.name}_${key}_${p}`;
912
- if (value === null) {
913
- if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
914
- andParts.push(`"${table.name}"."${key}" is null`);
915
- } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
916
- validateInArrayValues(col, key, value, "in");
917
- andParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
918
- params[paramName] = value;
919
- addTypeHintForParam(type_hints, paramName, col, value);
920
- } else {
921
- validateScalarForColumn(col, value, `column ${key}`);
922
- andParts.push(`"${table.name}"."${key}" = :${paramName}`);
923
- params[paramName] = value;
924
- addTypeHintForParam(type_hints, paramName, col, value);
1083
+ function findJoinOn(base, target) {
1084
+ const bc = base.constraints || [];
1085
+ const tc = target.constraints || [];
1086
+ for (const c of bc) if (c.constraint === "foreign" && c.referenced_table === target.name && c.columns?.length && c.referenced_columns?.length && c.columns.length === c.referenced_columns.length) return c.columns.map((col, i) => ({
1087
+ left: String(col),
1088
+ right: String(c.referenced_columns[i])
1089
+ }));
1090
+ for (const c of tc) if (c.constraint === "foreign" && c.referenced_table === base.name && c.columns?.length && c.referenced_columns?.length && c.columns.length === c.referenced_columns.length) return c.referenced_columns.map((rcol, i) => ({
1091
+ left: String(rcol),
1092
+ right: String(c.columns[i])
1093
+ }));
1094
+ return null;
1095
+ }
1096
+ var TableQueryImpl = class {
1097
+ constructor(schema, tableName) {
1098
+ this.schema = schema;
1099
+ this.table = findTable(schema, tableName);
1100
+ }
1101
+ select(cols) {
1102
+ const table = this.table;
1103
+ const schema = this.schema;
1104
+ const selected = cols && cols.length ? cols : ["*"];
1105
+ const state = {
1106
+ table,
1107
+ selected,
1108
+ where: {},
1109
+ orWhereGroups: [],
1110
+ andOps: [],
1111
+ orOpGroups: [],
1112
+ order: [],
1113
+ limit: void 0,
1114
+ offset: void 0,
1115
+ joins: [],
1116
+ joinSelections: []
1117
+ };
1118
+ return new class {
1119
+ constructor() {
1120
+ this.s = state;
1121
+ this.toSql = () => {
1122
+ const params = {};
1123
+ const type_hints = {};
1124
+ let p = 0;
1125
+ const parts = [];
1126
+ const selectParts = [];
1127
+ if (selected.length === 1 && selected[0] === "*") selectParts.push(`"${table.name}".*`);
1128
+ else {
1129
+ const sel = selected;
1130
+ for (const c of sel) findColumn(table, String(c));
1131
+ selectParts.push(sel.map((c) => `"${table.name}"."${c}"`).join(", "));
925
1132
  }
926
- }
927
- for (const pred of state.andOps) {
928
- const key = String(pred.col);
929
- const op = String(pred.op);
930
- const col = findColumn(table, key);
931
- const qualified = `"${table.name}"."${key}"`;
932
- if (op === "isnull" || op === "notnull") {
933
- if (pred.value !== void 0) throw new Error(`Operator ${op} does not take a value for column ${key}`);
934
- andParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
935
- } else if (op === "in" || op === "notin") {
936
- const val = pred.value;
937
- if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
938
- validateInArrayValues(col, key, val, op);
939
- p += 1;
940
- const paramName = `${table.name}_${key}_${p}`;
941
- andParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
942
- params[paramName] = val;
943
- addTypeHintForParam(type_hints, paramName, col, val);
944
- } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
945
- const val = pred.value;
946
- if (typeof val !== "string") throw new Error(`Operator ${op} requires a string value for column ${key}`);
947
- p += 1;
948
- const paramName = `${table.name}_${key}_${p}`;
949
- const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
950
- andParts.push(`${qualified} ${sqlOp} :${paramName}`);
951
- params[paramName] = val;
952
- addTypeHintForParam(type_hints, paramName, col, val);
953
- } else {
954
- const val = pred.value;
955
- if (val === void 0) throw new Error(`Operator ${op} requires a value for column ${key}`);
956
- validateComparisonValue(col, key, val, op);
957
- p += 1;
958
- const paramName = `${table.name}_${key}_${p}`;
959
- if (op === "=") andParts.push(`${qualified} = :${paramName}`);
960
- else if (op === "!=") andParts.push(`${qualified} <> :${paramName}`);
961
- else if (op === "<" || op === "<=" || op === ">" || op === ">=") andParts.push(`${qualified} ${op} :${paramName}`);
962
- else throw new Error(`Unsupported operator: ${op}`);
963
- params[paramName] = val;
964
- addTypeHintForParam(type_hints, paramName, col, val);
1133
+ for (const js of state.joinSelections) if (js.selected.length === 1 && js.selected[0] === "*") selectParts.push(`"${js.target.name}".*`);
1134
+ else {
1135
+ const cols$1 = js.selected;
1136
+ for (const c of cols$1) findColumn(js.target, String(c));
1137
+ selectParts.push(cols$1.map((c) => `"${js.target.name}"."${c}"`).join(", "));
965
1138
  }
966
- }
967
- const orGroupSql = [];
968
- for (const group of state.orWhereGroups) {
969
- const orParts = [];
970
- for (const key in group) {
971
- const value = group[key];
1139
+ parts.push(`select ${selectParts.join(", ")} from "${schema.name}"."${table.name}"`);
1140
+ for (const j of state.joins) {
1141
+ const onExpr = j.on.map((p$1) => `"${j.source.name}"."${p$1.left}" = "${j.target.name}"."${p$1.right}"`).join(" and ");
1142
+ parts.push(`${j.type} join "${schema.name}"."${j.target.name}" on ${onExpr}`);
1143
+ }
1144
+ const andParts = [];
1145
+ for (const key in state.where) {
1146
+ const value = state.where[key];
972
1147
  const col = findColumn(table, key);
973
1148
  p += 1;
974
1149
  const paramName = `${table.name}_${key}_${p}`;
975
1150
  if (value === null) {
976
1151
  if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
977
- orParts.push(`"${table.name}"."${key}" is null`);
1152
+ andParts.push(`"${table.name}"."${key}" is null`);
978
1153
  } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
979
1154
  validateInArrayValues(col, key, value, "in");
980
- orParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
1155
+ andParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
981
1156
  params[paramName] = value;
982
1157
  addTypeHintForParam(type_hints, paramName, col, value);
983
1158
  } else {
984
1159
  validateScalarForColumn(col, value, `column ${key}`);
985
- orParts.push(`"${table.name}"."${key}" = :${paramName}`);
1160
+ andParts.push(`"${table.name}"."${key}" = :${paramName}`);
986
1161
  params[paramName] = value;
987
1162
  addTypeHintForParam(type_hints, paramName, col, value);
988
1163
  }
989
1164
  }
990
- if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
991
- }
992
- for (const group of state.orOpGroups) {
993
- const orParts = [];
994
- for (const pred of group) {
1165
+ for (const pred of state.andOps) {
995
1166
  const key = String(pred.col);
996
1167
  const op = String(pred.op);
997
1168
  const col = findColumn(table, key);
998
1169
  const qualified = `"${table.name}"."${key}"`;
999
1170
  if (op === "isnull" || op === "notnull") {
1000
1171
  if (pred.value !== void 0) throw new Error(`Operator ${op} does not take a value for column ${key}`);
1001
- orParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1172
+ andParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1002
1173
  } else if (op === "in" || op === "notin") {
1003
1174
  const val = pred.value;
1004
1175
  if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
1005
1176
  validateInArrayValues(col, key, val, op);
1006
1177
  p += 1;
1007
1178
  const paramName = `${table.name}_${key}_${p}`;
1008
- orParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1179
+ andParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1009
1180
  params[paramName] = val;
1010
1181
  addTypeHintForParam(type_hints, paramName, col, val);
1011
1182
  } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
@@ -1014,7 +1185,7 @@ var TableQueryImpl = class {
1014
1185
  p += 1;
1015
1186
  const paramName = `${table.name}_${key}_${p}`;
1016
1187
  const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
1017
- orParts.push(`${qualified} ${sqlOp} :${paramName}`);
1188
+ andParts.push(`${qualified} ${sqlOp} :${paramName}`);
1018
1189
  params[paramName] = val;
1019
1190
  addTypeHintForParam(type_hints, paramName, col, val);
1020
1191
  } else {
@@ -1023,252 +1194,137 @@ var TableQueryImpl = class {
1023
1194
  validateComparisonValue(col, key, val, op);
1024
1195
  p += 1;
1025
1196
  const paramName = `${table.name}_${key}_${p}`;
1026
- if (op === "=") orParts.push(`${qualified} = :${paramName}`);
1027
- else if (op === "!=") orParts.push(`${qualified} <> :${paramName}`);
1028
- else if (op === "<" || op === "<=" || op === ">" || op === ">=") orParts.push(`${qualified} ${op} :${paramName}`);
1197
+ if (op === "=") andParts.push(`${qualified} = :${paramName}`);
1198
+ else if (op === "!=") andParts.push(`${qualified} <> :${paramName}`);
1199
+ else if (op === "<" || op === "<=" || op === ">" || op === ">=") andParts.push(`${qualified} ${op} :${paramName}`);
1029
1200
  else throw new Error(`Unsupported operator: ${op}`);
1030
1201
  params[paramName] = val;
1031
1202
  addTypeHintForParam(type_hints, paramName, col, val);
1032
1203
  }
1033
1204
  }
1034
- if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
1035
- }
1036
- if (orGroupSql.length) {
1037
- const andSql = andParts.length ? `(${andParts.join(" and ")})` : "";
1038
- const orSql = orGroupSql.join(" or ");
1039
- const full = andSql ? `${andSql} or ${orSql}` : orSql;
1040
- if (full.trim().length) parts.push("where " + full);
1041
- } else if (andParts.length) parts.push("where " + andParts.join(" and "));
1042
- if (state.order.length) {
1043
- const orders = [];
1044
- for (const o of state.order) orders.push(`"${table.name}"."${o.col}" ${o.dir}`);
1045
- parts.push("order by " + orders.join(", "));
1046
- }
1047
- if (state.limit !== void 0) parts.push("limit " + state.limit);
1048
- if (state.offset !== void 0) parts.push("offset " + state.offset);
1049
- return {
1050
- q: parts.join(" "),
1051
- params: Object.keys(params).length > 0 ? params : void 0,
1052
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1205
+ const orGroupSql = [];
1206
+ for (const group of state.orWhereGroups) {
1207
+ const orParts = [];
1208
+ for (const key in group) {
1209
+ const value = group[key];
1210
+ const col = findColumn(table, key);
1211
+ p += 1;
1212
+ const paramName = `${table.name}_${key}_${p}`;
1213
+ if (value === null) {
1214
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1215
+ orParts.push(`"${table.name}"."${key}" is null`);
1216
+ } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1217
+ validateInArrayValues(col, key, value, "in");
1218
+ orParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
1219
+ params[paramName] = value;
1220
+ addTypeHintForParam(type_hints, paramName, col, value);
1221
+ } else {
1222
+ validateScalarForColumn(col, value, `column ${key}`);
1223
+ orParts.push(`"${table.name}"."${key}" = :${paramName}`);
1224
+ params[paramName] = value;
1225
+ addTypeHintForParam(type_hints, paramName, col, value);
1226
+ }
1227
+ }
1228
+ if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
1229
+ }
1230
+ for (const group of state.orOpGroups) {
1231
+ const orParts = [];
1232
+ for (const pred of group) {
1233
+ const key = String(pred.col);
1234
+ const op = String(pred.op);
1235
+ const col = findColumn(table, key);
1236
+ const qualified = `"${table.name}"."${key}"`;
1237
+ if (op === "isnull" || op === "notnull") {
1238
+ if (pred.value !== void 0) throw new Error(`Operator ${op} does not take a value for column ${key}`);
1239
+ orParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1240
+ } else if (op === "in" || op === "notin") {
1241
+ const val = pred.value;
1242
+ if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
1243
+ validateInArrayValues(col, key, val, op);
1244
+ p += 1;
1245
+ const paramName = `${table.name}_${key}_${p}`;
1246
+ orParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1247
+ params[paramName] = val;
1248
+ addTypeHintForParam(type_hints, paramName, col, val);
1249
+ } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
1250
+ const val = pred.value;
1251
+ if (typeof val !== "string") throw new Error(`Operator ${op} requires a string value for column ${key}`);
1252
+ p += 1;
1253
+ const paramName = `${table.name}_${key}_${p}`;
1254
+ const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
1255
+ orParts.push(`${qualified} ${sqlOp} :${paramName}`);
1256
+ params[paramName] = val;
1257
+ addTypeHintForParam(type_hints, paramName, col, val);
1258
+ } else {
1259
+ const val = pred.value;
1260
+ if (val === void 0) throw new Error(`Operator ${op} requires a value for column ${key}`);
1261
+ validateComparisonValue(col, key, val, op);
1262
+ p += 1;
1263
+ const paramName = `${table.name}_${key}_${p}`;
1264
+ if (op === "=") orParts.push(`${qualified} = :${paramName}`);
1265
+ else if (op === "!=") orParts.push(`${qualified} <> :${paramName}`);
1266
+ else if (op === "<" || op === "<=" || op === ">" || op === ">=") orParts.push(`${qualified} ${op} :${paramName}`);
1267
+ else throw new Error(`Unsupported operator: ${op}`);
1268
+ params[paramName] = val;
1269
+ addTypeHintForParam(type_hints, paramName, col, val);
1270
+ }
1271
+ }
1272
+ if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
1273
+ }
1274
+ if (orGroupSql.length) {
1275
+ const andSql = andParts.length ? `(${andParts.join(" and ")})` : "";
1276
+ const orSql = orGroupSql.join(" or ");
1277
+ const full = andSql ? `${andSql} or ${orSql}` : orSql;
1278
+ if (full.trim().length) parts.push("where " + full);
1279
+ } else if (andParts.length) parts.push("where " + andParts.join(" and "));
1280
+ if (state.order.length) {
1281
+ const orders = [];
1282
+ for (const o of state.order) orders.push(`"${table.name}"."${o.col}" ${o.dir}`);
1283
+ parts.push("order by " + orders.join(", "));
1284
+ }
1285
+ if (state.limit !== void 0) parts.push("limit " + state.limit);
1286
+ if (state.offset !== void 0) parts.push("offset " + state.offset);
1287
+ return {
1288
+ q: parts.join(" "),
1289
+ params: Object.keys(params).length > 0 ? params : void 0,
1290
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1291
+ };
1053
1292
  };
1054
- };
1055
- }
1056
- selectFrom(tableName, cols$1) {
1057
- const jtName = String(tableName);
1058
- const join = this.s.joins.find((j) => j.target.name === jtName);
1059
- if (!join) throw new Error(`selectFrom('${jtName}') requires a prior join('${jtName}') call`);
1060
- const sel = !cols$1 || cols$1.length === 0 ? ["*"] : cols$1.map(String);
1061
- if (!(sel.length === 1 && sel[0] === "*")) for (const c of sel) findColumn(join.target, String(c));
1062
- const existing = this.s.joinSelections.find((js) => js.target.name === jtName);
1063
- if (existing) {
1064
- if (existing.selected.includes("*")) return this;
1065
- if (sel.length === 1 && sel[0] === "*") existing.selected = ["*"];
1066
- else {
1067
- const set = new Set(existing.selected);
1068
- for (const c of sel) set.add(String(c));
1069
- existing.selected = Array.from(set);
1070
- }
1071
- } else this.s.joinSelections.push({
1072
- target: join.target,
1073
- selected: sel
1074
- });
1075
- return this;
1076
- }
1077
- andWhere(where) {
1078
- for (const k in where) this.s.where[k] = where[k];
1079
- return this;
1080
- }
1081
- /** @deprecated Use andWhere() instead */
1082
- where(where) {
1083
- return this.andWhere(where);
1084
- }
1085
- orWhere(where) {
1086
- this.s.orWhereGroups.push(where);
1087
- return this;
1088
- }
1089
- wherePk(pk) {
1090
- const pkCols = getPrimaryKeyColumns(table);
1091
- if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1092
- if (pkCols.length === 1) {
1093
- const colName = pkCols[0];
1094
- const colDef = findColumn(table, colName);
1095
- if (pk === null || pk === void 0) throw new Error(`wherePk on ${table.name} requires a non-null value for primary key column ${colName}`);
1096
- if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1097
- if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1098
- validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1099
- this.s.where[colName] = pk;
1100
- return this;
1101
- } else {
1102
- if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1103
- const obj = pk;
1104
- for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1105
- for (const colName of pkCols) {
1106
- if (!(colName in obj)) throw new Error(`wherePk missing key '${colName}'. Required keys: ${pkCols.join(", ")}`);
1107
- const v = obj[colName];
1108
- if (v === null || v === void 0) throw new Error(`wherePk on ${table.name} requires non-null values for all primary key columns (${pkCols.join(", ")})`);
1109
- if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1110
- validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1111
- this.s.where[colName] = v;
1112
- }
1113
- return this;
1114
1293
  }
1115
- }
1116
- andWhereOp(col, op, ...args) {
1117
- const value = args[0];
1118
- this.s.andOps.push({
1119
- col,
1120
- op,
1121
- value
1122
- });
1123
- return this;
1124
- }
1125
- orWhereOp(col, op, ...args) {
1126
- const value = args[0];
1127
- this.s.orOpGroups.push([{
1128
- col,
1129
- op,
1130
- value
1131
- }]);
1132
- return this;
1133
- }
1134
- andWhereOpGroup(predicates) {
1135
- const group = predicates.map((p) => ({
1136
- col: p[0],
1137
- op: p[1],
1138
- value: p[2]
1139
- }));
1140
- for (const g of group) this.s.andOps.push(g);
1141
- return this;
1142
- }
1143
- orWhereOpGroup(predicates) {
1144
- const group = predicates.map((p) => ({
1145
- col: p[0],
1146
- op: p[1],
1147
- value: p[2]
1148
- }));
1149
- this.s.orOpGroups.push(group);
1150
- return this;
1151
- }
1152
- orderBy(order) {
1153
- this.s.order = [];
1154
- const isValidDir = (d) => d === "asc" || d === "desc";
1155
- if (typeof order === "string") {
1156
- findColumn(table, String(order));
1157
- this.s.order.push({
1158
- col: order,
1159
- dir: "asc"
1160
- });
1161
- } else for (const item of order) {
1162
- const col = String(item[0]);
1163
- const dir = String(item[1]);
1164
- findColumn(table, col);
1165
- if (!isValidDir(dir)) throw new Error(`Invalid order direction: ${dir}. Allowed: asc | desc`);
1166
- this.s.order.push({
1167
- col: item[0],
1168
- dir
1294
+ selectFrom(tableName, cols$1) {
1295
+ const jtName = String(tableName);
1296
+ const join = this.s.joins.find((j) => j.target.name === jtName);
1297
+ if (!join) throw new Error(`selectFrom('${jtName}') requires a prior join('${jtName}') call`);
1298
+ const sel = !cols$1 || cols$1.length === 0 ? ["*"] : cols$1.map(String);
1299
+ if (!(sel.length === 1 && sel[0] === "*")) for (const c of sel) findColumn(join.target, String(c));
1300
+ const existing = this.s.joinSelections.find((js) => js.target.name === jtName);
1301
+ if (existing) {
1302
+ if (existing.selected.includes("*")) return this;
1303
+ if (sel.length === 1 && sel[0] === "*") existing.selected = ["*"];
1304
+ else {
1305
+ const set = new Set(existing.selected);
1306
+ for (const c of sel) set.add(String(c));
1307
+ existing.selected = Array.from(set);
1308
+ }
1309
+ } else this.s.joinSelections.push({
1310
+ target: join.target,
1311
+ selected: sel
1169
1312
  });
1313
+ return this;
1170
1314
  }
1171
- return this;
1172
- }
1173
- limit(n) {
1174
- if (typeof n !== "number" || !Number.isFinite(n) || !Number.isInteger(n) || n < 0) throw new Error(`Invalid limit: ${n}. Limit must be a non-negative integer`);
1175
- this.s.limit = n;
1176
- return this;
1177
- }
1178
- offset(n) {
1179
- if (typeof n !== "number" || !Number.isFinite(n) || !Number.isInteger(n) || n < 0) throw new Error(`Invalid offset: ${n}. Offset must be a non-negative integer`);
1180
- this.s.offset = n;
1181
- return this;
1182
- }
1183
- join(tableName, type = "inner") {
1184
- const target = findTable(schema, String(tableName));
1185
- const sources = [];
1186
- for (let i = this.s.joins.length - 1; i >= 0; i--) {
1187
- const src = this.s.joins[i].target;
1188
- if (!sources.some((s) => s.name === src.name)) sources.push(src);
1189
- }
1190
- if (!sources.some((s) => s.name === table.name)) sources.push(table);
1191
- let pickedSource = null;
1192
- let pairs = null;
1193
- for (const src of sources) {
1194
- const p = findJoinOn(src, target);
1195
- if (p && p.length) {
1196
- pickedSource = src;
1197
- pairs = p;
1198
- break;
1199
- }
1200
- }
1201
- if (!pairs || !pickedSource) {
1202
- const candidates = sources.map((s) => s.name).join(", ");
1203
- throw new Error(`No foreign key relation found between any of [${candidates}] and ${target.name}`);
1315
+ andWhere(where) {
1316
+ for (const k in where) this.s.where[k] = where[k];
1317
+ return this;
1204
1318
  }
1205
- const jt = String(type);
1206
- if (jt !== "inner" && jt !== "left" && jt !== "right" && jt !== "full") throw new Error(`Invalid join type: ${jt}. Allowed: inner | left | right | full`);
1207
- this.s.joins.push({
1208
- type: jt,
1209
- source: pickedSource,
1210
- target,
1211
- on: pairs
1212
- });
1213
- return this;
1214
- }
1215
- }();
1216
- }
1217
- insert(values) {
1218
- const table = this.table;
1219
- const schema = this.schema;
1220
- const state = {
1221
- values,
1222
- returning: []
1223
- };
1224
- return new class {
1225
- returning(cols) {
1226
- state.returning = cols || [];
1227
- return this;
1228
- }
1229
- toSql() {
1230
- const colsArr = [];
1231
- const vals = [];
1232
- const params = {};
1233
- const type_hints = {};
1234
- let p = 0;
1235
- for (const key in state.values) {
1236
- const value = state.values[key];
1237
- const col = findColumn(table, key);
1238
- p += 1;
1239
- const paramName = `${table.name}_${key}_${p}`;
1240
- colsArr.push(`"${key}"`);
1241
- vals.push(`:${paramName}`);
1242
- params[paramName] = value;
1243
- addTypeHintForParam(type_hints, paramName, col, value);
1319
+ /** @deprecated Use andWhere() instead */
1320
+ where(where) {
1321
+ return this.andWhere(where);
1244
1322
  }
1245
- const parts = [];
1246
- parts.push(`insert into "${schema.name}"."${table.name}" (${colsArr.join(", ")}) values (${vals.join(", ")})`);
1247
- if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1248
- const req = {
1249
- q: parts.join(" "),
1250
- params: Object.keys(params).length > 0 ? params : void 0,
1251
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1252
- };
1253
- return state.returning.length ? req : req;
1254
- }
1255
- }();
1256
- }
1257
- update(values) {
1258
- const table = this.table;
1259
- const schema = this.schema;
1260
- const state = {
1261
- values,
1262
- where: {},
1263
- returning: []
1264
- };
1265
- return new class {
1266
- constructor() {
1267
- this.where = (w) => {
1268
- for (const k in w) state.where[k] = w[k];
1323
+ orWhere(where) {
1324
+ this.s.orWhereGroups.push(where);
1269
1325
  return this;
1270
- };
1271
- this.wherePk = (pk) => {
1326
+ }
1327
+ wherePk(pk) {
1272
1328
  const pkCols = getPrimaryKeyColumns(table);
1273
1329
  if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1274
1330
  if (pkCols.length === 1) {
@@ -1278,7 +1334,8 @@ var TableQueryImpl = class {
1278
1334
  if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1279
1335
  if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1280
1336
  validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1281
- state.where[colName] = pk;
1337
+ this.s.where[colName] = pk;
1338
+ return this;
1282
1339
  } else {
1283
1340
  if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1284
1341
  const obj = pk;
@@ -1289,146 +1346,884 @@ var TableQueryImpl = class {
1289
1346
  if (v === null || v === void 0) throw new Error(`wherePk on ${table.name} requires non-null values for all primary key columns (${pkCols.join(", ")})`);
1290
1347
  if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1291
1348
  validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1292
- state.where[colName] = v;
1349
+ this.s.where[colName] = v;
1293
1350
  }
1351
+ return this;
1294
1352
  }
1353
+ }
1354
+ andWhereOp(col, op, ...args) {
1355
+ const value = args[0];
1356
+ this.s.andOps.push({
1357
+ col,
1358
+ op,
1359
+ value
1360
+ });
1295
1361
  return this;
1296
- };
1297
- }
1298
- returning(cols) {
1299
- state.returning = cols || [];
1300
- return this;
1301
- }
1302
- toSql() {
1303
- const params = {};
1304
- const type_hints = {};
1305
- let p = 0;
1306
- const setParts = [];
1307
- for (const key in state.values) {
1308
- const value = state.values[key];
1309
- const col = findColumn(table, key);
1310
- p += 1;
1311
- const paramName = `${table.name}_${key}_${p}`;
1312
- setParts.push(`"${key}" = :${paramName}`);
1313
- params[paramName] = value;
1314
- addTypeHintForParam(type_hints, paramName, col, value);
1315
1362
  }
1316
- const whereClauses = [];
1317
- for (const key in state.where) {
1318
- const value = state.where[key];
1319
- const col = findColumn(table, key);
1320
- p += 1;
1321
- const paramName = `${table.name}_${key}_${p}`;
1322
- if (value === null) {
1323
- if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1324
- whereClauses.push(`"${key}" is null`);
1325
- } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1326
- validateInArrayValues(col, key, value, "in");
1327
- whereClauses.push(`"${key}" = ANY(:${paramName})`);
1328
- params[paramName] = value;
1329
- addTypeHintForParam(type_hints, paramName, col, value);
1330
- } else {
1331
- validateScalarForColumn(col, value, `column ${key}`);
1332
- whereClauses.push(`"${key}" = :${paramName}`);
1333
- params[paramName] = value;
1334
- addTypeHintForParam(type_hints, paramName, col, value);
1363
+ orWhereOp(col, op, ...args) {
1364
+ const value = args[0];
1365
+ this.s.orOpGroups.push([{
1366
+ col,
1367
+ op,
1368
+ value
1369
+ }]);
1370
+ return this;
1371
+ }
1372
+ andWhereOpGroup(predicates) {
1373
+ const group = predicates.map((p) => ({
1374
+ col: p[0],
1375
+ op: p[1],
1376
+ value: p[2]
1377
+ }));
1378
+ for (const g of group) this.s.andOps.push(g);
1379
+ return this;
1380
+ }
1381
+ orWhereOpGroup(predicates) {
1382
+ const group = predicates.map((p) => ({
1383
+ col: p[0],
1384
+ op: p[1],
1385
+ value: p[2]
1386
+ }));
1387
+ this.s.orOpGroups.push(group);
1388
+ return this;
1389
+ }
1390
+ orderBy(order) {
1391
+ this.s.order = [];
1392
+ const isValidDir = (d) => d === "asc" || d === "desc";
1393
+ if (typeof order === "string") {
1394
+ findColumn(table, String(order));
1395
+ this.s.order.push({
1396
+ col: order,
1397
+ dir: "asc"
1398
+ });
1399
+ } else for (const item of order) {
1400
+ const col = String(item[0]);
1401
+ const dir = String(item[1]);
1402
+ findColumn(table, col);
1403
+ if (!isValidDir(dir)) throw new Error(`Invalid order direction: ${dir}. Allowed: asc | desc`);
1404
+ this.s.order.push({
1405
+ col: item[0],
1406
+ dir
1407
+ });
1335
1408
  }
1409
+ return this;
1336
1410
  }
1337
- const parts = [];
1338
- parts.push(`update "${schema.name}"."${table.name}" set ${setParts.join(", ")}`);
1339
- if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1340
- if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1341
- const req = {
1342
- q: parts.join(" "),
1343
- params: Object.keys(params).length > 0 ? params : void 0,
1344
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1345
- };
1346
- return state.returning.length ? req : req;
1347
- }
1348
- }();
1349
- }
1350
- delete() {
1351
- const table = this.table;
1352
- const schema = this.schema;
1353
- const state = {
1354
- where: {},
1355
- returning: []
1356
- };
1357
- return new class {
1358
- constructor() {
1359
- this.where = (w) => {
1360
- for (const k in w) state.where[k] = w[k];
1411
+ limit(n) {
1412
+ if (typeof n !== "number" || !Number.isFinite(n) || !Number.isInteger(n) || n < 0) throw new Error(`Invalid limit: ${n}. Limit must be a non-negative integer`);
1413
+ this.s.limit = n;
1361
1414
  return this;
1362
- };
1363
- this.wherePk = (pk) => {
1364
- const pkCols = getPrimaryKeyColumns(table);
1365
- if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1366
- if (pkCols.length === 1) {
1367
- const col = pkCols[0];
1368
- if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${col}`);
1369
- state.where[col] = pk;
1370
- } else {
1371
- if (!isPlainObject(pk)) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1372
- const obj = pk;
1373
- for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1374
- for (const col of pkCols) {
1375
- if (!(col in obj)) throw new Error(`wherePk missing key '${col}'. Required keys: ${pkCols.join(", ")}`);
1376
- state.where[col] = obj[col];
1415
+ }
1416
+ offset(n) {
1417
+ if (typeof n !== "number" || !Number.isFinite(n) || !Number.isInteger(n) || n < 0) throw new Error(`Invalid offset: ${n}. Offset must be a non-negative integer`);
1418
+ this.s.offset = n;
1419
+ return this;
1420
+ }
1421
+ join(tableName, type = "inner") {
1422
+ const target = findTable(schema, String(tableName));
1423
+ const sources = [];
1424
+ for (let i = this.s.joins.length - 1; i >= 0; i--) {
1425
+ const src = this.s.joins[i].target;
1426
+ if (!sources.some((s) => s.name === src.name)) sources.push(src);
1427
+ }
1428
+ if (!sources.some((s) => s.name === table.name)) sources.push(table);
1429
+ let pickedSource = null;
1430
+ let pairs = null;
1431
+ for (const src of sources) {
1432
+ const p = findJoinOn(src, target);
1433
+ if (p && p.length) {
1434
+ pickedSource = src;
1435
+ pairs = p;
1436
+ break;
1377
1437
  }
1378
1438
  }
1439
+ if (!pairs || !pickedSource) {
1440
+ const candidates = sources.map((s) => s.name).join(", ");
1441
+ throw new Error(`No foreign key relation found between any of [${candidates}] and ${target.name}`);
1442
+ }
1443
+ const jt = String(type);
1444
+ if (jt !== "inner" && jt !== "left" && jt !== "right" && jt !== "full") throw new Error(`Invalid join type: ${jt}. Allowed: inner | left | right | full`);
1445
+ this.s.joins.push({
1446
+ type: jt,
1447
+ source: pickedSource,
1448
+ target,
1449
+ on: pairs
1450
+ });
1379
1451
  return this;
1380
- };
1381
- }
1382
- returning(cols) {
1383
- state.returning = cols || [];
1384
- return this;
1385
- }
1386
- toSql() {
1387
- const params = {};
1388
- const type_hints = {};
1389
- let p = 0;
1390
- const whereClauses = [];
1391
- for (const key in state.where) {
1392
- const value = state.where[key];
1393
- const col = findColumn(table, key);
1394
- p += 1;
1395
- const paramName = `${table.name}_${key}_${p}`;
1396
- if (value === null) {
1397
- if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1398
- whereClauses.push(`"${key}" is null`);
1399
- } else if (Array.isArray(value)) {
1400
- validateInArrayValues(col, key, value, "in");
1401
- whereClauses.push(`"${key}" = ANY(:${paramName})`);
1452
+ }
1453
+ }();
1454
+ }
1455
+ insert(values) {
1456
+ const table = this.table;
1457
+ const schema = this.schema;
1458
+ const state = {
1459
+ values,
1460
+ returning: []
1461
+ };
1462
+ return new class {
1463
+ returning(cols) {
1464
+ state.returning = cols || [];
1465
+ return this;
1466
+ }
1467
+ toSql() {
1468
+ const colsArr = [];
1469
+ const vals = [];
1470
+ const params = {};
1471
+ const type_hints = {};
1472
+ let p = 0;
1473
+ for (const key in state.values) {
1474
+ const value = state.values[key];
1475
+ const col = findColumn(table, key);
1476
+ p += 1;
1477
+ const paramName = `${table.name}_${key}_${p}`;
1478
+ colsArr.push(`"${key}"`);
1479
+ vals.push(`:${paramName}`);
1402
1480
  params[paramName] = value;
1403
1481
  addTypeHintForParam(type_hints, paramName, col, value);
1404
- } else {
1405
- validateScalarForColumn(col, value, `column ${key}`);
1406
- whereClauses.push(`"${key}" = :${paramName}`);
1482
+ }
1483
+ const parts = [];
1484
+ parts.push(`insert into "${schema.name}"."${table.name}" (${colsArr.join(", ")}) values (${vals.join(", ")})`);
1485
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1486
+ const req = {
1487
+ q: parts.join(" "),
1488
+ params: Object.keys(params).length > 0 ? params : void 0,
1489
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1490
+ };
1491
+ return state.returning.length ? req : req;
1492
+ }
1493
+ }();
1494
+ }
1495
+ update(values) {
1496
+ const table = this.table;
1497
+ const schema = this.schema;
1498
+ const state = {
1499
+ values,
1500
+ where: {},
1501
+ returning: []
1502
+ };
1503
+ return new class {
1504
+ constructor() {
1505
+ this.where = (w) => {
1506
+ for (const k in w) state.where[k] = w[k];
1507
+ return this;
1508
+ };
1509
+ this.wherePk = (pk) => {
1510
+ const pkCols = getPrimaryKeyColumns(table);
1511
+ if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1512
+ if (pkCols.length === 1) {
1513
+ const colName = pkCols[0];
1514
+ const colDef = findColumn(table, colName);
1515
+ if (pk === null || pk === void 0) throw new Error(`wherePk on ${table.name} requires a non-null value for primary key column ${colName}`);
1516
+ if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1517
+ if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1518
+ validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1519
+ state.where[colName] = pk;
1520
+ } else {
1521
+ if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1522
+ const obj = pk;
1523
+ for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1524
+ for (const colName of pkCols) {
1525
+ if (!(colName in obj)) throw new Error(`wherePk missing key '${colName}'. Required keys: ${pkCols.join(", ")}`);
1526
+ const v = obj[colName];
1527
+ if (v === null || v === void 0) throw new Error(`wherePk on ${table.name} requires non-null values for all primary key columns (${pkCols.join(", ")})`);
1528
+ if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1529
+ validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1530
+ state.where[colName] = v;
1531
+ }
1532
+ }
1533
+ return this;
1534
+ };
1535
+ }
1536
+ returning(cols) {
1537
+ state.returning = cols || [];
1538
+ return this;
1539
+ }
1540
+ toSql() {
1541
+ const params = {};
1542
+ const type_hints = {};
1543
+ let p = 0;
1544
+ const setParts = [];
1545
+ for (const key in state.values) {
1546
+ const value = state.values[key];
1547
+ const col = findColumn(table, key);
1548
+ p += 1;
1549
+ const paramName = `${table.name}_${key}_${p}`;
1550
+ setParts.push(`"${key}" = :${paramName}`);
1407
1551
  params[paramName] = value;
1408
1552
  addTypeHintForParam(type_hints, paramName, col, value);
1409
1553
  }
1554
+ const whereClauses = [];
1555
+ for (const key in state.where) {
1556
+ const value = state.where[key];
1557
+ const col = findColumn(table, key);
1558
+ p += 1;
1559
+ const paramName = `${table.name}_${key}_${p}`;
1560
+ if (value === null) {
1561
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1562
+ whereClauses.push(`"${key}" is null`);
1563
+ } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1564
+ validateInArrayValues(col, key, value, "in");
1565
+ whereClauses.push(`"${key}" = ANY(:${paramName})`);
1566
+ params[paramName] = value;
1567
+ addTypeHintForParam(type_hints, paramName, col, value);
1568
+ } else {
1569
+ validateScalarForColumn(col, value, `column ${key}`);
1570
+ whereClauses.push(`"${key}" = :${paramName}`);
1571
+ params[paramName] = value;
1572
+ addTypeHintForParam(type_hints, paramName, col, value);
1573
+ }
1574
+ }
1575
+ const parts = [];
1576
+ parts.push(`update "${schema.name}"."${table.name}" set ${setParts.join(", ")}`);
1577
+ if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1578
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1579
+ const req = {
1580
+ q: parts.join(" "),
1581
+ params: Object.keys(params).length > 0 ? params : void 0,
1582
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1583
+ };
1584
+ return state.returning.length ? req : req;
1410
1585
  }
1411
- const parts = [];
1412
- parts.push(`delete from "${schema.name}"."${table.name}"`);
1413
- if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1414
- if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1415
- const req = {
1416
- q: parts.join(" "),
1417
- params: Object.keys(params).length > 0 ? params : void 0,
1418
- type_hints: Object.keys(type_hints).length ? type_hints : void 0
1419
- };
1420
- return state.returning.length ? req : req;
1586
+ }();
1587
+ }
1588
+ delete() {
1589
+ const table = this.table;
1590
+ const schema = this.schema;
1591
+ const state = {
1592
+ where: {},
1593
+ returning: []
1594
+ };
1595
+ return new class {
1596
+ constructor() {
1597
+ this.where = (w) => {
1598
+ for (const k in w) state.where[k] = w[k];
1599
+ return this;
1600
+ };
1601
+ this.wherePk = (pk) => {
1602
+ const pkCols = getPrimaryKeyColumns(table);
1603
+ if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1604
+ if (pkCols.length === 1) {
1605
+ const col = pkCols[0];
1606
+ if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${col}`);
1607
+ state.where[col] = pk;
1608
+ } else {
1609
+ if (!isPlainObject(pk)) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1610
+ const obj = pk;
1611
+ for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1612
+ for (const col of pkCols) {
1613
+ if (!(col in obj)) throw new Error(`wherePk missing key '${col}'. Required keys: ${pkCols.join(", ")}`);
1614
+ state.where[col] = obj[col];
1615
+ }
1616
+ }
1617
+ return this;
1618
+ };
1619
+ }
1620
+ returning(cols) {
1621
+ state.returning = cols || [];
1622
+ return this;
1623
+ }
1624
+ toSql() {
1625
+ const params = {};
1626
+ const type_hints = {};
1627
+ let p = 0;
1628
+ const whereClauses = [];
1629
+ for (const key in state.where) {
1630
+ const value = state.where[key];
1631
+ const col = findColumn(table, key);
1632
+ p += 1;
1633
+ const paramName = `${table.name}_${key}_${p}`;
1634
+ if (value === null) {
1635
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1636
+ whereClauses.push(`"${key}" is null`);
1637
+ } else if (Array.isArray(value)) {
1638
+ validateInArrayValues(col, key, value, "in");
1639
+ whereClauses.push(`"${key}" = ANY(:${paramName})`);
1640
+ params[paramName] = value;
1641
+ addTypeHintForParam(type_hints, paramName, col, value);
1642
+ } else {
1643
+ validateScalarForColumn(col, value, `column ${key}`);
1644
+ whereClauses.push(`"${key}" = :${paramName}`);
1645
+ params[paramName] = value;
1646
+ addTypeHintForParam(type_hints, paramName, col, value);
1647
+ }
1648
+ }
1649
+ const parts = [];
1650
+ parts.push(`delete from "${schema.name}"."${table.name}"`);
1651
+ if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1652
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1653
+ const req = {
1654
+ q: parts.join(" "),
1655
+ params: Object.keys(params).length > 0 ? params : void 0,
1656
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1657
+ };
1658
+ return state.returning.length ? req : req;
1659
+ }
1660
+ }();
1661
+ }
1662
+ };
1663
+ function createSqlBuilder(schema) {
1664
+ return { table: (name) => new TableQueryImpl(schema, String(name)) };
1665
+ }
1666
+
1667
+ //#endregion
1668
+ //#region src/provisioning/Schemas.ts
1669
+ var Schemas = class {
1670
+ constructor(client) {
1671
+ this.client = client;
1672
+ }
1673
+ async getSchema(schema, opts) {
1674
+ const path = schema ? `api/v4/schemas/${encodeURIComponent(schema)}` : "api/v4/schemas";
1675
+ const query = {};
1676
+ if (opts?.namesOnly) query.namesOnly = "true";
1677
+ return this.client.request({
1678
+ path,
1679
+ method: "GET",
1680
+ query: Object.keys(query).length > 0 ? query : void 0
1681
+ });
1682
+ }
1683
+ async postSchema(body) {
1684
+ return { location: (await this.client.requestFull({
1685
+ path: "api/v4/schemas",
1686
+ method: "POST",
1687
+ body,
1688
+ expectedStatus: 201
1689
+ })).getHeader("Location") ?? "" };
1690
+ }
1691
+ async patchSchema(schema, body) {
1692
+ return { location: (await this.client.requestFull({
1693
+ path: `api/v4/schemas/${encodeURIComponent(schema)}`,
1694
+ method: "PATCH",
1695
+ body,
1696
+ expectedStatus: 303
1697
+ })).getHeader("Location") ?? "" };
1698
+ }
1699
+ async deleteSchema(schema) {
1700
+ await this.client.request({
1701
+ path: `api/v4/schemas/${encodeURIComponent(schema)}`,
1702
+ method: "DELETE",
1703
+ expectedStatus: 204
1704
+ });
1705
+ }
1706
+ };
1707
+
1708
+ //#endregion
1709
+ //#region src/provisioning/Columns.ts
1710
+ var Columns = class {
1711
+ constructor(client) {
1712
+ this.client = client;
1713
+ }
1714
+ basePath(schema, table) {
1715
+ return `api/v4/schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}/columns`;
1716
+ }
1717
+ async getColumn(schema, table, column) {
1718
+ const path = column ? `${this.basePath(schema, table)}/${encodeURIComponent(column)}` : this.basePath(schema, table);
1719
+ return this.client.request({
1720
+ path,
1721
+ method: "GET"
1722
+ });
1723
+ }
1724
+ async postColumn(schema, table, body) {
1725
+ return { location: (await this.client.requestFull({
1726
+ path: this.basePath(schema, table),
1727
+ method: "POST",
1728
+ body,
1729
+ expectedStatus: 201
1730
+ })).getHeader("Location") ?? "" };
1731
+ }
1732
+ async patchColumn(schema, table, column, body) {
1733
+ return { location: (await this.client.requestFull({
1734
+ path: `${this.basePath(schema, table)}/${encodeURIComponent(column)}`,
1735
+ method: "PATCH",
1736
+ body,
1737
+ expectedStatus: 303
1738
+ })).getHeader("Location") ?? "" };
1739
+ }
1740
+ async deleteColumn(schema, table, column) {
1741
+ await this.client.request({
1742
+ path: `${this.basePath(schema, table)}/${encodeURIComponent(column)}`,
1743
+ method: "DELETE",
1744
+ expectedStatus: 204
1745
+ });
1746
+ }
1747
+ };
1748
+
1749
+ //#endregion
1750
+ //#region src/provisioning/Constraints.ts
1751
+ var Constraints = class {
1752
+ constructor(client) {
1753
+ this.client = client;
1754
+ }
1755
+ basePath(schema, table) {
1756
+ return `api/v4/schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}/constraints`;
1757
+ }
1758
+ async getConstraint(schema, table, constraint) {
1759
+ const path = constraint ? `${this.basePath(schema, table)}/${encodeURIComponent(constraint)}` : this.basePath(schema, table);
1760
+ return this.client.request({
1761
+ path,
1762
+ method: "GET"
1763
+ });
1764
+ }
1765
+ async postConstraint(schema, table, body) {
1766
+ return { location: (await this.client.requestFull({
1767
+ path: this.basePath(schema, table),
1768
+ method: "POST",
1769
+ body,
1770
+ expectedStatus: 201
1771
+ })).getHeader("Location") ?? "" };
1772
+ }
1773
+ async deleteConstraint(schema, table, constraint) {
1774
+ await this.client.request({
1775
+ path: `${this.basePath(schema, table)}/${encodeURIComponent(constraint)}`,
1776
+ method: "DELETE",
1777
+ expectedStatus: 204
1778
+ });
1779
+ }
1780
+ };
1781
+
1782
+ //#endregion
1783
+ //#region src/provisioning/Indices.ts
1784
+ var Indices = class {
1785
+ constructor(client) {
1786
+ this.client = client;
1787
+ }
1788
+ basePath(schema, table) {
1789
+ return `api/v4/schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}/indices`;
1790
+ }
1791
+ async getIndex(schema, table, index) {
1792
+ const path = index ? `${this.basePath(schema, table)}/${encodeURIComponent(index)}` : this.basePath(schema, table);
1793
+ return this.client.request({
1794
+ path,
1795
+ method: "GET"
1796
+ });
1797
+ }
1798
+ async postIndex(schema, table, body) {
1799
+ return { location: (await this.client.requestFull({
1800
+ path: this.basePath(schema, table),
1801
+ method: "POST",
1802
+ body,
1803
+ expectedStatus: 201
1804
+ })).getHeader("Location") ?? "" };
1805
+ }
1806
+ async deleteIndex(schema, table, index) {
1807
+ await this.client.request({
1808
+ path: `${this.basePath(schema, table)}/${encodeURIComponent(index)}`,
1809
+ method: "DELETE",
1810
+ expectedStatus: 204
1811
+ });
1812
+ }
1813
+ };
1814
+
1815
+ //#endregion
1816
+ //#region src/provisioning/Sequences.ts
1817
+ var Sequences = class {
1818
+ constructor(client) {
1819
+ this.client = client;
1820
+ }
1821
+ basePath(schema) {
1822
+ return `api/v4/schemas/${encodeURIComponent(schema)}/sequences`;
1823
+ }
1824
+ async getSequence(schema, sequence) {
1825
+ const path = sequence ? `${this.basePath(schema)}/${encodeURIComponent(sequence)}` : this.basePath(schema);
1826
+ return this.client.request({
1827
+ path,
1828
+ method: "GET"
1829
+ });
1830
+ }
1831
+ async postSequence(schema, body) {
1832
+ return { location: (await this.client.requestFull({
1833
+ path: this.basePath(schema),
1834
+ method: "POST",
1835
+ body,
1836
+ expectedStatus: 201
1837
+ })).getHeader("Location") ?? "" };
1838
+ }
1839
+ async patchSequence(schema, sequence, body) {
1840
+ return { location: (await this.client.requestFull({
1841
+ path: `${this.basePath(schema)}/${encodeURIComponent(sequence)}`,
1842
+ method: "PATCH",
1843
+ body,
1844
+ expectedStatus: 303
1845
+ })).getHeader("Location") ?? "" };
1846
+ }
1847
+ async deleteSequence(schema, sequence) {
1848
+ await this.client.request({
1849
+ path: `${this.basePath(schema)}/${encodeURIComponent(sequence)}`,
1850
+ method: "DELETE",
1851
+ expectedStatus: 204
1852
+ });
1853
+ }
1854
+ };
1855
+
1856
+ //#endregion
1857
+ //#region src/provisioning/Tables.ts
1858
+ var ProvisioningTables = class {
1859
+ constructor(client) {
1860
+ this.client = client;
1861
+ }
1862
+ basePath(schema) {
1863
+ return `api/v4/schemas/${encodeURIComponent(schema)}/tables`;
1864
+ }
1865
+ async getTable(schema, table) {
1866
+ const path = table ? `${this.basePath(schema)}/${encodeURIComponent(table)}` : this.basePath(schema);
1867
+ return this.client.request({
1868
+ path,
1869
+ method: "GET"
1870
+ });
1871
+ }
1872
+ async postTable(schema, body) {
1873
+ return { location: (await this.client.requestFull({
1874
+ path: this.basePath(schema),
1875
+ method: "POST",
1876
+ body,
1877
+ expectedStatus: 201
1878
+ })).getHeader("Location") ?? "" };
1879
+ }
1880
+ async patchTable(schema, table, body) {
1881
+ return { location: (await this.client.requestFull({
1882
+ path: `${this.basePath(schema)}/${encodeURIComponent(table)}`,
1883
+ method: "PATCH",
1884
+ body,
1885
+ expectedStatus: 303
1886
+ })).getHeader("Location") ?? "" };
1887
+ }
1888
+ async deleteTable(schema, table) {
1889
+ await this.client.request({
1890
+ path: `${this.basePath(schema)}/${encodeURIComponent(table)}`,
1891
+ method: "DELETE",
1892
+ expectedStatus: 204
1893
+ });
1894
+ }
1895
+ };
1896
+
1897
+ //#endregion
1898
+ //#region src/provisioning/Users.ts
1899
+ var ProvisioningUsers = class {
1900
+ constructor(client) {
1901
+ this.client = client;
1902
+ }
1903
+ async getUser(name) {
1904
+ const path = name ? `api/v4/users/${encodeURIComponent(name)}` : "api/v4/users";
1905
+ return this.client.request({
1906
+ path,
1907
+ method: "GET"
1908
+ });
1909
+ }
1910
+ async postUser(body) {
1911
+ return { location: (await this.client.requestFull({
1912
+ path: "api/v4/users",
1913
+ method: "POST",
1914
+ body,
1915
+ expectedStatus: 201
1916
+ })).getHeader("Location") ?? "" };
1917
+ }
1918
+ async patchUser(name, body) {
1919
+ return { location: (await this.client.requestFull({
1920
+ path: `api/v4/users/${encodeURIComponent(name)}`,
1921
+ method: "PATCH",
1922
+ body,
1923
+ expectedStatus: 303
1924
+ })).getHeader("Location") ?? "" };
1925
+ }
1926
+ async deleteUser(name) {
1927
+ await this.client.request({
1928
+ path: `api/v4/users/${encodeURIComponent(name)}`,
1929
+ method: "DELETE",
1930
+ expectedStatus: 204
1931
+ });
1932
+ }
1933
+ };
1934
+
1935
+ //#endregion
1936
+ //#region src/provisioning/Clients.ts
1937
+ var ProvisioningClients = class {
1938
+ constructor(client) {
1939
+ this.client = client;
1940
+ }
1941
+ async getClient(id) {
1942
+ const path = id ? `api/v4/clients/${encodeURIComponent(id)}` : "api/v4/clients";
1943
+ return this.client.request({
1944
+ path,
1945
+ method: "GET"
1946
+ });
1947
+ }
1948
+ async postClient(body) {
1949
+ const res = await this.client.requestFull({
1950
+ path: "api/v4/clients",
1951
+ method: "POST",
1952
+ body,
1953
+ expectedStatus: 201
1954
+ });
1955
+ return {
1956
+ location: res.getHeader("Location") ?? "",
1957
+ secret: res.body.secret
1958
+ };
1959
+ }
1960
+ async patchClient(id, body) {
1961
+ return { location: (await this.client.requestFull({
1962
+ path: `api/v4/clients/${encodeURIComponent(id)}`,
1963
+ method: "PATCH",
1964
+ body,
1965
+ expectedStatus: 303
1966
+ })).getHeader("Location") ?? "" };
1967
+ }
1968
+ async deleteClient(id) {
1969
+ await this.client.request({
1970
+ path: `api/v4/clients/${encodeURIComponent(id)}`,
1971
+ method: "DELETE",
1972
+ expectedStatus: 204
1973
+ });
1974
+ }
1975
+ };
1976
+
1977
+ //#endregion
1978
+ //#region src/provisioning/Rules.ts
1979
+ var Rules = class {
1980
+ constructor(client) {
1981
+ this.client = client;
1982
+ }
1983
+ async getRule(id) {
1984
+ const path = id != null ? `api/v4/rules/${encodeURIComponent(id)}` : "api/v4/rules";
1985
+ return this.client.request({
1986
+ path,
1987
+ method: "GET"
1988
+ });
1989
+ }
1990
+ async postRule(body) {
1991
+ return this.client.request({
1992
+ path: "api/v4/rules",
1993
+ method: "POST",
1994
+ body,
1995
+ expectedStatus: 201
1996
+ });
1997
+ }
1998
+ async patchRule(id, body) {
1999
+ return this.client.request({
2000
+ path: `api/v4/rules/${encodeURIComponent(id)}`,
2001
+ method: "PATCH",
2002
+ body
2003
+ });
2004
+ }
2005
+ async deleteRule(id) {
2006
+ await this.client.request({
2007
+ path: `api/v4/rules/${encodeURIComponent(id)}`,
2008
+ method: "DELETE",
2009
+ expectedStatus: 204
2010
+ });
2011
+ }
2012
+ };
2013
+
2014
+ //#endregion
2015
+ //#region src/provisioning/Privileges.ts
2016
+ var Privileges = class {
2017
+ constructor(client) {
2018
+ this.client = client;
2019
+ }
2020
+ async getPrivileges(schema, table) {
2021
+ return this.client.request({
2022
+ path: `api/v4/schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}/privileges`,
2023
+ method: "GET"
2024
+ });
2025
+ }
2026
+ async patchPrivileges(schema, table, body) {
2027
+ return this.client.request({
2028
+ path: `api/v4/schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}/privileges`,
2029
+ method: "PATCH",
2030
+ body
2031
+ });
2032
+ }
2033
+ };
2034
+
2035
+ //#endregion
2036
+ //#region src/provisioning/RpcMethods.ts
2037
+ var RpcMethods = class {
2038
+ constructor(client) {
2039
+ this.client = client;
2040
+ }
2041
+ async getRpc(method) {
2042
+ const path = method ? `api/v4/methods/${encodeURIComponent(method)}` : "api/v4/methods";
2043
+ return this.client.request({
2044
+ path,
2045
+ method: "GET"
2046
+ });
2047
+ }
2048
+ async postRpc(body) {
2049
+ return { location: (await this.client.requestFull({
2050
+ path: "api/v4/methods",
2051
+ method: "POST",
2052
+ body,
2053
+ expectedStatus: 201
2054
+ })).getHeader("Location") ?? "" };
2055
+ }
2056
+ async patchRpc(method, body) {
2057
+ return { location: (await this.client.requestFull({
2058
+ path: `api/v4/methods/${encodeURIComponent(method)}`,
2059
+ method: "PATCH",
2060
+ body,
2061
+ expectedStatus: 303
2062
+ })).getHeader("Location") ?? "" };
2063
+ }
2064
+ async deleteRpc(method) {
2065
+ await this.client.request({
2066
+ path: `api/v4/methods/${encodeURIComponent(method)}`,
2067
+ method: "DELETE",
2068
+ expectedStatus: 204
2069
+ });
2070
+ }
2071
+ async postCallDry(body) {
2072
+ return this.client.request({
2073
+ path: "api/v4/call/dry",
2074
+ method: "POST",
2075
+ body
2076
+ });
2077
+ }
2078
+ };
2079
+
2080
+ //#endregion
2081
+ //#region src/provisioning/MetadataWrite.ts
2082
+ var MetadataWrite = class {
2083
+ constructor(client) {
2084
+ this.client = client;
2085
+ }
2086
+ async patchMetaData(body) {
2087
+ return this.client.request({
2088
+ path: "api/v4/meta",
2089
+ method: "PATCH",
2090
+ body
2091
+ });
2092
+ }
2093
+ };
2094
+
2095
+ //#endregion
2096
+ //#region src/provisioning/TypeScriptInterfaces.ts
2097
+ var TypeScriptInterfaces = class {
2098
+ constructor(client) {
2099
+ this.client = client;
2100
+ }
2101
+ async getTypeScript() {
2102
+ return this.client.request({
2103
+ path: "api/v4/interfaces",
2104
+ method: "GET",
2105
+ accept: "text/plain"
2106
+ });
2107
+ }
2108
+ };
2109
+
2110
+ //#endregion
2111
+ //#region src/provisioning/FileImport.ts
2112
+ var FileImport = class {
2113
+ constructor(client) {
2114
+ this.client = client;
2115
+ }
2116
+ /**
2117
+ * Upload a file via multipart/form-data.
2118
+ * In Node.js, pass a FormData instance. In browsers, pass a native FormData.
2119
+ */
2120
+ async postFileUpload(formData) {
2121
+ return this.client.request({
2122
+ path: "api/v4/file/upload",
2123
+ method: "POST",
2124
+ body: formData,
2125
+ contentType: null,
2126
+ expectedStatus: 201
2127
+ });
2128
+ }
2129
+ async postFileProcess(body) {
2130
+ return this.client.request({
2131
+ path: "api/v4/file/process",
2132
+ method: "POST",
2133
+ body,
2134
+ expectedStatus: 201
2135
+ });
2136
+ }
2137
+ };
2138
+
2139
+ //#endregion
2140
+ //#region src/provisioning/GitCommit.ts
2141
+ var GitCommit = class {
2142
+ constructor(client) {
2143
+ this.client = client;
2144
+ }
2145
+ async postCommit(body) {
2146
+ return this.client.request({
2147
+ path: "api/v4/commit",
2148
+ method: "POST",
2149
+ body
2150
+ });
2151
+ }
2152
+ };
2153
+
2154
+ //#endregion
2155
+ //#region src/provisioning/SqlNoToken.ts
2156
+ var SqlNoToken = class {
2157
+ constructor(client) {
2158
+ this.client = client;
2159
+ }
2160
+ async postSqlNoToken(database, body) {
2161
+ return this.client.request({
2162
+ path: `api/v4/sql/database/${encodeURIComponent(database)}`,
2163
+ method: "POST",
2164
+ body
2165
+ });
2166
+ }
2167
+ };
2168
+
2169
+ //#endregion
2170
+ //#region src/admin.ts
2171
+ /**
2172
+ * @author Martin Høgh <mh@mapcentia.com>
2173
+ * @copyright 2013-2026 MapCentia ApS
2174
+ * @license https://opensource.org/license/mit The MIT License
2175
+ */
2176
+ /**
2177
+ * Create a Centia admin client with access to provisioning operations.
2178
+ *
2179
+ * ```ts
2180
+ * const client = createCentiaAdminClient({
2181
+ * baseUrl: 'https://example.centia.io',
2182
+ * auth: { getAccessToken: async () => token },
2183
+ * });
2184
+ *
2185
+ * await client.provisioning.schemas.postSchema({ name: 'myschema' });
2186
+ * ```
2187
+ */
2188
+ function createCentiaAdminClient(config) {
2189
+ const http = new CentiaHttpClient(config);
2190
+ return {
2191
+ http,
2192
+ provisioning: {
2193
+ schemas: new Schemas(http),
2194
+ tables: new ProvisioningTables(http),
2195
+ columns: new Columns(http),
2196
+ constraints: new Constraints(http),
2197
+ indices: new Indices(http),
2198
+ sequences: new Sequences(http),
2199
+ users: new ProvisioningUsers(http),
2200
+ clients: new ProvisioningClients(http),
2201
+ rules: new Rules(http),
2202
+ privileges: new Privileges(http),
2203
+ rpcMethods: new RpcMethods(http),
2204
+ metadata: new MetadataWrite(http),
2205
+ typeScript: new TypeScriptInterfaces(http),
2206
+ fileImport: new FileImport(http),
2207
+ gitCommit: new GitCommit(http),
2208
+ sqlNoToken: new SqlNoToken(http)
1421
2209
  }
1422
- }();
2210
+ };
1423
2211
  }
1424
- };
1425
- function createSqlBuilder(schema) {
1426
- return { table: (name) => new TableQueryImpl(schema, String(name)) };
1427
- }
1428
2212
 
1429
2213
  //#endregion
2214
+ //#region src/index.ts
2215
+ /**
2216
+ * @author Martin Høgh <mh@mapcentia.com>
2217
+ * @copyright 2013-2026 MapCentia ApS
2218
+ * @license https://opensource.org/license/mit The MIT License
2219
+ *
2220
+ */
2221
+
2222
+ //#endregion
2223
+ exports.CentiaApiError = CentiaApiError;
1430
2224
  exports.Claims = Claims;
1431
2225
  exports.CodeFlow = CodeFlow;
2226
+ exports.Gql = Gql;
1432
2227
  exports.Meta = Meta;
1433
2228
  exports.PasswordFlow = PasswordFlow;
1434
2229
  exports.Rpc = Rpc;
@@ -1440,5 +2235,8 @@ exports.Tables = Tables;
1440
2235
  exports.Users = Users;
1441
2236
  exports.Ws = Ws;
1442
2237
  exports.createApi = createApi;
2238
+ exports.createCentiaAdminClient = createCentiaAdminClient;
2239
+ exports.createCentiaClient = createCentiaClient;
1443
2240
  exports.createSqlBuilder = createSqlBuilder;
2241
+ exports.isCentiaApiError = isCentiaApiError;
1444
2242
  });