@tinycloud/sdk-services 3.1.0-beta.1 → 3.1.0-beta.10
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/{BaseService-BhpVpA9b.d.cts → BaseService-B_UKhVht.d.ts} +74 -2
- package/dist/{BaseService-CuV-ZVPs.d.ts → BaseService-DWbPbov7.d.cts} +74 -2
- package/dist/encryption/index.cjs +199 -100
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.d.cts +2 -2
- package/dist/encryption/index.d.ts +2 -2
- package/dist/encryption/index.js +199 -100
- package/dist/encryption/index.js.map +1 -1
- package/dist/index.cjs +739 -258
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -42
- package/dist/index.d.ts +66 -42
- package/dist/index.js +714 -240
- package/dist/index.js.map +1 -1
- package/dist/internal/decrypt-transport-response-error.d.cts +1 -1
- package/dist/internal/decrypt-transport-response-error.d.ts +1 -1
- package/dist/kv/index.cjs +568 -74
- package/dist/kv/index.cjs.map +1 -1
- package/dist/kv/index.d.cts +197 -15
- package/dist/kv/index.d.ts +197 -15
- package/dist/kv/index.js +568 -74
- package/dist/kv/index.js.map +1 -1
- package/dist/sql/index.cjs +191 -35
- package/dist/sql/index.cjs.map +1 -1
- package/dist/sql/index.d.cts +6 -3
- package/dist/sql/index.d.ts +6 -3
- package/dist/sql/index.js +182 -26
- package/dist/sql/index.js.map +1 -1
- package/dist/{types-qwMmB7qB.d.cts → types-CVwwxqXF.d.cts} +8 -0
- package/dist/{types-qwMmB7qB.d.ts → types-CVwwxqXF.d.ts} +8 -0
- package/package.json +3 -3
package/dist/sql/index.cjs
CHANGED
|
@@ -34,6 +34,10 @@ var ErrorCodes = {
|
|
|
34
34
|
AUTH_EXPIRED: "AUTH_EXPIRED",
|
|
35
35
|
AUTH_REQUIRED: "AUTH_REQUIRED",
|
|
36
36
|
AUTH_UNAUTHORIZED: "AUTH_UNAUTHORIZED",
|
|
37
|
+
/** HTTP 401: the delegation the invocation cites was revoked. */
|
|
38
|
+
AUTH_DELEGATION_REVOKED: "AUTH_DELEGATION_REVOKED",
|
|
39
|
+
/** HTTP 401: a delegation the cited one rests on was revoked. */
|
|
40
|
+
AUTH_DELEGATION_ANCESTOR_REVOKED: "AUTH_DELEGATION_ANCESTOR_REVOKED",
|
|
37
41
|
NETWORK_ERROR: "NETWORK_ERROR",
|
|
38
42
|
TIMEOUT: "TIMEOUT",
|
|
39
43
|
ABORTED: "ABORTED",
|
|
@@ -45,6 +49,10 @@ var ErrorCodes = {
|
|
|
45
49
|
KV_PRECONDITION_FAILED: "KV_PRECONDITION_FAILED",
|
|
46
50
|
KV_CONFLICT: "KV_CONFLICT",
|
|
47
51
|
KV_RESPONSE_TOO_LARGE: "KV_RESPONSE_TOO_LARGE",
|
|
52
|
+
/** HTTP 410 from the change feed: discard sync state and restart without a cursor; `meta.reason` says why. */
|
|
53
|
+
KV_SYNC_RESET_REQUIRED: "KV_SYNC_RESET_REQUIRED",
|
|
54
|
+
/** HTTP 403 from the change feed: the retention grant was refused; `meta.reason` says why. */
|
|
55
|
+
KV_RETENTION_GRANT_REFUSED: "KV_RETENTION_GRANT_REFUSED",
|
|
48
56
|
// SQL-specific errors
|
|
49
57
|
SQL_ERROR: "SQL_ERROR",
|
|
50
58
|
SQL_PERMISSION_DENIED: "SQL_PERMISSION_DENIED",
|
|
@@ -100,6 +108,7 @@ function serviceError(code, message, service, options) {
|
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
// src/errors.ts
|
|
111
|
+
var import_bootstrap = require("@tinycloud/bootstrap");
|
|
103
112
|
function authRequiredError(service) {
|
|
104
113
|
return {
|
|
105
114
|
code: ErrorCodes.AUTH_REQUIRED,
|
|
@@ -107,11 +116,31 @@ function authRequiredError(service) {
|
|
|
107
116
|
service
|
|
108
117
|
};
|
|
109
118
|
}
|
|
110
|
-
|
|
119
|
+
var RequestTimeoutError = class extends Error {
|
|
120
|
+
constructor(timeoutMs) {
|
|
121
|
+
super(`Request timed out after ${timeoutMs}ms.`);
|
|
122
|
+
this.name = "TimeoutError";
|
|
123
|
+
this.timeoutMs = timeoutMs;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
function isRequestTimeoutError(error) {
|
|
127
|
+
return error instanceof RequestTimeoutError || error instanceof Error && error.name === "TimeoutError" && typeof error.timeoutMs === "number";
|
|
128
|
+
}
|
|
129
|
+
function timeoutError(service, timeoutMs, cause) {
|
|
130
|
+
if (timeoutMs === void 0) {
|
|
131
|
+
return {
|
|
132
|
+
code: ErrorCodes.TIMEOUT,
|
|
133
|
+
message: "Request timed out.",
|
|
134
|
+
service,
|
|
135
|
+
...cause === void 0 ? {} : { cause }
|
|
136
|
+
};
|
|
137
|
+
}
|
|
111
138
|
return {
|
|
112
139
|
code: ErrorCodes.TIMEOUT,
|
|
113
|
-
message:
|
|
114
|
-
service
|
|
140
|
+
message: `Request timed out after ${timeoutMs}ms.`,
|
|
141
|
+
service,
|
|
142
|
+
...cause === void 0 ? {} : { cause },
|
|
143
|
+
meta: { timeoutMs }
|
|
115
144
|
};
|
|
116
145
|
}
|
|
117
146
|
function abortedError(service) {
|
|
@@ -128,8 +157,47 @@ function parseAuthError(responseText) {
|
|
|
128
157
|
}
|
|
129
158
|
return {};
|
|
130
159
|
}
|
|
160
|
+
var grantableActions = new Set(
|
|
161
|
+
import_bootstrap.CAPABILITY_REGISTRY.map(({ urn }) => urn).filter((urn) => !urn.endsWith("/*"))
|
|
162
|
+
);
|
|
163
|
+
var capabilityServices = new Set(
|
|
164
|
+
import_bootstrap.CAPABILITY_REGISTRY.map(({ service }) => service.slice("tinycloud.".length))
|
|
165
|
+
);
|
|
166
|
+
function storageQuotaExceededError(service, message, meta) {
|
|
167
|
+
return {
|
|
168
|
+
code: ErrorCodes.STORAGE_QUOTA_EXCEEDED,
|
|
169
|
+
message,
|
|
170
|
+
service,
|
|
171
|
+
meta
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function storageLimitReachedError(service, message, meta) {
|
|
175
|
+
return {
|
|
176
|
+
code: ErrorCodes.STORAGE_LIMIT_REACHED,
|
|
177
|
+
message,
|
|
178
|
+
service,
|
|
179
|
+
meta
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
var STORAGE_FULL_MESSAGE = "TinyCloud storage is full, so this change was not saved. Reading still works. Free up space or upgrade your plan to save again.";
|
|
183
|
+
var STORAGE_WRITE_TOO_LARGE_MESSAGE = "This change is larger than the TinyCloud storage you have left, so it was not saved. Reading still works. Free up space or upgrade your plan to save it.";
|
|
184
|
+
function parseStorageQuotaBytes(responseText) {
|
|
185
|
+
const match = responseText.match(/Used:\s*(\d+)\s*bytes,\s*Limit:\s*(\d+)\s*bytes/i);
|
|
186
|
+
if (!match) return void 0;
|
|
187
|
+
return {
|
|
188
|
+
usedBytes: parseInt(match[1], 10),
|
|
189
|
+
limitBytes: parseInt(match[2], 10)
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function storageRejectionError(service, status, meta, responseText) {
|
|
193
|
+
const quotaMeta = { ...meta, ...parseStorageQuotaBytes(responseText) };
|
|
194
|
+
return status === 402 ? storageQuotaExceededError(service, STORAGE_FULL_MESSAGE, quotaMeta) : storageLimitReachedError(service, STORAGE_WRITE_TOO_LARGE_MESSAGE, quotaMeta);
|
|
195
|
+
}
|
|
131
196
|
function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
132
197
|
if (error instanceof Error) {
|
|
198
|
+
if (isRequestTimeoutError(error)) {
|
|
199
|
+
return timeoutError(service, error.timeoutMs, error);
|
|
200
|
+
}
|
|
133
201
|
if (error.name === "AbortError") {
|
|
134
202
|
return abortedError(service);
|
|
135
203
|
}
|
|
@@ -151,6 +219,7 @@ function wrapError(service, error, defaultCode = ErrorCodes.NETWORK_ERROR) {
|
|
|
151
219
|
}
|
|
152
220
|
|
|
153
221
|
// src/base/BaseService.ts
|
|
222
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
154
223
|
var BaseService = class {
|
|
155
224
|
constructor() {
|
|
156
225
|
/**
|
|
@@ -331,6 +400,64 @@ var BaseService = class {
|
|
|
331
400
|
}
|
|
332
401
|
return controller.signal;
|
|
333
402
|
}
|
|
403
|
+
/**
|
|
404
|
+
* Create the abort signal for one request, bounded by the request timeout.
|
|
405
|
+
*
|
|
406
|
+
* The signal aborts when the service signs out, the context aborts, the
|
|
407
|
+
* caller's `signal` aborts, or the timeout elapses, whichever comes first.
|
|
408
|
+
* A timeout aborts with a {@link RequestTimeoutError} (`TimeoutError`), which
|
|
409
|
+
* `wrapError` maps to `ErrorCodes.TIMEOUT`; the other sources keep their own
|
|
410
|
+
* reason (normally `AbortError`, mapped to `ErrorCodes.ABORTED`).
|
|
411
|
+
*
|
|
412
|
+
* The timeout is `timeoutMs` when given, otherwise `config.timeout`. Only a
|
|
413
|
+
* positive, finite value (at most 2^31-1 ms) applies; `undefined`, `0`, and
|
|
414
|
+
* `Infinity` mean no timeout, so a per-call `0` opts out of a configured one.
|
|
415
|
+
*
|
|
416
|
+
* Callers must call `dispose()` once the response body has been consumed,
|
|
417
|
+
* which clears the timer and removes the listeners this adds to the
|
|
418
|
+
* long-lived service and context signals.
|
|
419
|
+
*
|
|
420
|
+
* @param signal - The caller's abort signal for this request
|
|
421
|
+
* @param timeoutMs - Per-request timeout override in milliseconds
|
|
422
|
+
*/
|
|
423
|
+
createRequestSignal(signal, timeoutMs) {
|
|
424
|
+
const controller = new AbortController();
|
|
425
|
+
const detachers = [];
|
|
426
|
+
let timer;
|
|
427
|
+
const dispose = () => {
|
|
428
|
+
if (timer !== void 0) {
|
|
429
|
+
clearTimeout(timer);
|
|
430
|
+
timer = void 0;
|
|
431
|
+
}
|
|
432
|
+
for (const detach of detachers.splice(0)) {
|
|
433
|
+
detach();
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
const abort = (reason) => {
|
|
437
|
+
dispose();
|
|
438
|
+
controller.abort(reason);
|
|
439
|
+
};
|
|
440
|
+
const requestSignal = { signal: controller.signal, dispose };
|
|
441
|
+
const parents = [
|
|
442
|
+
this.abortController.signal,
|
|
443
|
+
this.context?.abortSignal,
|
|
444
|
+
signal
|
|
445
|
+
].filter((parent) => parent !== void 0);
|
|
446
|
+
for (const parent of parents) {
|
|
447
|
+
if (parent.aborted) {
|
|
448
|
+
abort(parent.reason);
|
|
449
|
+
return requestSignal;
|
|
450
|
+
}
|
|
451
|
+
const onAbort = () => abort(parent.reason);
|
|
452
|
+
parent.addEventListener("abort", onAbort, { once: true });
|
|
453
|
+
detachers.push(() => parent.removeEventListener("abort", onAbort));
|
|
454
|
+
}
|
|
455
|
+
const timeout = timeoutMs ?? this._config.timeout;
|
|
456
|
+
if (typeof timeout === "number" && timeout > 0 && timeout <= MAX_TIMER_DELAY_MS) {
|
|
457
|
+
timer = setTimeout(() => abort(new RequestTimeoutError(timeout)), timeout);
|
|
458
|
+
}
|
|
459
|
+
return requestSignal;
|
|
460
|
+
}
|
|
334
461
|
/**
|
|
335
462
|
* Wrap an operation with error handling and telemetry.
|
|
336
463
|
*
|
|
@@ -432,16 +559,16 @@ var DatabaseHandle = class {
|
|
|
432
559
|
};
|
|
433
560
|
|
|
434
561
|
// src/sql/types.ts
|
|
435
|
-
var
|
|
562
|
+
var import_bootstrap2 = require("@tinycloud/bootstrap");
|
|
436
563
|
var SQLAction = {
|
|
437
|
-
READ:
|
|
438
|
-
WRITE:
|
|
439
|
-
SCHEMA:
|
|
440
|
-
ADMIN:
|
|
441
|
-
SELECT:
|
|
442
|
-
EXECUTE:
|
|
443
|
-
EXPORT:
|
|
444
|
-
ALL:
|
|
564
|
+
READ: import_bootstrap2.SQL.READ,
|
|
565
|
+
WRITE: import_bootstrap2.SQL.WRITE,
|
|
566
|
+
SCHEMA: import_bootstrap2.SQL.SCHEMA,
|
|
567
|
+
ADMIN: import_bootstrap2.SQL.ADMIN,
|
|
568
|
+
SELECT: import_bootstrap2.SQL.SELECT,
|
|
569
|
+
EXECUTE: import_bootstrap2.SQL.EXECUTE,
|
|
570
|
+
EXPORT: import_bootstrap2.SQL.EXPORT,
|
|
571
|
+
ALL: import_bootstrap2.SQL.ALL
|
|
445
572
|
};
|
|
446
573
|
|
|
447
574
|
// src/sql/SQLService.ts
|
|
@@ -519,6 +646,7 @@ var SQLService = class extends BaseService {
|
|
|
519
646
|
if (!this.requireAuth()) {
|
|
520
647
|
return err(authRequiredError("sql"));
|
|
521
648
|
}
|
|
649
|
+
const request = this.createRequestSignal(options?.signal);
|
|
522
650
|
try {
|
|
523
651
|
const body = {
|
|
524
652
|
action: "query",
|
|
@@ -527,19 +655,22 @@ var SQLService = class extends BaseService {
|
|
|
527
655
|
};
|
|
528
656
|
if (options?.maxRows !== void 0) body.maxRows = options.maxRows;
|
|
529
657
|
if (options?.maxBytes !== void 0) body.maxBytes = options.maxBytes;
|
|
658
|
+
const action = this.actionForSql(sql, SQLAction.READ);
|
|
530
659
|
const response = await this.invokeSQL(
|
|
531
660
|
dbName,
|
|
532
|
-
|
|
661
|
+
action,
|
|
533
662
|
body,
|
|
534
|
-
|
|
663
|
+
request.signal
|
|
535
664
|
);
|
|
536
665
|
if (!response.ok) {
|
|
537
|
-
return this.handleErrorResponse(response, "query");
|
|
666
|
+
return this.handleErrorResponse(response, "query", dbName, [action]);
|
|
538
667
|
}
|
|
539
668
|
const data = await response.json();
|
|
540
669
|
return ok(data);
|
|
541
670
|
} catch (error) {
|
|
542
671
|
return err(wrapError("sql", error));
|
|
672
|
+
} finally {
|
|
673
|
+
request.dispose();
|
|
543
674
|
}
|
|
544
675
|
});
|
|
545
676
|
}
|
|
@@ -548,6 +679,7 @@ var SQLService = class extends BaseService {
|
|
|
548
679
|
if (!this.requireAuth()) {
|
|
549
680
|
return err(authRequiredError("sql"));
|
|
550
681
|
}
|
|
682
|
+
const request = this.createRequestSignal(options?.signal);
|
|
551
683
|
try {
|
|
552
684
|
const body = {
|
|
553
685
|
action: "execute",
|
|
@@ -563,19 +695,22 @@ var SQLService = class extends BaseService {
|
|
|
563
695
|
(statement) => this.actionForSql(statement, SQLAction.SCHEMA)
|
|
564
696
|
)
|
|
565
697
|
];
|
|
698
|
+
const requestedActions = this.dedupeActions(actions);
|
|
566
699
|
const response = await this.invokeSQL(
|
|
567
700
|
dbName,
|
|
568
|
-
|
|
701
|
+
requestedActions,
|
|
569
702
|
body,
|
|
570
|
-
|
|
703
|
+
request.signal
|
|
571
704
|
);
|
|
572
705
|
if (!response.ok) {
|
|
573
|
-
return this.handleErrorResponse(response, "execute");
|
|
706
|
+
return this.handleErrorResponse(response, "execute", dbName, requestedActions);
|
|
574
707
|
}
|
|
575
708
|
const data = await response.json();
|
|
576
709
|
return ok(data);
|
|
577
710
|
} catch (error) {
|
|
578
711
|
return err(wrapError("sql", error));
|
|
712
|
+
} finally {
|
|
713
|
+
request.dispose();
|
|
579
714
|
}
|
|
580
715
|
});
|
|
581
716
|
}
|
|
@@ -584,20 +719,24 @@ var SQLService = class extends BaseService {
|
|
|
584
719
|
if (!this.requireAuth()) {
|
|
585
720
|
return err(authRequiredError("sql"));
|
|
586
721
|
}
|
|
722
|
+
const request = this.createRequestSignal(options?.signal);
|
|
587
723
|
try {
|
|
724
|
+
const requestedActions = this.actionsForSqlBatch(statements);
|
|
588
725
|
const response = await this.invokeSQL(
|
|
589
726
|
dbName,
|
|
590
|
-
|
|
727
|
+
requestedActions,
|
|
591
728
|
{ action: "batch", statements },
|
|
592
|
-
|
|
729
|
+
request.signal
|
|
593
730
|
);
|
|
594
731
|
if (!response.ok) {
|
|
595
|
-
return this.handleErrorResponse(response, "batch");
|
|
732
|
+
return this.handleErrorResponse(response, "batch", dbName, requestedActions);
|
|
596
733
|
}
|
|
597
734
|
const data = await response.json();
|
|
598
735
|
return ok(data);
|
|
599
736
|
} catch (error) {
|
|
600
737
|
return err(wrapError("sql", error));
|
|
738
|
+
} finally {
|
|
739
|
+
request.dispose();
|
|
601
740
|
}
|
|
602
741
|
});
|
|
603
742
|
}
|
|
@@ -606,20 +745,23 @@ var SQLService = class extends BaseService {
|
|
|
606
745
|
if (!this.requireAuth()) {
|
|
607
746
|
return err(authRequiredError("sql"));
|
|
608
747
|
}
|
|
748
|
+
const request = this.createRequestSignal(options?.signal);
|
|
609
749
|
try {
|
|
610
750
|
const response = await this.invokeSQL(
|
|
611
751
|
dbName,
|
|
612
752
|
SQLAction.WRITE,
|
|
613
753
|
{ action: "execute_statement", name, params: params ?? [] },
|
|
614
|
-
|
|
754
|
+
request.signal
|
|
615
755
|
);
|
|
616
756
|
if (!response.ok) {
|
|
617
|
-
return this.handleErrorResponse(response, "executeStatement");
|
|
757
|
+
return this.handleErrorResponse(response, "executeStatement", dbName, [SQLAction.WRITE]);
|
|
618
758
|
}
|
|
619
759
|
const data = await response.json();
|
|
620
760
|
return ok(data);
|
|
621
761
|
} catch (error) {
|
|
622
762
|
return err(wrapError("sql", error));
|
|
763
|
+
} finally {
|
|
764
|
+
request.dispose();
|
|
623
765
|
}
|
|
624
766
|
});
|
|
625
767
|
}
|
|
@@ -628,15 +770,16 @@ var SQLService = class extends BaseService {
|
|
|
628
770
|
if (!this.requireAuth()) {
|
|
629
771
|
return err(authRequiredError("sql"));
|
|
630
772
|
}
|
|
773
|
+
const request = this.createRequestSignal(options?.signal);
|
|
631
774
|
try {
|
|
632
775
|
const response = await this.invokeSQL(
|
|
633
776
|
dbName,
|
|
634
777
|
SQLAction.READ,
|
|
635
778
|
{ action: "export" },
|
|
636
|
-
|
|
779
|
+
request.signal
|
|
637
780
|
);
|
|
638
781
|
if (!response.ok) {
|
|
639
|
-
return this.handleErrorResponse(response, "export");
|
|
782
|
+
return this.handleErrorResponse(response, "export", dbName, [SQLAction.READ]);
|
|
640
783
|
}
|
|
641
784
|
const resp = response;
|
|
642
785
|
if (typeof resp.blob === "function") {
|
|
@@ -647,26 +790,31 @@ var SQLService = class extends BaseService {
|
|
|
647
790
|
return ok(text);
|
|
648
791
|
} catch (error) {
|
|
649
792
|
return err(wrapError("sql", error));
|
|
793
|
+
} finally {
|
|
794
|
+
request.dispose();
|
|
650
795
|
}
|
|
651
796
|
});
|
|
652
797
|
}
|
|
653
798
|
async applyMigrationsOnDbUnlocked(dbName, options) {
|
|
654
799
|
return this.withTelemetry("migrations.apply", dbName, async () => {
|
|
655
|
-
const created = await this.ensureMigrationsTable(dbName, options.signal);
|
|
656
|
-
if (!created.ok) return created;
|
|
657
800
|
const listed = await this.queryOnDb(
|
|
658
801
|
dbName,
|
|
659
802
|
`SELECT id FROM ${MIGRATIONS_TABLE} WHERE namespace = ? ORDER BY applied_at, id`,
|
|
660
803
|
[options.namespace],
|
|
661
804
|
{ signal: options.signal }
|
|
662
805
|
);
|
|
663
|
-
|
|
806
|
+
const tableMissing = !listed.ok && (listed.error.code === ErrorCodes.SQL_DATABASE_NOT_FOUND || isMissingTableError(listed.error.message));
|
|
807
|
+
if (!listed.ok && !tableMissing) return listed;
|
|
664
808
|
const appliedIds = new Set(
|
|
665
|
-
listed.data.rows.map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
|
|
809
|
+
(listed.ok ? listed.data.rows : []).map((row) => rowValue(row, 0)).filter((id) => typeof id === "string")
|
|
666
810
|
);
|
|
667
811
|
const skipped = options.migrations.filter((migration) => appliedIds.has(migration.id)).map((migration) => migration.id);
|
|
668
812
|
const pending = options.migrations.filter((migration) => !appliedIds.has(migration.id));
|
|
669
813
|
const applied = [];
|
|
814
|
+
if (pending.length > 0 && tableMissing) {
|
|
815
|
+
const created = await this.ensureMigrationsTable(dbName, options.signal);
|
|
816
|
+
if (!created.ok) return created;
|
|
817
|
+
}
|
|
670
818
|
for (const migration of pending) {
|
|
671
819
|
const result = await this.applyOneMigration(dbName, options.namespace, migration, options.signal);
|
|
672
820
|
if (!result.ok) return result;
|
|
@@ -734,7 +882,7 @@ var SQLService = class extends BaseService {
|
|
|
734
882
|
"Content-Type": "application/json"
|
|
735
883
|
},
|
|
736
884
|
body: JSON.stringify(body),
|
|
737
|
-
signal
|
|
885
|
+
signal
|
|
738
886
|
});
|
|
739
887
|
}
|
|
740
888
|
actionForSql(sql, fallback) {
|
|
@@ -767,8 +915,12 @@ var SQLService = class extends BaseService {
|
|
|
767
915
|
}))
|
|
768
916
|
);
|
|
769
917
|
}
|
|
770
|
-
async handleErrorResponse(response, operation) {
|
|
918
|
+
async handleErrorResponse(response, operation, dbName, requestedActions) {
|
|
771
919
|
const errorText = await response.text();
|
|
920
|
+
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
921
|
+
if (response.status === 402) {
|
|
922
|
+
return err(storageRejectionError("sql", 402, meta, errorText));
|
|
923
|
+
}
|
|
772
924
|
const errorBody = parseServiceErrorBody(errorText);
|
|
773
925
|
const errorCode = this.mapHttpStatusToErrorCode(
|
|
774
926
|
response.status,
|
|
@@ -781,11 +933,12 @@ var SQLService = class extends BaseService {
|
|
|
781
933
|
errorText,
|
|
782
934
|
errorBody
|
|
783
935
|
);
|
|
784
|
-
const meta = responseErrorMeta(response.status, response.statusText, errorText);
|
|
785
936
|
if (response.status === 401) {
|
|
786
|
-
const {
|
|
787
|
-
if (action
|
|
788
|
-
|
|
937
|
+
const { action } = parseAuthError(errorText);
|
|
938
|
+
if (action && requestedActions.includes(action)) {
|
|
939
|
+
meta.requiredAction = action;
|
|
940
|
+
meta.resource = `${this.context.session.spaceId}/sql/${dbName}`;
|
|
941
|
+
}
|
|
789
942
|
}
|
|
790
943
|
return err(
|
|
791
944
|
serviceError(errorCode, message, "sql", { meta })
|
|
@@ -882,6 +1035,9 @@ function serializeSqlValues(values) {
|
|
|
882
1035
|
(value) => value instanceof Uint8Array ? Array.from(value) : value
|
|
883
1036
|
);
|
|
884
1037
|
}
|
|
1038
|
+
function isMissingTableError(message) {
|
|
1039
|
+
return /no such table/i.test(message);
|
|
1040
|
+
}
|
|
885
1041
|
function migrationKey(namespace, id) {
|
|
886
1042
|
return `${encodeURIComponent(namespace)}:${encodeURIComponent(id)}`;
|
|
887
1043
|
}
|