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