@tinycloud/sdk-services 2.4.0-beta.1 → 2.4.0-beta.11
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/dist/index.cjs +284 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +283 -44
- package/dist/index.js.map +1 -1
- package/dist/kv/index.cjs +28 -21
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +12 -0
- package/dist/kv/index.d.ts +12 -0
- package/dist/kv/index.js +28 -21
- package/dist/kv/index.js.map +1 -1
- package/dist/sql/index.cjs +247 -16
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +70 -2
- package/dist/sql/index.d.ts +70 -2
- package/dist/sql/index.js +246 -16
- package/dist/sql/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -52,6 +52,7 @@ __export(index_exports, {
|
|
|
52
52
|
RetryPolicySchema: () => RetryPolicySchema,
|
|
53
53
|
SECRET_NAME_RE: () => SECRET_NAME_RE,
|
|
54
54
|
SQLAction: () => SQLAction,
|
|
55
|
+
SQLMigrations: () => SQLMigrations,
|
|
55
56
|
SQLService: () => SQLService,
|
|
56
57
|
SecretsService: () => SecretsService,
|
|
57
58
|
ServiceContext: () => ServiceContext,
|
|
@@ -1113,6 +1114,31 @@ var KVService = class extends BaseService {
|
|
|
1113
1114
|
}
|
|
1114
1115
|
return void 0;
|
|
1115
1116
|
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Classify a KV 404 by reading the response body once.
|
|
1119
|
+
*
|
|
1120
|
+
* The server returns 404 both for a genuinely missing key AND for an
|
|
1121
|
+
* un-hosted space (body "Space not found"). Previously get/head/delete
|
|
1122
|
+
* collapsed every 404 to KV_NOT_FOUND before reading the body, so an
|
|
1123
|
+
* un-hosted-space read was indistinguishable from a missing key. We now
|
|
1124
|
+
* preserve status + the "Space not found" body for the un-hosted case (so the
|
|
1125
|
+
* CLI/SDK can normalize it to SPACE_NOT_HOSTED, matching put/list/sql), and
|
|
1126
|
+
* fall through to KV_NOT_FOUND for a real missing key.
|
|
1127
|
+
*/
|
|
1128
|
+
async classifyNotFound(response, key) {
|
|
1129
|
+
const errorText = await response.text();
|
|
1130
|
+
if (/space not found/i.test(errorText)) {
|
|
1131
|
+
return err(
|
|
1132
|
+
serviceError(
|
|
1133
|
+
ErrorCodes.KV_NOT_FOUND,
|
|
1134
|
+
`KV ${response.status} - ${errorText}`,
|
|
1135
|
+
"kv",
|
|
1136
|
+
{ meta: { status: response.status, statusText: response.statusText } }
|
|
1137
|
+
)
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
return err(serviceError(ErrorCodes.KV_NOT_FOUND, `Key not found: ${key}`, "kv"));
|
|
1141
|
+
}
|
|
1116
1142
|
/**
|
|
1117
1143
|
* Get the full path with optional prefix.
|
|
1118
1144
|
*
|
|
@@ -1359,13 +1385,7 @@ var KVService = class extends BaseService {
|
|
|
1359
1385
|
}));
|
|
1360
1386
|
}
|
|
1361
1387
|
if (response.status === 404) {
|
|
1362
|
-
return
|
|
1363
|
-
serviceError(
|
|
1364
|
-
ErrorCodes.KV_NOT_FOUND,
|
|
1365
|
-
`Key not found: ${key}`,
|
|
1366
|
-
"kv"
|
|
1367
|
-
)
|
|
1368
|
-
);
|
|
1388
|
+
return this.classifyNotFound(response, key);
|
|
1369
1389
|
}
|
|
1370
1390
|
const errorText = await response.text();
|
|
1371
1391
|
return err(
|
|
@@ -1626,13 +1646,7 @@ var KVService = class extends BaseService {
|
|
|
1626
1646
|
}));
|
|
1627
1647
|
}
|
|
1628
1648
|
if (response.status === 404) {
|
|
1629
|
-
return
|
|
1630
|
-
serviceError(
|
|
1631
|
-
ErrorCodes.KV_NOT_FOUND,
|
|
1632
|
-
`Key not found: ${key}`,
|
|
1633
|
-
"kv"
|
|
1634
|
-
)
|
|
1635
|
-
);
|
|
1649
|
+
return this.classifyNotFound(response, key);
|
|
1636
1650
|
}
|
|
1637
1651
|
const errorText = await response.text();
|
|
1638
1652
|
return err(
|
|
@@ -1677,13 +1691,7 @@ var KVService = class extends BaseService {
|
|
|
1677
1691
|
}));
|
|
1678
1692
|
}
|
|
1679
1693
|
if (response.status === 404) {
|
|
1680
|
-
return
|
|
1681
|
-
serviceError(
|
|
1682
|
-
ErrorCodes.KV_NOT_FOUND,
|
|
1683
|
-
`Key not found: ${key}`,
|
|
1684
|
-
"kv"
|
|
1685
|
-
)
|
|
1686
|
-
);
|
|
1694
|
+
return this.classifyNotFound(response, key);
|
|
1687
1695
|
}
|
|
1688
1696
|
const errorText = await response.text();
|
|
1689
1697
|
return err(
|
|
@@ -1810,11 +1818,59 @@ var KVService = class extends BaseService {
|
|
|
1810
1818
|
*/
|
|
1811
1819
|
KVService.serviceName = "kv";
|
|
1812
1820
|
|
|
1821
|
+
// src/responseErrors.ts
|
|
1822
|
+
function parseServiceErrorBody(errorText) {
|
|
1823
|
+
try {
|
|
1824
|
+
return JSON.parse(errorText);
|
|
1825
|
+
} catch {
|
|
1826
|
+
return {};
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
function formatServiceResponseError(serviceLabel, operation, status, errorText, parsed) {
|
|
1830
|
+
if (parsed.message) {
|
|
1831
|
+
return compactMessage(parsed.message);
|
|
1832
|
+
}
|
|
1833
|
+
if (looksLikeHtml(errorText)) {
|
|
1834
|
+
if (status === 524 || /524\s*[:-]/i.test(errorText) || /a timeout occurred/i.test(errorText)) {
|
|
1835
|
+
return `${serviceLabel} ${operation} failed: upstream request timed out. Please retry.`;
|
|
1836
|
+
}
|
|
1837
|
+
return `${serviceLabel} ${operation} failed: upstream service returned an HTML error page (${status}).`;
|
|
1838
|
+
}
|
|
1839
|
+
return `${serviceLabel} ${operation} failed: ${status} - ${compactMessage(errorText)}`;
|
|
1840
|
+
}
|
|
1841
|
+
function responseErrorMeta(status, statusText, errorText) {
|
|
1842
|
+
const meta = { status, statusText };
|
|
1843
|
+
const snippet = compactMessage(errorText);
|
|
1844
|
+
if (snippet) {
|
|
1845
|
+
meta.responseSnippet = snippet.slice(0, 300);
|
|
1846
|
+
}
|
|
1847
|
+
return meta;
|
|
1848
|
+
}
|
|
1849
|
+
function looksLikeHtml(text) {
|
|
1850
|
+
return /<!doctype html/i.test(text) || /<html[\s>]/i.test(text);
|
|
1851
|
+
}
|
|
1852
|
+
function compactMessage(message) {
|
|
1853
|
+
const compact = message.replace(/\s+/g, " ").trim();
|
|
1854
|
+
return compact.length > 500 ? `${compact.slice(0, 500)}...` : compact;
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
// src/sql/SQLMigrations.ts
|
|
1858
|
+
var SQLMigrations = class {
|
|
1859
|
+
constructor(service, dbName) {
|
|
1860
|
+
this.service = service;
|
|
1861
|
+
this.dbName = dbName;
|
|
1862
|
+
}
|
|
1863
|
+
apply(options) {
|
|
1864
|
+
return this.service.applyMigrationsOnDb(this.dbName, options);
|
|
1865
|
+
}
|
|
1866
|
+
};
|
|
1867
|
+
|
|
1813
1868
|
// src/sql/DatabaseHandle.ts
|
|
1814
1869
|
var DatabaseHandle = class {
|
|
1815
1870
|
constructor(service, name) {
|
|
1816
1871
|
this.service = service;
|
|
1817
1872
|
this.name = name;
|
|
1873
|
+
this.migrations = new SQLMigrations(service, name);
|
|
1818
1874
|
}
|
|
1819
1875
|
async query(sql, params, options) {
|
|
1820
1876
|
return this.service.queryOnDb(this.name, sql, params, options);
|
|
@@ -1837,6 +1893,7 @@ var DatabaseHandle = class {
|
|
|
1837
1893
|
var SQLAction = {
|
|
1838
1894
|
READ: "tinycloud.sql/read",
|
|
1839
1895
|
WRITE: "tinycloud.sql/write",
|
|
1896
|
+
DDL: "tinycloud.sql/ddl",
|
|
1840
1897
|
ADMIN: "tinycloud.sql/admin",
|
|
1841
1898
|
SELECT: "tinycloud.sql/select",
|
|
1842
1899
|
INSERT: "tinycloud.sql/insert",
|
|
@@ -1848,9 +1905,21 @@ var SQLAction = {
|
|
|
1848
1905
|
};
|
|
1849
1906
|
|
|
1850
1907
|
// src/sql/SQLService.ts
|
|
1908
|
+
var DDL_TOKENS = /* @__PURE__ */ new Set(["alter", "create", "drop"]);
|
|
1909
|
+
var MIGRATIONS_TABLE = "__tinycloud_sql_migrations";
|
|
1910
|
+
var MIGRATIONS_SCHEMA = `CREATE TABLE IF NOT EXISTS ${MIGRATIONS_TABLE} (
|
|
1911
|
+
key TEXT PRIMARY KEY,
|
|
1912
|
+
namespace TEXT NOT NULL,
|
|
1913
|
+
id TEXT NOT NULL,
|
|
1914
|
+
applied_at TEXT NOT NULL,
|
|
1915
|
+
statement_count INTEGER NOT NULL
|
|
1916
|
+
)`;
|
|
1917
|
+
var MIGRATIONS_META_NAMESPACE = "tinycloud.sql.migrations";
|
|
1918
|
+
var MIGRATIONS_META_ID = "000_metadata";
|
|
1851
1919
|
var SQLService = class extends BaseService {
|
|
1852
1920
|
constructor(config = {}) {
|
|
1853
1921
|
super();
|
|
1922
|
+
this.migrationLocks = /* @__PURE__ */ new Map();
|
|
1854
1923
|
this._config = config;
|
|
1855
1924
|
}
|
|
1856
1925
|
get config() {
|
|
@@ -1886,6 +1955,24 @@ var SQLService = class extends BaseService {
|
|
|
1886
1955
|
async batch(statements, options) {
|
|
1887
1956
|
return this.batchOnDb(this.defaultDbName, statements, options);
|
|
1888
1957
|
}
|
|
1958
|
+
async applyMigrationsOnDb(dbName, options) {
|
|
1959
|
+
const validationError = validateMigrationOptions(options);
|
|
1960
|
+
if (validationError) {
|
|
1961
|
+
return err(serviceError(ErrorCodes.INVALID_INPUT, validationError, "sql"));
|
|
1962
|
+
}
|
|
1963
|
+
const lockKey = `${dbName}\0${options.namespace}`;
|
|
1964
|
+
const existing = this.migrationLocks.get(lockKey);
|
|
1965
|
+
if (existing) {
|
|
1966
|
+
return existing;
|
|
1967
|
+
}
|
|
1968
|
+
const promise = this.applyMigrationsOnDbUnlocked(dbName, options);
|
|
1969
|
+
this.migrationLocks.set(lockKey, promise);
|
|
1970
|
+
try {
|
|
1971
|
+
return await promise;
|
|
1972
|
+
} finally {
|
|
1973
|
+
this.migrationLocks.delete(lockKey);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1889
1976
|
// === Internal methods called by DatabaseHandle ===
|
|
1890
1977
|
async queryOnDb(dbName, sql, params, options) {
|
|
1891
1978
|
return this.withTelemetry("query", dbName, async () => {
|
|
@@ -1923,9 +2010,15 @@ var SQLService = class extends BaseService {
|
|
|
1923
2010
|
if (options?.schema) {
|
|
1924
2011
|
body.schema = options.schema;
|
|
1925
2012
|
}
|
|
2013
|
+
const actions = [
|
|
2014
|
+
this.actionForSql(sql, SQLAction.WRITE),
|
|
2015
|
+
...(options?.schema ?? []).map(
|
|
2016
|
+
(statement) => this.actionForSql(statement, SQLAction.DDL)
|
|
2017
|
+
)
|
|
2018
|
+
];
|
|
1926
2019
|
const response = await this.invokeSQL(
|
|
1927
2020
|
dbName,
|
|
1928
|
-
this.
|
|
2021
|
+
this.dedupeActions(actions),
|
|
1929
2022
|
body,
|
|
1930
2023
|
options?.signal
|
|
1931
2024
|
);
|
|
@@ -1947,7 +2040,7 @@ var SQLService = class extends BaseService {
|
|
|
1947
2040
|
try {
|
|
1948
2041
|
const response = await this.invokeSQL(
|
|
1949
2042
|
dbName,
|
|
1950
|
-
this.
|
|
2043
|
+
this.actionsForSqlBatch(statements),
|
|
1951
2044
|
{ action: "batch", statements },
|
|
1952
2045
|
options?.signal
|
|
1953
2046
|
);
|
|
@@ -2010,10 +2103,83 @@ var SQLService = class extends BaseService {
|
|
|
2010
2103
|
}
|
|
2011
2104
|
});
|
|
2012
2105
|
}
|
|
2106
|
+
async applyMigrationsOnDbUnlocked(dbName, options) {
|
|
2107
|
+
return this.withTelemetry("migrations.apply", dbName, async () => {
|
|
2108
|
+
const created = await this.ensureMigrationsTable(dbName, options.signal);
|
|
2109
|
+
if (!created.ok) return created;
|
|
2110
|
+
const listed = await this.queryOnDb(
|
|
2111
|
+
dbName,
|
|
2112
|
+
`SELECT id FROM ${MIGRATIONS_TABLE} WHERE namespace = ? ORDER BY applied_at, id`,
|
|
2113
|
+
[options.namespace],
|
|
2114
|
+
{ signal: options.signal }
|
|
2115
|
+
);
|
|
2116
|
+
if (!listed.ok) return listed;
|
|
2117
|
+
const appliedIds = new Set(
|
|
2118
|
+
listed.data.rows.map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
|
|
2119
|
+
);
|
|
2120
|
+
const skipped = options.migrations.filter((migration) => appliedIds.has(migration.id)).map((migration) => migration.id);
|
|
2121
|
+
const pending = options.migrations.filter((migration) => !appliedIds.has(migration.id));
|
|
2122
|
+
const applied = [];
|
|
2123
|
+
for (const migration of pending) {
|
|
2124
|
+
const result = await this.applyOneMigration(dbName, options.namespace, migration, options.signal);
|
|
2125
|
+
if (!result.ok) return result;
|
|
2126
|
+
applied.push(migration.id);
|
|
2127
|
+
}
|
|
2128
|
+
return ok({
|
|
2129
|
+
database: dbName,
|
|
2130
|
+
namespace: options.namespace,
|
|
2131
|
+
status: applied.length > 0 ? "applied" : "already_current",
|
|
2132
|
+
applied,
|
|
2133
|
+
skipped
|
|
2134
|
+
});
|
|
2135
|
+
});
|
|
2136
|
+
}
|
|
2137
|
+
async applyOneMigration(dbName, namespace, migration, signal) {
|
|
2138
|
+
const statements = [
|
|
2139
|
+
...migration.sql.map(
|
|
2140
|
+
(statement) => typeof statement === "string" ? { sql: statement } : statement
|
|
2141
|
+
),
|
|
2142
|
+
{
|
|
2143
|
+
sql: `INSERT OR REPLACE INTO ${MIGRATIONS_TABLE} (key, namespace, id, applied_at, statement_count) VALUES (?, ?, ?, ?, ?)`,
|
|
2144
|
+
params: [
|
|
2145
|
+
migrationKey(namespace, migration.id),
|
|
2146
|
+
namespace,
|
|
2147
|
+
migration.id,
|
|
2148
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
2149
|
+
migration.sql.length
|
|
2150
|
+
]
|
|
2151
|
+
}
|
|
2152
|
+
];
|
|
2153
|
+
const result = await this.batchOnDb(dbName, statements, { signal });
|
|
2154
|
+
if (!result.ok) return result;
|
|
2155
|
+
return ok(void 0);
|
|
2156
|
+
}
|
|
2157
|
+
async ensureMigrationsTable(dbName, signal) {
|
|
2158
|
+
const result = await this.batchOnDb(
|
|
2159
|
+
dbName,
|
|
2160
|
+
[
|
|
2161
|
+
{ sql: MIGRATIONS_SCHEMA },
|
|
2162
|
+
{
|
|
2163
|
+
sql: `INSERT OR REPLACE INTO ${MIGRATIONS_TABLE} (key, namespace, id, applied_at, statement_count) VALUES (?, ?, ?, ?, ?)`,
|
|
2164
|
+
params: [
|
|
2165
|
+
migrationKey(MIGRATIONS_META_NAMESPACE, MIGRATIONS_META_ID),
|
|
2166
|
+
MIGRATIONS_META_NAMESPACE,
|
|
2167
|
+
MIGRATIONS_META_ID,
|
|
2168
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
2169
|
+
1
|
|
2170
|
+
]
|
|
2171
|
+
}
|
|
2172
|
+
],
|
|
2173
|
+
{ signal }
|
|
2174
|
+
);
|
|
2175
|
+
if (!result.ok) return result;
|
|
2176
|
+
return ok(void 0);
|
|
2177
|
+
}
|
|
2013
2178
|
// === Private helpers ===
|
|
2014
|
-
async invokeSQL(dbName,
|
|
2179
|
+
async invokeSQL(dbName, actions, body, signal) {
|
|
2015
2180
|
const session = this.context.session;
|
|
2016
|
-
const
|
|
2181
|
+
const actionList = Array.isArray(actions) ? actions : [actions];
|
|
2182
|
+
const headers = actionList.length === 1 ? this.context.invoke(session, "sql", dbName, actionList[0]) : this.invokeSQLAny(session, dbName, actionList);
|
|
2017
2183
|
return this.context.fetch(`${this.host}/invoke`, {
|
|
2018
2184
|
method: "POST",
|
|
2019
2185
|
headers: {
|
|
@@ -2025,26 +2191,50 @@ var SQLService = class extends BaseService {
|
|
|
2025
2191
|
});
|
|
2026
2192
|
}
|
|
2027
2193
|
actionForSql(sql, fallback) {
|
|
2028
|
-
|
|
2194
|
+
const token = firstSqlToken(sql);
|
|
2195
|
+
if (token === "pragma") return SQLAction.ADMIN;
|
|
2196
|
+
if (token !== void 0 && DDL_TOKENS.has(token)) return SQLAction.DDL;
|
|
2197
|
+
return fallback;
|
|
2198
|
+
}
|
|
2199
|
+
actionsForSqlBatch(statements) {
|
|
2200
|
+
return this.dedupeActions(
|
|
2201
|
+
statements.map((statement) => this.actionForSql(statement.sql, SQLAction.WRITE))
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
dedupeActions(actions) {
|
|
2205
|
+
return [...new Set(actions)];
|
|
2029
2206
|
}
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2207
|
+
invokeSQLAny(session, dbName, actions) {
|
|
2208
|
+
if (!this.context.invokeAny) {
|
|
2209
|
+
throw new Error(
|
|
2210
|
+
`SQL operation requires multiple permissions (${actions.join(", ")}) but this SDK runtime does not support multi-resource invocations`
|
|
2211
|
+
);
|
|
2212
|
+
}
|
|
2213
|
+
return this.context.invokeAny(
|
|
2214
|
+
session,
|
|
2215
|
+
actions.map((action) => ({
|
|
2216
|
+
spaceId: session.spaceId,
|
|
2217
|
+
service: "sql",
|
|
2218
|
+
path: dbName,
|
|
2219
|
+
action
|
|
2220
|
+
}))
|
|
2221
|
+
);
|
|
2034
2222
|
}
|
|
2035
2223
|
async handleErrorResponse(response, operation) {
|
|
2036
2224
|
const errorText = await response.text();
|
|
2037
|
-
|
|
2038
|
-
try {
|
|
2039
|
-
errorBody = JSON.parse(errorText);
|
|
2040
|
-
} catch {
|
|
2041
|
-
}
|
|
2225
|
+
const errorBody = parseServiceErrorBody(errorText);
|
|
2042
2226
|
const errorCode = this.mapHttpStatusToErrorCode(
|
|
2043
2227
|
response.status,
|
|
2044
2228
|
errorBody.error
|
|
2045
2229
|
);
|
|
2046
|
-
const message =
|
|
2047
|
-
|
|
2230
|
+
const message = formatServiceResponseError(
|
|
2231
|
+
"SQL",
|
|
2232
|
+
operation,
|
|
2233
|
+
response.status,
|
|
2234
|
+
errorText,
|
|
2235
|
+
errorBody
|
|
2236
|
+
);
|
|
2237
|
+
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
2048
2238
|
if (response.status === 401) {
|
|
2049
2239
|
const { resource, action } = parseAuthError(errorText);
|
|
2050
2240
|
if (action) meta.requiredAction = action;
|
|
@@ -2104,6 +2294,53 @@ function firstSqlToken(sql) {
|
|
|
2104
2294
|
const match = /^[A-Za-z_]+/.exec(sql.slice(index));
|
|
2105
2295
|
return match?.[0].toLowerCase();
|
|
2106
2296
|
}
|
|
2297
|
+
function validateMigrationOptions(options) {
|
|
2298
|
+
if (!options || typeof options !== "object") {
|
|
2299
|
+
return "SQL migrations require options";
|
|
2300
|
+
}
|
|
2301
|
+
if (!options.namespace || typeof options.namespace !== "string") {
|
|
2302
|
+
return "SQL migrations require a non-empty namespace";
|
|
2303
|
+
}
|
|
2304
|
+
if (!Array.isArray(options.migrations)) {
|
|
2305
|
+
return "SQL migrations require an ordered migrations array";
|
|
2306
|
+
}
|
|
2307
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2308
|
+
for (const migration of options.migrations) {
|
|
2309
|
+
if (!migration.id || typeof migration.id !== "string") {
|
|
2310
|
+
return "SQL migrations require every migration to have a non-empty id";
|
|
2311
|
+
}
|
|
2312
|
+
if (ids.has(migration.id)) {
|
|
2313
|
+
return `Duplicate SQL migration id: ${migration.id}`;
|
|
2314
|
+
}
|
|
2315
|
+
ids.add(migration.id);
|
|
2316
|
+
if (!Array.isArray(migration.sql)) {
|
|
2317
|
+
return `SQL migration ${migration.id} requires a sql array`;
|
|
2318
|
+
}
|
|
2319
|
+
for (const statement of migration.sql) {
|
|
2320
|
+
if (typeof statement === "string") {
|
|
2321
|
+
if (statement.trim() === "") {
|
|
2322
|
+
return `SQL migration ${migration.id} contains an empty statement`;
|
|
2323
|
+
}
|
|
2324
|
+
continue;
|
|
2325
|
+
}
|
|
2326
|
+
if (!statement || typeof statement.sql !== "string" || statement.sql.trim() === "") {
|
|
2327
|
+
return `SQL migration ${migration.id} contains an invalid statement`;
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
return null;
|
|
2332
|
+
}
|
|
2333
|
+
function migrationKey(namespace, id) {
|
|
2334
|
+
return `${encodeURIComponent(namespace)}:${encodeURIComponent(id)}`;
|
|
2335
|
+
}
|
|
2336
|
+
function rowValue(row, index) {
|
|
2337
|
+
if (Array.isArray(row)) return row[index];
|
|
2338
|
+
if (row && typeof row === "object") {
|
|
2339
|
+
const values = Object.values(row);
|
|
2340
|
+
return values[index];
|
|
2341
|
+
}
|
|
2342
|
+
return void 0;
|
|
2343
|
+
}
|
|
2107
2344
|
|
|
2108
2345
|
// src/duckdb/DuckDbDatabaseHandle.ts
|
|
2109
2346
|
var DuckDbDatabaseHandle = class {
|
|
@@ -2413,17 +2650,19 @@ var DuckDbService = class extends BaseService {
|
|
|
2413
2650
|
}
|
|
2414
2651
|
async handleErrorResponse(response, operation) {
|
|
2415
2652
|
const errorText = await response.text();
|
|
2416
|
-
|
|
2417
|
-
try {
|
|
2418
|
-
errorBody = JSON.parse(errorText);
|
|
2419
|
-
} catch {
|
|
2420
|
-
}
|
|
2653
|
+
const errorBody = parseServiceErrorBody(errorText);
|
|
2421
2654
|
const errorCode = this.mapHttpStatusToErrorCode(
|
|
2422
2655
|
response.status,
|
|
2423
2656
|
errorBody.error
|
|
2424
2657
|
);
|
|
2425
|
-
const message =
|
|
2426
|
-
|
|
2658
|
+
const message = formatServiceResponseError(
|
|
2659
|
+
"DuckDB",
|
|
2660
|
+
operation,
|
|
2661
|
+
response.status,
|
|
2662
|
+
errorText,
|
|
2663
|
+
errorBody
|
|
2664
|
+
);
|
|
2665
|
+
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
2427
2666
|
if (response.status === 401) {
|
|
2428
2667
|
const { resource, action } = parseAuthError(errorText);
|
|
2429
2668
|
if (action) meta.requiredAction = action;
|
|
@@ -5772,6 +6011,7 @@ EncryptionService.serviceName = "encryption";
|
|
|
5772
6011
|
RetryPolicySchema,
|
|
5773
6012
|
SECRET_NAME_RE,
|
|
5774
6013
|
SQLAction,
|
|
6014
|
+
SQLMigrations,
|
|
5775
6015
|
SQLService,
|
|
5776
6016
|
SecretsService,
|
|
5777
6017
|
ServiceContext,
|