@centia-io/sdk 0.0.43 → 0.0.44

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,1069 @@
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}`);
227
- }
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;
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;
213
+ }
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
444
  //#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
445
+ /**
446
+ * @author Martin Høgh <mh@mapcentia.com>
447
+ * @copyright 2013-2026 MapCentia ApS
448
+ * @license https://opensource.org/license/mit The MIT License
449
+ *
450
+ */
451
+ const getHeaders = async (contentType = "application/json") => {
452
+ if (!await isLogin(new Gc2Service(getOptions()))) return Promise.reject("Is not logged in");
453
+ const { accessToken } = getTokens();
454
+ const headers = {
455
+ Accept: "application/json",
456
+ Cookie: "XDEBUG_SESSION=XDEBUG_ECLIPSE",
457
+ Authorization: accessToken ? "Bearer " + accessToken : null
458
+ };
459
+ if (contentType) headers["Content-Type"] = contentType;
460
+ return headers;
425
461
  };
426
- if (contentType) headers["Content-Type"] = contentType;
427
- return headers;
428
- };
429
- var request_headers_default = getHeaders;
462
+ var request_headers_default = getHeaders;
430
463
 
431
464
  //#endregion
432
465
  //#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"
466
+ /**
467
+ * @author Martin Høgh <mh@mapcentia.com>
468
+ * @copyright 2013-2026 MapCentia ApS
469
+ * @license https://opensource.org/license/mit The MIT License
470
+ *
471
+ */
472
+ const make = async (version, resource, method, payload, contentType = "application/json") => {
473
+ const options = getOptions();
474
+ let request = {
475
+ method,
476
+ headers: await request_headers_default(contentType),
477
+ redirect: "manual"
478
+ };
479
+ if (payload) request.body = contentType === "application/json" ? JSON.stringify(payload) : payload;
480
+ if (version !== null) return await fetch(options.host + `/api/v${version}/${resource}`, request);
481
+ else return await fetch(options.host + `/api/${resource}`, request);
439
482
  };
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;
483
+ var make_request_default = make;
444
484
 
445
485
  //#endregion
446
486
  //#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);
459
- }
460
- return res;
461
- };
462
- var get_response_default = get;
487
+ /**
488
+ * @author Martin Høgh <mh@mapcentia.com>
489
+ * @copyright 2013-2026 MapCentia ApS
490
+ * @license https://opensource.org/license/mit The MIT License
491
+ *
492
+ */
493
+ const get = async (response, expectedCode) => {
494
+ let res = null;
495
+ let bodyText = "";
496
+ try {
497
+ bodyText = await response.text();
498
+ } catch (e) {}
499
+ if (bodyText) try {
500
+ res = JSON.parse(bodyText);
501
+ } catch (e) {}
502
+ if (response.status !== expectedCode) {
503
+ const msg = res && (res.message || res.error) || bodyText || `Unexpected status ${response.status}`;
504
+ throw new Error(msg);
505
+ }
506
+ return res;
507
+ };
508
+ var get_response_default = get;
463
509
 
464
510
  //#endregion
465
511
  //#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
- };
512
+ /**
513
+ * @author Martin Høgh <mh@mapcentia.com>
514
+ * @copyright 2013-2026 MapCentia ApS
515
+ * @license https://opensource.org/license/mit The MIT License
516
+ *
517
+ */
518
+ var Sql = class {
519
+ async exec(request) {
520
+ return await get_response_default(await make_request_default("4", `sql`, "POST", request), 200);
521
+ }
522
+ };
471
523
 
472
524
  //#endregion
473
525
  //#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
- };
526
+ /**
527
+ * @author Martin Høgh <mh@mapcentia.com>
528
+ * @copyright 2013-2026 MapCentia ApS
529
+ * @license https://opensource.org/license/mit The MIT License
530
+ *
531
+ */
532
+ var Rpc = class {
533
+ async call(request) {
534
+ return await get_response_default(await make_request_default("4", `call`, "POST", request), 200);
535
+ }
536
+ };
537
+
538
+ //#endregion
539
+ //#region src/Gql.ts
540
+ /**
541
+ * @author Martin Høgh <mh@mapcentia.com>
542
+ * @copyright 2013-2026 MapCentia ApS
543
+ * @license https://opensource.org/license/mit The MIT License
544
+ *
545
+ */
546
+ var Gql = class {
547
+ constructor(schema) {
548
+ this.schema = schema;
549
+ }
550
+ async request(request) {
551
+ return await get_response_default(await make_request_default(null, `graphql/schema/${this.schema}`, "POST", request), 200);
552
+ }
553
+ };
479
554
 
480
555
  //#endregion
481
556
  //#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
- };
557
+ /**
558
+ * @author Martin Høgh <mh@mapcentia.com>
559
+ * @copyright 2013-2026 MapCentia ApS
560
+ * @license https://opensource.org/license/mit The MIT License
561
+ *
562
+ */
563
+ var Meta = class {
564
+ async query(rel) {
565
+ return await get_response_default(await make_request_default("3", `meta/${rel}`, "GET", null), 200);
566
+ }
567
+ };
487
568
 
488
569
  //#endregion
489
570
  //#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
- };
571
+ /**
572
+ * @author Martin Høgh <mh@mapcentia.com>
573
+ * @copyright 2013-2026 MapCentia ApS
574
+ * @license https://opensource.org/license/mit The MIT License
575
+ *
576
+ */
577
+ var Status = class {
578
+ isAuth() {
579
+ const tokens = getTokens();
580
+ return !(!tokens.accessToken && !tokens.refreshToken);
581
+ }
582
+ getTokens() {
583
+ return getTokens();
584
+ }
585
+ };
499
586
 
500
587
  //#endregion
501
588
  //#region src/Claims.ts
502
- var Claims = class {
503
- get() {
504
- const tokens = getTokens().accessToken;
505
- return claims(tokens);
506
- }
507
- };
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
+ */
595
+ var Claims = class {
596
+ get() {
597
+ const tokens = getTokens().accessToken;
598
+ return claims(tokens);
599
+ }
600
+ };
508
601
 
509
602
  //#endregion
510
603
  //#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
- };
604
+ /**
605
+ * @author Martin Høgh <mh@mapcentia.com>
606
+ * @copyright 2013-2026 MapCentia ApS
607
+ * @license https://opensource.org/license/mit The MIT License
608
+ *
609
+ */
610
+ var Users = class {
611
+ async get(user) {
612
+ return await get_response_default(await make_request_default("4", `users/${user}`, "GET", null), 200);
613
+ }
614
+ };
516
615
 
517
616
  //#endregion
518
617
  //#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();
618
+ /**
619
+ * @author Martin Høgh <mh@mapcentia.com>
620
+ * @copyright 2013-2026 MapCentia ApS
621
+ * @license https://opensource.org/license/mit The MIT License
622
+ *
623
+ */
624
+ var Ws = class {
625
+ constructor(options) {
626
+ this.options = options;
627
+ this.options.wsClient = this.options?.wsClient ?? WebSocket;
628
+ }
629
+ connect() {
630
+ const me = this;
631
+ const { accessToken } = getTokens();
632
+ const connect = () => {
633
+ let queryString = `?token=` + accessToken;
634
+ if (this.options?.rel) queryString = queryString + `&rel=` + this.options.rel;
635
+ const WSClass = this.options.wsClient;
636
+ const ws = new WSClass(this.options.host + `/` + queryString);
637
+ ws.onopen = function() {
638
+ console.log("WebSocket connected!");
639
+ };
640
+ ws.onmessage = function(event) {
641
+ me.options.callBack(event.data);
642
+ };
643
+ ws.onclose = function(event) {
644
+ if (accessToken !== "") {
645
+ console.log("WebSocket closed, reconnecting in 3 seconds...", event.reason);
646
+ setTimeout(connect, 3e3);
647
+ }
648
+ };
649
+ ws.onerror = function(err) {
650
+ console.error("WebSocket error observed:", err);
651
+ ws.close();
652
+ };
547
653
  };
548
- };
549
- if (accessToken !== "") connect();
550
- }
551
- };
654
+ if (accessToken !== "") connect();
655
+ }
656
+ };
552
657
 
553
658
  //#endregion
554
659
  //#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
- };
660
+ /**
661
+ * @author Martin Høgh <mh@mapcentia.com>
662
+ * @copyright 2013-2026 MapCentia ApS
663
+ * @license https://opensource.org/license/mit The MIT License
664
+ *
665
+ */
666
+ var Stats = class {
667
+ async get() {
668
+ return await get_response_default(await make_request_default("4", `stats`, "GET", null), 200);
669
+ }
670
+ };
560
671
 
561
672
  //#endregion
562
673
  //#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
- };
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 Tables = class {
681
+ async get(schema, table) {
682
+ return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "GET", null), 200);
683
+ }
684
+ async create(schema, table, payload) {
685
+ return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "POST", payload), 200);
686
+ }
687
+ async patch(schema, table, payload) {
688
+ return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "PATCH", payload), 200);
689
+ }
690
+ async delete(schema, table) {
691
+ return await get_response_default(await make_request_default("4", `schemas/${encodeURIComponent(schema)}/tables/${encodeURIComponent(table)}`, "DELETE", null), 204);
692
+ }
693
+ };
577
694
 
578
695
  //#endregion
579
696
  //#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.`);
697
+ /**
698
+ * @author Martin Høgh <mh@mapcentia.com>
699
+ * @copyright 2013-2026 MapCentia ApS
700
+ * @license https://opensource.org/license/mit The MIT License
701
+ *
702
+ */
703
+ function isPlainObject$1(v) {
704
+ return typeof v === "object" && v !== null && !Array.isArray(v);
705
+ }
706
+ function validateParamsForMethod(method, params) {
707
+ if (Array.isArray(params)) {
708
+ const badIndex = params.findIndex((p) => !isPlainObject$1(p));
709
+ if (badIndex !== -1) throw new TypeError(`createApi: Invalid argument at index ${badIndex} for RPC method "${method}". Expected a plain object.`);
710
+ return params;
711
+ }
712
+ if (params === void 0) return {};
713
+ if (!isPlainObject$1(params)) throw new TypeError(`createApi: Invalid argument for RPC method "${method}". Expected a plain object.`);
587
714
  return params;
588
715
  }
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);
716
+ function extractDataFromResponse(method, res) {
717
+ if (!res || typeof res !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected an object.`);
718
+ if (res.jsonrpc !== "2.0") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing or invalid jsonrpc version.`);
719
+ const err = res.error;
720
+ if (err !== void 0) {
721
+ if (!err || typeof err !== "object") throw new TypeError(`createApi: Invalid RPC error for method "${method}". Expected 'error' to be an object.`);
722
+ const code = err.code;
723
+ const message = err.message;
724
+ const data$1 = err.data;
725
+ const codeIsNum = typeof code === "number" && Number.isFinite(code);
726
+ const details = typeof message === "string" && message.length > 0 ? message : "Unknown error";
727
+ const e = /* @__PURE__ */ new Error(`createApi: RPC error for method "${method}"${codeIsNum ? ` (${code})` : ""}: ${details}`);
728
+ e.code = code;
729
+ if (data$1 !== void 0) e.data = data$1;
730
+ e.method = method;
731
+ e.name = "JsonRpcError";
732
+ throw e;
733
+ }
734
+ const result = res.result;
735
+ if (!result || typeof result !== "object") throw new TypeError(`createApi: Invalid RPC response for method "${method}". Missing result object.`);
736
+ const data = result.data;
737
+ if (!Array.isArray(data)) throw new TypeError(`createApi: Invalid RPC response for method "${method}". Expected result.data to be an array.`);
738
+ return data;
739
+ }
740
+ async function dispatch(name, paramsLike) {
741
+ if (typeof name !== "string" || name.length === 0) throw new TypeError("createApi: RPC method name must be a non-empty string.");
742
+ const params = validateParamsForMethod(String(name), paramsLike);
743
+ const rpc = new Rpc();
744
+ const request = {
745
+ jsonrpc: "2.0",
746
+ method: name,
747
+ id: 1,
748
+ params
635
749
  };
636
- } });
637
- }
750
+ const res = await rpc.call(request);
751
+ return extractDataFromResponse(String(name), res);
752
+ }
753
+ function createApi() {
754
+ return new Proxy({}, { get(_target, prop) {
755
+ if (typeof prop !== "string") return void 0;
756
+ return (...args) => {
757
+ return dispatch(prop, args.length === 0 ? {} : args.length === 1 ? args[0] : args);
758
+ };
759
+ } });
760
+ }
638
761
 
639
762
  //#endregion
640
763
  //#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
- };
764
+ /**
765
+ * @author Martin Høgh <mh@mapcentia.com>
766
+ * @copyright 2013-2026 MapCentia ApS
767
+ * @license https://opensource.org/license/mit The MIT License
768
+ *
769
+ */
770
+ var SignUp = class {
771
+ constructor(options) {
772
+ this.options = options;
773
+ this.service = new Gc2Service(options);
774
+ }
775
+ async signUp() {
776
+ window.location.assign(this.service.getSignUpURL());
777
+ }
778
+ };
650
779
 
651
780
  //#endregion
652
781
  //#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;
782
+ function findTable(schema, name) {
783
+ const tbl = schema.tables.find((t) => t.name === name);
784
+ if (!tbl) throw new Error(`Table not found in schema: ${name}`);
785
+ return tbl;
786
+ }
787
+ function findColumn(table, name) {
788
+ const col = table.columns.find((c) => c.name === name);
789
+ if (!col) throw new Error(`Column not found in table ${table.name}: ${name}`);
790
+ return col;
791
+ }
792
+ function getPrimaryKeyColumns(table) {
793
+ const pk = (table.constraints || []).find((c) => c.constraint === "primary" && Array.isArray(c.columns) && c.columns.length > 0);
794
+ return pk ? pk.columns.map(String) : [];
795
+ }
796
+ function typeNameToHint(typname, isArray) {
797
+ if (!typname) return void 0;
798
+ const base = typname;
799
+ return isArray ? base + "[]" : base;
800
+ }
801
+ function addTypeHintForParam(typeHints, paramName, col, value) {
802
+ let isArr = col._is_array;
803
+ if (Array.isArray(value)) if (isArrayShapedGeomTypename(col._typname)) isArr = value.every(Array.isArray);
804
+ else isArr = true;
805
+ const hint = typeNameToHint(col._typname, isArr);
806
+ if (hint) typeHints[paramName] = hint;
807
+ }
808
+ function expectedScalarKind(typname) {
809
+ const t = typname.toLowerCase();
810
+ if (t === "int2" || t === "int4" || t === "int8" || t === "float4" || t === "float8") return "number";
811
+ if (t === "numeric" || t === "decimal") return "string";
812
+ if (t === "varchar" || t === "text" || t === "bpchar" || t === "char" || t === "date" || t === "time" || t === "timetz" || t === "timestamp" || t === "timestamptz") return "string";
813
+ if (t === "bool") return "boolean";
814
+ if (t === "json" || t === "jsonb") return "json";
815
+ if (t === "int4range" || t === "int8range" || t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "range";
816
+ if (t === "interval") return "interval";
817
+ if (t === "point" || t === "line" || t === "lseg" || t === "box" || t === "path" || t === "polygon" || t === "circle") return "geom";
818
+ return "unknown";
819
+ }
820
+ function isArrayShapedGeomTypename(typname) {
821
+ const t = typname.toLowerCase();
822
+ return t === "path" || t === "polygon";
823
+ }
824
+ function isArrayShapedGeomScalarValue(col, value) {
825
+ if (!Array.isArray(value)) return false;
826
+ if (!isArrayShapedGeomTypename(col._typname)) return false;
827
+ return !value.every(Array.isArray);
828
+ }
829
+ function expectedRangeInnerKind(typname) {
830
+ const t = typname.toLowerCase();
831
+ if (t === "int4range" || t === "int8range") return "number";
832
+ if (t === "numrange" || t === "tsrange" || t === "tstzrange" || t === "daterange") return "string";
833
+ return "unknown";
834
+ }
835
+ function isPlainObject(v) {
836
+ return typeof v === "object" && v !== null && !Array.isArray(v);
837
+ }
838
+ function isFiniteNumber(n) {
839
+ return typeof n === "number" && Number.isFinite(n);
840
+ }
841
+ function isPointLike(v) {
842
+ if (!isPlainObject(v)) return false;
843
+ const x = v.x;
844
+ const y = v.y;
845
+ return isFiniteNumber(x) && isFiniteNumber(y);
846
+ }
847
+ function validateGeometryForColumn(col, value, context) {
848
+ const t = col._typname.toLowerCase();
849
+ if (t === "point") {
850
+ if (!isPointLike(value)) throw new Error(`Invalid value for ${context}. Expected Point { x: number, y: number }`);
851
+ return;
852
+ }
853
+ if (t === "line") {
854
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Line { A: number, B: number, C: number }`);
855
+ const A = value.A, B = value.B, C = value.C;
856
+ if (!isFiniteNumber(A) || !isFiniteNumber(B) || !isFiniteNumber(C)) throw new Error(`Invalid Line for ${context}. A, B, C must be finite numbers`);
857
+ return;
858
+ }
859
+ if (t === "lseg" || t === "box") {
860
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected ${t.toUpperCase()} { start: Point, end: Point }`);
861
+ const start = value.start;
862
+ const end = value.end;
863
+ if (!isPointLike(start) || !isPointLike(end)) throw new Error(`Invalid ${t} for ${context}. 'start' and 'end' must be Point { x, y }`);
864
+ return;
865
+ }
866
+ if (t === "path") {
867
+ if (!Array.isArray(value) || value.length < 1) throw new Error(`Invalid value for ${context}. Expected Path [isClosed: boolean, ...points: Point[]]`);
868
+ const [isClosed, ...points] = value;
869
+ if (typeof isClosed !== "boolean") throw new Error(`Invalid Path for ${context}. First element must be boolean (isClosed)`);
870
+ 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 }`);
871
+ return;
872
+ }
873
+ if (t === "polygon") {
874
+ if (!Array.isArray(value)) throw new Error(`Invalid value for ${context}. Expected Polygon as Point[]`);
875
+ 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 }`);
876
+ return;
877
+ }
878
+ if (t === "circle") {
879
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected Circle { center: Point, radius: number }`);
880
+ const center = value.center;
881
+ const radius = value.radius;
882
+ if (!isPointLike(center) || !isFiniteNumber(radius)) throw new Error(`Invalid Circle for ${context}. 'center' must be Point and 'radius' must be finite number`);
883
+ return;
884
+ }
812
885
  }
813
- if (kind === "range") {
814
- validateRangeForColumn(col, value, context);
815
- return;
886
+ function validateRangeForColumn(col, value, context) {
887
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected a range object for type ${col._typname}`);
888
+ const r = value;
889
+ const hasLower = Object.prototype.hasOwnProperty.call(r, "lower");
890
+ const hasUpper = Object.prototype.hasOwnProperty.call(r, "upper");
891
+ const hasLi = Object.prototype.hasOwnProperty.call(r, "lowerInclusive");
892
+ const hasUi = Object.prototype.hasOwnProperty.call(r, "upperInclusive");
893
+ if (!hasLower || !hasUpper || !hasLi || !hasUi) throw new Error(`Invalid range for ${context}. Required properties: lower, upper, lowerInclusive, upperInclusive`);
894
+ if (typeof r.lowerInclusive !== "boolean" || typeof r.upperInclusive !== "boolean") throw new Error(`Invalid range for ${context}. lowerInclusive and upperInclusive must be boolean`);
895
+ const inner = expectedRangeInnerKind(col._typname);
896
+ if (inner === "number") {
897
+ if (typeof r.lower !== "number" || !Number.isFinite(r.lower)) throw new Error(`Invalid range.lower for ${context}. Expected number for type ${col._typname}`);
898
+ if (typeof r.upper !== "number" || !Number.isFinite(r.upper)) throw new Error(`Invalid range.upper for ${context}. Expected number for type ${col._typname}`);
899
+ } else if (inner === "string") {
900
+ if (typeof r.lower !== "string") throw new Error(`Invalid range.lower for ${context}. Expected string for type ${col._typname}`);
901
+ if (typeof r.upper !== "string") throw new Error(`Invalid range.upper for ${context}. Expected string for type ${col._typname}`);
902
+ }
816
903
  }
817
- if (kind === "interval") {
818
- validateIntervalForColumn(col, value, context);
819
- return;
904
+ function validateIntervalForColumn(col, value, context) {
905
+ if (!isPlainObject(value)) throw new Error(`Invalid value for ${context}. Expected an interval object for type ${col._typname}`);
906
+ const v = value;
907
+ for (const k of [
908
+ "y",
909
+ "m",
910
+ "d",
911
+ "h",
912
+ "i",
913
+ "s"
914
+ ]) {
915
+ if (!Object.prototype.hasOwnProperty.call(v, k)) throw new Error(`Invalid interval for ${context}. Missing property '${k}'`);
916
+ const num = v[k];
917
+ if (typeof num !== "number" || !Number.isFinite(num)) throw new Error(`Invalid interval.${String(k)} for ${context}. Expected finite number`);
918
+ }
820
919
  }
821
- if (kind === "geom") {
822
- validateGeometryForColumn(col, value, context);
823
- return;
920
+ function isValidJsonLike(value) {
921
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "object" && value !== null;
824
922
  }
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}`);
923
+ function validateScalarForColumn(col, value, context) {
924
+ const kind = expectedScalarKind(col._typname);
925
+ if (kind === "unknown") return;
926
+ if (kind === "number") {
927
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`Invalid value for ${context}. Expected number for type ${col._typname}, got ${typeof value}`);
928
+ return;
929
+ }
930
+ if (kind === "string") {
931
+ if (typeof value !== "string") throw new Error(`Invalid value for ${context}. Expected string for type ${col._typname}, got ${typeof value}`);
932
+ return;
933
+ }
934
+ if (kind === "boolean") {
935
+ if (typeof value !== "boolean") throw new Error(`Invalid value for ${context}. Expected boolean for type ${col._typname}, got ${typeof value}`);
936
+ return;
937
+ }
938
+ if (kind === "json") {
939
+ if (!isValidJsonLike(value)) throw new Error(`Invalid value for ${context}. Expected JSON-compatible value for type ${col._typname}`);
940
+ return;
941
+ }
942
+ if (kind === "range") {
943
+ validateRangeForColumn(col, value, context);
944
+ return;
945
+ }
946
+ if (kind === "interval") {
947
+ validateIntervalForColumn(col, value, context);
948
+ return;
949
+ }
950
+ if (kind === "geom") {
951
+ validateGeometryForColumn(col, value, context);
952
+ return;
953
+ }
834
954
  }
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++;
955
+ function validateComparisonValue(col, key, value, op) {
956
+ 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.`);
957
+ if (col._is_array) {
958
+ if (!Array.isArray(value)) throw new Error(`Operator ${op} on array column ${key} requires an array value`);
959
+ for (const [i, v] of value.entries()) validateScalarForColumn(col, v, `column ${key}[${i}]`);
960
+ } else {
961
+ if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) throw new Error(`Operator ${op} on scalar column ${key} cannot accept an array value`);
962
+ validateScalarForColumn(col, value, `column ${key}`);
842
963
  }
843
964
  }
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);
965
+ function validateInArrayValues(col, key, values, op) {
966
+ if (!col._is_array) {
967
+ let idx = 0;
968
+ for (const v of values) {
969
+ validateScalarForColumn(col, v, `column ${key} (element ${idx})`);
970
+ idx++;
971
+ }
972
+ }
862
973
  }
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);
974
+ function findJoinOn(base, target) {
975
+ const bc = base.constraints || [];
976
+ const tc = target.constraints || [];
977
+ 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) => ({
978
+ left: String(col),
979
+ right: String(c.referenced_columns[i])
980
+ }));
981
+ 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) => ({
982
+ left: String(rcol),
983
+ right: String(c.columns[i])
984
+ }));
985
+ return null;
986
+ }
987
+ var TableQueryImpl = class {
988
+ constructor(schema, tableName) {
989
+ this.schema = schema;
990
+ this.table = findTable(schema, tableName);
991
+ }
992
+ select(cols) {
993
+ const table = this.table;
994
+ const schema = this.schema;
995
+ const selected = cols && cols.length ? cols : ["*"];
996
+ const state = {
997
+ table,
998
+ selected,
999
+ where: {},
1000
+ orWhereGroups: [],
1001
+ andOps: [],
1002
+ orOpGroups: [],
1003
+ order: [],
1004
+ limit: void 0,
1005
+ offset: void 0,
1006
+ joins: [],
1007
+ joinSelections: []
1008
+ };
1009
+ return new class {
1010
+ constructor() {
1011
+ this.s = state;
1012
+ this.toSql = () => {
1013
+ const params = {};
1014
+ const type_hints = {};
1015
+ let p = 0;
1016
+ const parts = [];
1017
+ const selectParts = [];
1018
+ if (selected.length === 1 && selected[0] === "*") selectParts.push(`"${table.name}".*`);
1019
+ else {
1020
+ const sel = selected;
1021
+ for (const c of sel) findColumn(table, String(c));
1022
+ selectParts.push(sel.map((c) => `"${table.name}"."${c}"`).join(", "));
925
1023
  }
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);
1024
+ for (const js of state.joinSelections) if (js.selected.length === 1 && js.selected[0] === "*") selectParts.push(`"${js.target.name}".*`);
1025
+ else {
1026
+ const cols$1 = js.selected;
1027
+ for (const c of cols$1) findColumn(js.target, String(c));
1028
+ selectParts.push(cols$1.map((c) => `"${js.target.name}"."${c}"`).join(", "));
965
1029
  }
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];
1030
+ parts.push(`select ${selectParts.join(", ")} from "${schema.name}"."${table.name}"`);
1031
+ for (const j of state.joins) {
1032
+ const onExpr = j.on.map((p$1) => `"${j.source.name}"."${p$1.left}" = "${j.target.name}"."${p$1.right}"`).join(" and ");
1033
+ parts.push(`${j.type} join "${schema.name}"."${j.target.name}" on ${onExpr}`);
1034
+ }
1035
+ const andParts = [];
1036
+ for (const key in state.where) {
1037
+ const value = state.where[key];
972
1038
  const col = findColumn(table, key);
973
1039
  p += 1;
974
1040
  const paramName = `${table.name}_${key}_${p}`;
975
1041
  if (value === null) {
976
1042
  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`);
1043
+ andParts.push(`"${table.name}"."${key}" is null`);
978
1044
  } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
979
1045
  validateInArrayValues(col, key, value, "in");
980
- orParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
1046
+ andParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
981
1047
  params[paramName] = value;
982
1048
  addTypeHintForParam(type_hints, paramName, col, value);
983
1049
  } else {
984
1050
  validateScalarForColumn(col, value, `column ${key}`);
985
- orParts.push(`"${table.name}"."${key}" = :${paramName}`);
1051
+ andParts.push(`"${table.name}"."${key}" = :${paramName}`);
986
1052
  params[paramName] = value;
987
1053
  addTypeHintForParam(type_hints, paramName, col, value);
988
1054
  }
989
1055
  }
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) {
1056
+ for (const pred of state.andOps) {
995
1057
  const key = String(pred.col);
996
1058
  const op = String(pred.op);
997
1059
  const col = findColumn(table, key);
998
1060
  const qualified = `"${table.name}"."${key}"`;
999
1061
  if (op === "isnull" || op === "notnull") {
1000
1062
  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"}`);
1063
+ andParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1002
1064
  } else if (op === "in" || op === "notin") {
1003
1065
  const val = pred.value;
1004
1066
  if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
1005
1067
  validateInArrayValues(col, key, val, op);
1006
1068
  p += 1;
1007
1069
  const paramName = `${table.name}_${key}_${p}`;
1008
- orParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1070
+ andParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1009
1071
  params[paramName] = val;
1010
1072
  addTypeHintForParam(type_hints, paramName, col, val);
1011
1073
  } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
@@ -1014,7 +1076,7 @@ var TableQueryImpl = class {
1014
1076
  p += 1;
1015
1077
  const paramName = `${table.name}_${key}_${p}`;
1016
1078
  const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
1017
- orParts.push(`${qualified} ${sqlOp} :${paramName}`);
1079
+ andParts.push(`${qualified} ${sqlOp} :${paramName}`);
1018
1080
  params[paramName] = val;
1019
1081
  addTypeHintForParam(type_hints, paramName, col, val);
1020
1082
  } else {
@@ -1023,252 +1085,137 @@ var TableQueryImpl = class {
1023
1085
  validateComparisonValue(col, key, val, op);
1024
1086
  p += 1;
1025
1087
  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}`);
1088
+ if (op === "=") andParts.push(`${qualified} = :${paramName}`);
1089
+ else if (op === "!=") andParts.push(`${qualified} <> :${paramName}`);
1090
+ else if (op === "<" || op === "<=" || op === ">" || op === ">=") andParts.push(`${qualified} ${op} :${paramName}`);
1029
1091
  else throw new Error(`Unsupported operator: ${op}`);
1030
1092
  params[paramName] = val;
1031
1093
  addTypeHintForParam(type_hints, paramName, col, val);
1032
1094
  }
1033
1095
  }
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
1096
+ const orGroupSql = [];
1097
+ for (const group of state.orWhereGroups) {
1098
+ const orParts = [];
1099
+ for (const key in group) {
1100
+ const value = group[key];
1101
+ const col = findColumn(table, key);
1102
+ p += 1;
1103
+ const paramName = `${table.name}_${key}_${p}`;
1104
+ if (value === null) {
1105
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1106
+ orParts.push(`"${table.name}"."${key}" is null`);
1107
+ } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1108
+ validateInArrayValues(col, key, value, "in");
1109
+ orParts.push(`"${table.name}"."${key}" = ANY(:${paramName})`);
1110
+ params[paramName] = value;
1111
+ addTypeHintForParam(type_hints, paramName, col, value);
1112
+ } else {
1113
+ validateScalarForColumn(col, value, `column ${key}`);
1114
+ orParts.push(`"${table.name}"."${key}" = :${paramName}`);
1115
+ params[paramName] = value;
1116
+ addTypeHintForParam(type_hints, paramName, col, value);
1117
+ }
1118
+ }
1119
+ if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
1120
+ }
1121
+ for (const group of state.orOpGroups) {
1122
+ const orParts = [];
1123
+ for (const pred of group) {
1124
+ const key = String(pred.col);
1125
+ const op = String(pred.op);
1126
+ const col = findColumn(table, key);
1127
+ const qualified = `"${table.name}"."${key}"`;
1128
+ if (op === "isnull" || op === "notnull") {
1129
+ if (pred.value !== void 0) throw new Error(`Operator ${op} does not take a value for column ${key}`);
1130
+ orParts.push(`${qualified} is ${op === "isnull" ? "null" : "not null"}`);
1131
+ } else if (op === "in" || op === "notin") {
1132
+ const val = pred.value;
1133
+ if (!Array.isArray(val)) throw new Error(`Operator ${op} requires an array value for column ${key}`);
1134
+ validateInArrayValues(col, key, val, op);
1135
+ p += 1;
1136
+ const paramName = `${table.name}_${key}_${p}`;
1137
+ orParts.push(`${qualified} ${op === "in" ? "= ANY" : "!= ALL"}(:${paramName})`);
1138
+ params[paramName] = val;
1139
+ addTypeHintForParam(type_hints, paramName, col, val);
1140
+ } else if (op === "like" || op === "ilike" || op === "notlike" || op === "notilike") {
1141
+ const val = pred.value;
1142
+ if (typeof val !== "string") throw new Error(`Operator ${op} requires a string value for column ${key}`);
1143
+ p += 1;
1144
+ const paramName = `${table.name}_${key}_${p}`;
1145
+ const sqlOp = op === "like" ? "like" : op === "ilike" ? "ilike" : op === "notlike" ? "not like" : "not ilike";
1146
+ orParts.push(`${qualified} ${sqlOp} :${paramName}`);
1147
+ params[paramName] = val;
1148
+ addTypeHintForParam(type_hints, paramName, col, val);
1149
+ } else {
1150
+ const val = pred.value;
1151
+ if (val === void 0) throw new Error(`Operator ${op} requires a value for column ${key}`);
1152
+ validateComparisonValue(col, key, val, op);
1153
+ p += 1;
1154
+ const paramName = `${table.name}_${key}_${p}`;
1155
+ if (op === "=") orParts.push(`${qualified} = :${paramName}`);
1156
+ else if (op === "!=") orParts.push(`${qualified} <> :${paramName}`);
1157
+ else if (op === "<" || op === "<=" || op === ">" || op === ">=") orParts.push(`${qualified} ${op} :${paramName}`);
1158
+ else throw new Error(`Unsupported operator: ${op}`);
1159
+ params[paramName] = val;
1160
+ addTypeHintForParam(type_hints, paramName, col, val);
1161
+ }
1162
+ }
1163
+ if (orParts.length) orGroupSql.push("(" + orParts.join(" or ") + ")");
1164
+ }
1165
+ if (orGroupSql.length) {
1166
+ const andSql = andParts.length ? `(${andParts.join(" and ")})` : "";
1167
+ const orSql = orGroupSql.join(" or ");
1168
+ const full = andSql ? `${andSql} or ${orSql}` : orSql;
1169
+ if (full.trim().length) parts.push("where " + full);
1170
+ } else if (andParts.length) parts.push("where " + andParts.join(" and "));
1171
+ if (state.order.length) {
1172
+ const orders = [];
1173
+ for (const o of state.order) orders.push(`"${table.name}"."${o.col}" ${o.dir}`);
1174
+ parts.push("order by " + orders.join(", "));
1175
+ }
1176
+ if (state.limit !== void 0) parts.push("limit " + state.limit);
1177
+ if (state.offset !== void 0) parts.push("offset " + state.offset);
1178
+ return {
1179
+ q: parts.join(" "),
1180
+ params: Object.keys(params).length > 0 ? params : void 0,
1181
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1182
+ };
1053
1183
  };
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
1184
  }
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
1185
+ selectFrom(tableName, cols$1) {
1186
+ const jtName = String(tableName);
1187
+ const join = this.s.joins.find((j) => j.target.name === jtName);
1188
+ if (!join) throw new Error(`selectFrom('${jtName}') requires a prior join('${jtName}') call`);
1189
+ const sel = !cols$1 || cols$1.length === 0 ? ["*"] : cols$1.map(String);
1190
+ if (!(sel.length === 1 && sel[0] === "*")) for (const c of sel) findColumn(join.target, String(c));
1191
+ const existing = this.s.joinSelections.find((js) => js.target.name === jtName);
1192
+ if (existing) {
1193
+ if (existing.selected.includes("*")) return this;
1194
+ if (sel.length === 1 && sel[0] === "*") existing.selected = ["*"];
1195
+ else {
1196
+ const set = new Set(existing.selected);
1197
+ for (const c of sel) set.add(String(c));
1198
+ existing.selected = Array.from(set);
1199
+ }
1200
+ } else this.s.joinSelections.push({
1201
+ target: join.target,
1202
+ selected: sel
1169
1203
  });
1204
+ return this;
1170
1205
  }
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}`);
1206
+ andWhere(where) {
1207
+ for (const k in where) this.s.where[k] = where[k];
1208
+ return this;
1204
1209
  }
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);
1210
+ /** @deprecated Use andWhere() instead */
1211
+ where(where) {
1212
+ return this.andWhere(where);
1244
1213
  }
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];
1214
+ orWhere(where) {
1215
+ this.s.orWhereGroups.push(where);
1269
1216
  return this;
1270
- };
1271
- this.wherePk = (pk) => {
1217
+ }
1218
+ wherePk(pk) {
1272
1219
  const pkCols = getPrimaryKeyColumns(table);
1273
1220
  if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1274
1221
  if (pkCols.length === 1) {
@@ -1278,7 +1225,8 @@ var TableQueryImpl = class {
1278
1225
  if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1279
1226
  if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1280
1227
  validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1281
- state.where[colName] = pk;
1228
+ this.s.where[colName] = pk;
1229
+ return this;
1282
1230
  } else {
1283
1231
  if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1284
1232
  const obj = pk;
@@ -1289,146 +1237,336 @@ var TableQueryImpl = class {
1289
1237
  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
1238
  if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1291
1239
  validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1292
- state.where[colName] = v;
1240
+ this.s.where[colName] = v;
1293
1241
  }
1242
+ return this;
1294
1243
  }
1244
+ }
1245
+ andWhereOp(col, op, ...args) {
1246
+ const value = args[0];
1247
+ this.s.andOps.push({
1248
+ col,
1249
+ op,
1250
+ value
1251
+ });
1295
1252
  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
1253
  }
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);
1254
+ orWhereOp(col, op, ...args) {
1255
+ const value = args[0];
1256
+ this.s.orOpGroups.push([{
1257
+ col,
1258
+ op,
1259
+ value
1260
+ }]);
1261
+ return this;
1262
+ }
1263
+ andWhereOpGroup(predicates) {
1264
+ const group = predicates.map((p) => ({
1265
+ col: p[0],
1266
+ op: p[1],
1267
+ value: p[2]
1268
+ }));
1269
+ for (const g of group) this.s.andOps.push(g);
1270
+ return this;
1271
+ }
1272
+ orWhereOpGroup(predicates) {
1273
+ const group = predicates.map((p) => ({
1274
+ col: p[0],
1275
+ op: p[1],
1276
+ value: p[2]
1277
+ }));
1278
+ this.s.orOpGroups.push(group);
1279
+ return this;
1280
+ }
1281
+ orderBy(order) {
1282
+ this.s.order = [];
1283
+ const isValidDir = (d) => d === "asc" || d === "desc";
1284
+ if (typeof order === "string") {
1285
+ findColumn(table, String(order));
1286
+ this.s.order.push({
1287
+ col: order,
1288
+ dir: "asc"
1289
+ });
1290
+ } else for (const item of order) {
1291
+ const col = String(item[0]);
1292
+ const dir = String(item[1]);
1293
+ findColumn(table, col);
1294
+ if (!isValidDir(dir)) throw new Error(`Invalid order direction: ${dir}. Allowed: asc | desc`);
1295
+ this.s.order.push({
1296
+ col: item[0],
1297
+ dir
1298
+ });
1335
1299
  }
1300
+ return this;
1336
1301
  }
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];
1302
+ limit(n) {
1303
+ 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`);
1304
+ this.s.limit = n;
1361
1305
  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];
1306
+ }
1307
+ offset(n) {
1308
+ 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`);
1309
+ this.s.offset = n;
1310
+ return this;
1311
+ }
1312
+ join(tableName, type = "inner") {
1313
+ const target = findTable(schema, String(tableName));
1314
+ const sources = [];
1315
+ for (let i = this.s.joins.length - 1; i >= 0; i--) {
1316
+ const src = this.s.joins[i].target;
1317
+ if (!sources.some((s) => s.name === src.name)) sources.push(src);
1318
+ }
1319
+ if (!sources.some((s) => s.name === table.name)) sources.push(table);
1320
+ let pickedSource = null;
1321
+ let pairs = null;
1322
+ for (const src of sources) {
1323
+ const p = findJoinOn(src, target);
1324
+ if (p && p.length) {
1325
+ pickedSource = src;
1326
+ pairs = p;
1327
+ break;
1377
1328
  }
1378
1329
  }
1379
- 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})`);
1402
- params[paramName] = value;
1403
- addTypeHintForParam(type_hints, paramName, col, value);
1404
- } else {
1405
- validateScalarForColumn(col, value, `column ${key}`);
1406
- whereClauses.push(`"${key}" = :${paramName}`);
1407
- params[paramName] = value;
1408
- addTypeHintForParam(type_hints, paramName, col, value);
1330
+ if (!pairs || !pickedSource) {
1331
+ const candidates = sources.map((s) => s.name).join(", ");
1332
+ throw new Error(`No foreign key relation found between any of [${candidates}] and ${target.name}`);
1409
1333
  }
1334
+ const jt = String(type);
1335
+ if (jt !== "inner" && jt !== "left" && jt !== "right" && jt !== "full") throw new Error(`Invalid join type: ${jt}. Allowed: inner | left | right | full`);
1336
+ this.s.joins.push({
1337
+ type: jt,
1338
+ source: pickedSource,
1339
+ target,
1340
+ on: pairs
1341
+ });
1342
+ return this;
1410
1343
  }
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;
1421
- }
1422
- }();
1344
+ }();
1345
+ }
1346
+ insert(values) {
1347
+ const table = this.table;
1348
+ const schema = this.schema;
1349
+ const state = {
1350
+ values,
1351
+ returning: []
1352
+ };
1353
+ return new class {
1354
+ constructor() {
1355
+ this.returning = (cols) => {
1356
+ state.returning = cols || [];
1357
+ return this;
1358
+ };
1359
+ this.toSql = () => {
1360
+ const cols = [];
1361
+ const vals = [];
1362
+ const params = {};
1363
+ const type_hints = {};
1364
+ let p = 0;
1365
+ for (const key in state.values) {
1366
+ const value = state.values[key];
1367
+ const col = findColumn(table, key);
1368
+ p += 1;
1369
+ const paramName = `${table.name}_${key}_${p}`;
1370
+ cols.push(`"${key}"`);
1371
+ vals.push(`:${paramName}`);
1372
+ params[paramName] = value;
1373
+ addTypeHintForParam(type_hints, paramName, col, value);
1374
+ }
1375
+ const parts = [];
1376
+ parts.push(`insert into "${schema.name}"."${table.name}" (${cols.join(", ")}) values (${vals.join(", ")})`);
1377
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1378
+ return {
1379
+ q: parts.join(" "),
1380
+ params: Object.keys(params).length > 0 ? params : void 0,
1381
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1382
+ };
1383
+ };
1384
+ }
1385
+ }();
1386
+ }
1387
+ update(values) {
1388
+ const table = this.table;
1389
+ const schema = this.schema;
1390
+ const state = {
1391
+ values,
1392
+ where: {},
1393
+ returning: []
1394
+ };
1395
+ return new class {
1396
+ constructor() {
1397
+ this.where = (w) => {
1398
+ for (const k in w) state.where[k] = w[k];
1399
+ return this;
1400
+ };
1401
+ this.wherePk = (pk) => {
1402
+ const pkCols = getPrimaryKeyColumns(table);
1403
+ if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1404
+ if (pkCols.length === 1) {
1405
+ const colName = pkCols[0];
1406
+ const colDef = findColumn(table, colName);
1407
+ if (pk === null || pk === void 0) throw new Error(`wherePk on ${table.name} requires a non-null value for primary key column ${colName}`);
1408
+ if (Array.isArray(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}, not an array`);
1409
+ if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${colName}`);
1410
+ validateScalarForColumn(colDef, pk, `primary key ${table.name}.${colName}`);
1411
+ state.where[colName] = pk;
1412
+ } else {
1413
+ if (!isPlainObject(pk) || pk === null) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1414
+ const obj = pk;
1415
+ for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1416
+ for (const colName of pkCols) {
1417
+ if (!(colName in obj)) throw new Error(`wherePk missing key '${colName}'. Required keys: ${pkCols.join(", ")}`);
1418
+ const v = obj[colName];
1419
+ if (v === null || v === void 0) throw new Error(`wherePk on ${table.name} requires non-null values for all primary key columns (${pkCols.join(", ")})`);
1420
+ if (Array.isArray(v)) throw new Error(`wherePk on ${table.name} expects scalar values for primary key column ${colName}, not an array`);
1421
+ validateScalarForColumn(findColumn(table, colName), v, `primary key ${table.name}.${colName}`);
1422
+ state.where[colName] = v;
1423
+ }
1424
+ }
1425
+ return this;
1426
+ };
1427
+ this.returning = (cols) => {
1428
+ state.returning = cols || [];
1429
+ return this;
1430
+ };
1431
+ this.toSql = () => {
1432
+ const params = {};
1433
+ const type_hints = {};
1434
+ let p = 0;
1435
+ const setParts = [];
1436
+ for (const key in state.values) {
1437
+ const value = state.values[key];
1438
+ const col = findColumn(table, key);
1439
+ p += 1;
1440
+ const paramName = `${table.name}_${key}_${p}`;
1441
+ setParts.push(`"${key}" = :${paramName}`);
1442
+ params[paramName] = value;
1443
+ addTypeHintForParam(type_hints, paramName, col, value);
1444
+ }
1445
+ const whereClauses = [];
1446
+ for (const key in state.where) {
1447
+ const value = state.where[key];
1448
+ const col = findColumn(table, key);
1449
+ p += 1;
1450
+ const paramName = `${table.name}_${key}_${p}`;
1451
+ if (value === null) {
1452
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1453
+ whereClauses.push(`"${key}" is null`);
1454
+ } else if (Array.isArray(value) && !isArrayShapedGeomScalarValue(col, value)) {
1455
+ validateInArrayValues(col, key, value, "in");
1456
+ whereClauses.push(`"${key}" = ANY(:${paramName})`);
1457
+ params[paramName] = value;
1458
+ addTypeHintForParam(type_hints, paramName, col, value);
1459
+ } else {
1460
+ validateScalarForColumn(col, value, `column ${key}`);
1461
+ whereClauses.push(`"${key}" = :${paramName}`);
1462
+ params[paramName] = value;
1463
+ addTypeHintForParam(type_hints, paramName, col, value);
1464
+ }
1465
+ }
1466
+ const parts = [];
1467
+ parts.push(`update "${schema.name}"."${table.name}" set ${setParts.join(", ")}`);
1468
+ if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1469
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1470
+ return {
1471
+ q: parts.join(" "),
1472
+ params: Object.keys(params).length > 0 ? params : void 0,
1473
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1474
+ };
1475
+ };
1476
+ }
1477
+ }();
1478
+ }
1479
+ delete() {
1480
+ const table = this.table;
1481
+ const schema = this.schema;
1482
+ const state = {
1483
+ where: {},
1484
+ returning: []
1485
+ };
1486
+ return new class {
1487
+ constructor() {
1488
+ this.where = (w) => {
1489
+ for (const k in w) state.where[k] = w[k];
1490
+ return this;
1491
+ };
1492
+ this.wherePk = (pk) => {
1493
+ const pkCols = getPrimaryKeyColumns(table);
1494
+ if (!pkCols || pkCols.length === 0) throw new Error(`Table ${table.name} does not have a primary key`);
1495
+ if (pkCols.length === 1) {
1496
+ const col = pkCols[0];
1497
+ if (isPlainObject(pk)) throw new Error(`wherePk on ${table.name} expects a scalar for primary key column ${col}`);
1498
+ state.where[col] = pk;
1499
+ } else {
1500
+ if (!isPlainObject(pk)) throw new Error(`wherePk on ${table.name} requires an object with keys: ${pkCols.join(", ")}`);
1501
+ const obj = pk;
1502
+ for (const k of Object.keys(obj)) if (!pkCols.includes(k)) throw new Error(`wherePk received unknown key '${k}'. Expected keys: ${pkCols.join(", ")}`);
1503
+ for (const col of pkCols) {
1504
+ if (!(col in obj)) throw new Error(`wherePk missing key '${col}'. Required keys: ${pkCols.join(", ")}`);
1505
+ state.where[col] = obj[col];
1506
+ }
1507
+ }
1508
+ return this;
1509
+ };
1510
+ this.returning = (cols) => {
1511
+ state.returning = cols || [];
1512
+ return this;
1513
+ };
1514
+ this.toSql = () => {
1515
+ const params = {};
1516
+ const type_hints = {};
1517
+ let p = 0;
1518
+ const whereClauses = [];
1519
+ for (const key in state.where) {
1520
+ const value = state.where[key];
1521
+ const col = findColumn(table, key);
1522
+ p += 1;
1523
+ const paramName = `${table.name}_${key}_${p}`;
1524
+ if (value === null) {
1525
+ if (!col.is_nullable) throw new Error(`Column ${table.name}.${key} is not nullable; cannot compare to null`);
1526
+ whereClauses.push(`"${key}" is null`);
1527
+ } else if (Array.isArray(value)) {
1528
+ validateInArrayValues(col, key, value, "in");
1529
+ whereClauses.push(`"${key}" = ANY(:${paramName})`);
1530
+ params[paramName] = value;
1531
+ addTypeHintForParam(type_hints, paramName, col, value);
1532
+ } else {
1533
+ validateScalarForColumn(col, value, `column ${key}`);
1534
+ whereClauses.push(`"${key}" = :${paramName}`);
1535
+ params[paramName] = value;
1536
+ addTypeHintForParam(type_hints, paramName, col, value);
1537
+ }
1538
+ }
1539
+ const parts = [];
1540
+ parts.push(`delete from "${schema.name}"."${table.name}"`);
1541
+ if (whereClauses.length) parts.push("where " + whereClauses.join(" and "));
1542
+ if (state.returning.length) parts.push("returning " + state.returning.join(", "));
1543
+ return {
1544
+ q: parts.join(" "),
1545
+ params: Object.keys(params).length > 0 ? params : void 0,
1546
+ type_hints: Object.keys(type_hints).length ? type_hints : void 0
1547
+ };
1548
+ };
1549
+ }
1550
+ }();
1551
+ }
1552
+ };
1553
+ function createSqlBuilder(schema) {
1554
+ return { table: (name) => new TableQueryImpl(schema, String(name)) };
1423
1555
  }
1424
- };
1425
- function createSqlBuilder(schema) {
1426
- return { table: (name) => new TableQueryImpl(schema, String(name)) };
1427
- }
1556
+
1557
+ //#endregion
1558
+ //#region src/index.ts
1559
+ /**
1560
+ * @author Martin Høgh <mh@mapcentia.com>
1561
+ * @copyright 2013-2026 MapCentia ApS
1562
+ * @license https://opensource.org/license/mit The MIT License
1563
+ *
1564
+ */
1428
1565
 
1429
1566
  //#endregion
1430
1567
  exports.Claims = Claims;
1431
1568
  exports.CodeFlow = CodeFlow;
1569
+ exports.Gql = Gql;
1432
1570
  exports.Meta = Meta;
1433
1571
  exports.PasswordFlow = PasswordFlow;
1434
1572
  exports.Rpc = Rpc;