naro-cli 0.20.0 → 0.21.0
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/README.md +61 -0
- package/dist/{chunk-SAA66XLD.js → chunk-FFPOVA7I.js} +996 -483
- package/dist/deploy.js +1 -1
- package/dist/index.js +2567 -161
- package/package.json +4 -4
|
@@ -19824,6 +19824,7 @@ var NaroClient = class {
|
|
|
19824
19824
|
db;
|
|
19825
19825
|
backend;
|
|
19826
19826
|
storage;
|
|
19827
|
+
realtime;
|
|
19827
19828
|
insights;
|
|
19828
19829
|
analytics;
|
|
19829
19830
|
protection;
|
|
@@ -19843,6 +19844,7 @@ var NaroClient = class {
|
|
|
19843
19844
|
this.db = new DbApi(this);
|
|
19844
19845
|
this.backend = new BackendApi(this);
|
|
19845
19846
|
this.storage = new StorageApi(this);
|
|
19847
|
+
this.realtime = new RealtimeApi(this);
|
|
19846
19848
|
this.insights = new InsightsApi(this);
|
|
19847
19849
|
this.analytics = new AnalyticsApi(this);
|
|
19848
19850
|
this.protection = new ProtectionApi(this);
|
|
@@ -20868,9 +20870,9 @@ function storageInfo(body) {
|
|
|
20868
20870
|
buckets: (body.buckets ?? []).map(storageBucket)
|
|
20869
20871
|
};
|
|
20870
20872
|
}
|
|
20871
|
-
function
|
|
20873
|
+
function provisionFailure(error51, feature) {
|
|
20872
20874
|
const details = isNaroError(error51) ? error51.details : void 0;
|
|
20873
|
-
if (isNaroError(error51) && error51.code === "BACKEND_PROVISION_FAILED" && isRecord(details?.
|
|
20875
|
+
if (isNaroError(error51) && error51.code === "BACKEND_PROVISION_FAILED" && isRecord(details?.[feature]) && isRecord(details.backend))
|
|
20874
20876
|
return new NaroError(error51.code, error51.message, {
|
|
20875
20877
|
...error51.status !== void 0 ? { status: error51.status } : {},
|
|
20876
20878
|
details: {
|
|
@@ -21308,7 +21310,7 @@ var StorageApi = class {
|
|
|
21308
21310
|
}
|
|
21309
21311
|
);
|
|
21310
21312
|
} catch (error51) {
|
|
21311
|
-
throw
|
|
21313
|
+
throw provisionFailure(error51, "storage");
|
|
21312
21314
|
}
|
|
21313
21315
|
return storageInfo(body.storage);
|
|
21314
21316
|
}
|
|
@@ -21346,7 +21348,7 @@ var StorageApi = class {
|
|
|
21346
21348
|
}
|
|
21347
21349
|
);
|
|
21348
21350
|
} catch (error51) {
|
|
21349
|
-
throw
|
|
21351
|
+
throw provisionFailure(error51, "storage");
|
|
21350
21352
|
}
|
|
21351
21353
|
return storageInfo(body.storage);
|
|
21352
21354
|
}
|
|
@@ -21505,6 +21507,114 @@ var StorageApi = class {
|
|
|
21505
21507
|
return body.objects;
|
|
21506
21508
|
}
|
|
21507
21509
|
};
|
|
21510
|
+
var RealtimeApi = class {
|
|
21511
|
+
constructor(client) {
|
|
21512
|
+
this.client = client;
|
|
21513
|
+
}
|
|
21514
|
+
path(projectId, suffix = "") {
|
|
21515
|
+
return `/api/projects/${encodeURIComponent(projectId)}/backend/realtime${suffix}`;
|
|
21516
|
+
}
|
|
21517
|
+
/**
|
|
21518
|
+
* Like `StorageApi.bucketPath`: URL parsing folds `.` and `..`, an empty
|
|
21519
|
+
* name is the collection, and `encodeURIComponent` throws on a lone
|
|
21520
|
+
* surrogate — so a name no URL can carry is refused here, before a
|
|
21521
|
+
* request. SQLite does make tables named `.` and `..`, and one with the
|
|
21522
|
+
* empty name (`CREATE TABLE "" (a)`); such a table cannot be published
|
|
21523
|
+
* or unpublished through this API.
|
|
21524
|
+
*/
|
|
21525
|
+
tablePath(projectId, table) {
|
|
21526
|
+
if (table === "" || table === "." || table === ".." || LONE_SURROGATE.test(table))
|
|
21527
|
+
throw new NaroError("INVALID_PATH", "The table name is not valid.");
|
|
21528
|
+
return this.path(projectId, `/tables/${encodeURIComponent(table)}`);
|
|
21529
|
+
}
|
|
21530
|
+
/**
|
|
21531
|
+
* Whether Realtime is on, the limits the hub enforces, the published
|
|
21532
|
+
* tables and the hub's own numbers. A project that never turned it on
|
|
21533
|
+
* answers `enabled: false` with no tables.
|
|
21534
|
+
*/
|
|
21535
|
+
async info(projectId) {
|
|
21536
|
+
const body = await this.client.request(
|
|
21537
|
+
this.path(projectId),
|
|
21538
|
+
{ context: "Read realtime" }
|
|
21539
|
+
);
|
|
21540
|
+
return body.realtime;
|
|
21541
|
+
}
|
|
21542
|
+
/**
|
|
21543
|
+
* Turns Realtime on: the request and the plan's limits are recorded, and
|
|
21544
|
+
* the Naro worker is uploaded again with its hub (a Durable Object). Safe
|
|
21545
|
+
* to repeat, and a repair — also after a plan change. The project must have
|
|
21546
|
+
* a backend, turned on, with its database. A backend in `error` or with a
|
|
21547
|
+
* run that stalled is not refused: its provisioning is resumed on the way.
|
|
21548
|
+
* Two minutes, like `backend.enable`.
|
|
21549
|
+
*
|
|
21550
|
+
* Refusals, in the order they are checked: `BACKEND_DISABLED` (the control
|
|
21551
|
+
* plane's backend switch), `FORBIDDEN` (`database.write`),
|
|
21552
|
+
* `REALTIME_DISABLED` (the control plane's Realtime switch),
|
|
21553
|
+
* `DATABASE_NOT_ENABLED` (the project's database is external),
|
|
21554
|
+
* `BACKEND_NOT_READY` (409, only when the project has no backend at all),
|
|
21555
|
+
* `BACKEND_OFF`, `BACKEND_BUSY`, `REALTIME_ENABLE_FAILED` (502: the request
|
|
21556
|
+
* could not be recorded; nothing changed), and `BACKEND_PROVISION_FAILED`
|
|
21557
|
+
* (502) when Realtime is recorded as on but the worker's upload stopped.
|
|
21558
|
+
* The last one's `details` hold a `RealtimeProvisionFailure` — `{ realtime:
|
|
21559
|
+
* { applied: false, enabled: true }, backend }`, the backend read like
|
|
21560
|
+
* `backend.info` — and `enable` again finishes.
|
|
21561
|
+
*/
|
|
21562
|
+
async enable(projectId) {
|
|
21563
|
+
let body;
|
|
21564
|
+
try {
|
|
21565
|
+
body = await this.client.request(
|
|
21566
|
+
this.path(projectId),
|
|
21567
|
+
{
|
|
21568
|
+
method: "POST",
|
|
21569
|
+
context: "Turn on Realtime",
|
|
21570
|
+
timeoutMs: PROVISION_TIMEOUT_MS
|
|
21571
|
+
}
|
|
21572
|
+
);
|
|
21573
|
+
} catch (error51) {
|
|
21574
|
+
throw provisionFailure(error51, "realtime");
|
|
21575
|
+
}
|
|
21576
|
+
return body.realtime;
|
|
21577
|
+
}
|
|
21578
|
+
/**
|
|
21579
|
+
* The tables whose Data API writes are published, in the order they were
|
|
21580
|
+
* published. `exists: false` is a published name whose table was dropped.
|
|
21581
|
+
* `REALTIME_NOT_ENABLED` (409) before `enable`; it answers while the
|
|
21582
|
+
* backend is off, since the list is in the project's database.
|
|
21583
|
+
*/
|
|
21584
|
+
async listTables(projectId) {
|
|
21585
|
+
const body = await this.client.request(
|
|
21586
|
+
this.path(projectId, "/tables"),
|
|
21587
|
+
{ context: "List realtime tables" }
|
|
21588
|
+
);
|
|
21589
|
+
return body.tables;
|
|
21590
|
+
}
|
|
21591
|
+
/**
|
|
21592
|
+
* Publishes a table's changes to the subscribers of its channel. Safe to
|
|
21593
|
+
* repeat. Only changes made through the Data API are published — writes
|
|
21594
|
+
* the app makes with `env.DB` are not (`warnings` says so).
|
|
21595
|
+
* `TABLE_NOT_FOUND` (404) for a table that does not exist;
|
|
21596
|
+
* `VALIDATION_FAILED` (400) for a Naro system table, a virtual table, a
|
|
21597
|
+
* name over 256 characters, or the 100-table cap; `REALTIME_NOT_ENABLED`
|
|
21598
|
+
* (409) before `enable`.
|
|
21599
|
+
*/
|
|
21600
|
+
async publishTable(projectId, table) {
|
|
21601
|
+
return this.client.request(
|
|
21602
|
+
this.tablePath(projectId, table),
|
|
21603
|
+
{ method: "PUT", context: "Publish a realtime table" }
|
|
21604
|
+
);
|
|
21605
|
+
}
|
|
21606
|
+
/**
|
|
21607
|
+
* Stops publishing a table's changes; a table dropped since can still be
|
|
21608
|
+
* unpublished. `TABLE_NOT_PUBLISHED` (404) for a table that does not
|
|
21609
|
+
* publish, `REALTIME_NOT_ENABLED` (409) before `enable`.
|
|
21610
|
+
*/
|
|
21611
|
+
async unpublishTable(projectId, table) {
|
|
21612
|
+
return this.client.request(
|
|
21613
|
+
this.tablePath(projectId, table),
|
|
21614
|
+
{ method: "DELETE", context: "Stop publishing a realtime table" }
|
|
21615
|
+
);
|
|
21616
|
+
}
|
|
21617
|
+
};
|
|
21508
21618
|
|
|
21509
21619
|
// ../../packages/sdk/src/database.ts
|
|
21510
21620
|
var BOOKMARK_RE = /^[0-9a-f]{8}-[0-9a-f]{8}-[0-9a-f]{8}-[0-9a-f]{32}$/;
|
|
@@ -21902,6 +22012,185 @@ function detectFramework2(dir) {
|
|
|
21902
22012
|
};
|
|
21903
22013
|
}
|
|
21904
22014
|
|
|
22015
|
+
// ../../packages/data-core/src/system-tables.ts
|
|
22016
|
+
var SYSTEM_TABLE_PREFIXES = [
|
|
22017
|
+
"_naro_",
|
|
22018
|
+
"_cf_",
|
|
22019
|
+
"sqlite_"
|
|
22020
|
+
];
|
|
22021
|
+
var SYSTEM_TABLE_NAMES = ["d1_migrations"];
|
|
22022
|
+
function asciiLower(text2) {
|
|
22023
|
+
return text2.replace(/[A-Z]+/g, (run) => run.toLowerCase());
|
|
22024
|
+
}
|
|
22025
|
+
function isSystemTable(name) {
|
|
22026
|
+
const lower = asciiLower(name);
|
|
22027
|
+
return SYSTEM_TABLE_PREFIXES.some((prefix) => lower.startsWith(prefix)) || SYSTEM_TABLE_NAMES.includes(lower);
|
|
22028
|
+
}
|
|
22029
|
+
function likeLiteral(text2) {
|
|
22030
|
+
return text2.replace(/[\\%_]/g, (char) => `\\${char}`).replace(/'/g, "''");
|
|
22031
|
+
}
|
|
22032
|
+
var COLUMN_REFERENCE = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)?$/;
|
|
22033
|
+
function systemTablePredicate(column2 = "name") {
|
|
22034
|
+
if (!COLUMN_REFERENCE.test(column2))
|
|
22035
|
+
throw new Error(`Not a column reference: ${column2}`);
|
|
22036
|
+
return [
|
|
22037
|
+
...SYSTEM_TABLE_PREFIXES.map(
|
|
22038
|
+
(prefix) => `${column2} NOT LIKE '${likeLiteral(prefix)}%' ESCAPE '\\'`
|
|
22039
|
+
),
|
|
22040
|
+
...SYSTEM_TABLE_NAMES.map(
|
|
22041
|
+
(name) => `${column2} NOT LIKE '${likeLiteral(name)}' ESCAPE '\\'`
|
|
22042
|
+
),
|
|
22043
|
+
`${column2} NOT IN (SELECT name FROM pragma_table_list WHERE schema = 'main' AND type = 'shadow')`
|
|
22044
|
+
].join(" AND ");
|
|
22045
|
+
}
|
|
22046
|
+
var SYSTEM_TABLE_SQL_PREDICATE = systemTablePredicate("name");
|
|
22047
|
+
|
|
22048
|
+
// ../../packages/data-core/src/collation.ts
|
|
22049
|
+
var COLLATIONS = ["BINARY", "NOCASE", "RTRIM"];
|
|
22050
|
+
function isSpace(char) {
|
|
22051
|
+
return char === " " || char === " " || char === "\n" || char === "\f" || char === "\r";
|
|
22052
|
+
}
|
|
22053
|
+
function isWordChar(char) {
|
|
22054
|
+
return /[A-Za-z0-9_$]/.test(char) || char.charCodeAt(0) >= 128;
|
|
22055
|
+
}
|
|
22056
|
+
function asciiUpper2(text2) {
|
|
22057
|
+
return text2.replace(/[a-z]/g, (letter) => letter.toUpperCase());
|
|
22058
|
+
}
|
|
22059
|
+
function quoted(sql, start, close, doubles) {
|
|
22060
|
+
let value = "";
|
|
22061
|
+
for (let index = start + 1; index < sql.length; index++) {
|
|
22062
|
+
const char = sql.charAt(index);
|
|
22063
|
+
if (char !== close) {
|
|
22064
|
+
value += char;
|
|
22065
|
+
continue;
|
|
22066
|
+
}
|
|
22067
|
+
if (doubles && sql.charAt(index + 1) === close) {
|
|
22068
|
+
value += close;
|
|
22069
|
+
index++;
|
|
22070
|
+
continue;
|
|
22071
|
+
}
|
|
22072
|
+
return { value, end: index + 1 };
|
|
22073
|
+
}
|
|
22074
|
+
return void 0;
|
|
22075
|
+
}
|
|
22076
|
+
function tokenize(sql) {
|
|
22077
|
+
const tokens = [];
|
|
22078
|
+
let index = 0;
|
|
22079
|
+
while (index < sql.length) {
|
|
22080
|
+
const char = sql.charAt(index);
|
|
22081
|
+
if (isSpace(char)) {
|
|
22082
|
+
index++;
|
|
22083
|
+
} else if (char === "-" && sql.charAt(index + 1) === "-") {
|
|
22084
|
+
const end = sql.indexOf("\n", index);
|
|
22085
|
+
index = end < 0 ? sql.length : end + 1;
|
|
22086
|
+
} else if (char === "/" && sql.charAt(index + 1) === "*") {
|
|
22087
|
+
const end = sql.indexOf("*/", index + 2);
|
|
22088
|
+
if (end < 0) return void 0;
|
|
22089
|
+
index = end + 2;
|
|
22090
|
+
} else if (char === '"' || char === "`" || char === "[" || char === "'") {
|
|
22091
|
+
const close = char === "[" ? "]" : char;
|
|
22092
|
+
const read = quoted(sql, index, close, char !== "[");
|
|
22093
|
+
if (!read) return void 0;
|
|
22094
|
+
tokens.push({
|
|
22095
|
+
kind: char === "'" ? "string" : "name",
|
|
22096
|
+
value: read.value
|
|
22097
|
+
});
|
|
22098
|
+
index = read.end;
|
|
22099
|
+
} else if (char === "(" || char === ")" || char === ",") {
|
|
22100
|
+
tokens.push({ kind: "punct", value: char });
|
|
22101
|
+
index++;
|
|
22102
|
+
} else if (isWordChar(char)) {
|
|
22103
|
+
let end = index;
|
|
22104
|
+
while (end < sql.length && isWordChar(sql.charAt(end))) end++;
|
|
22105
|
+
tokens.push({ kind: "word", value: sql.slice(index, end) });
|
|
22106
|
+
index = end;
|
|
22107
|
+
} else {
|
|
22108
|
+
tokens.push({ kind: "other", value: char });
|
|
22109
|
+
index++;
|
|
22110
|
+
}
|
|
22111
|
+
}
|
|
22112
|
+
return tokens;
|
|
22113
|
+
}
|
|
22114
|
+
function isWord2(token, word) {
|
|
22115
|
+
return token?.kind === "word" && asciiLower(token.value) === word;
|
|
22116
|
+
}
|
|
22117
|
+
function definitions(tokens) {
|
|
22118
|
+
const open = tokens.findIndex(
|
|
22119
|
+
(token) => token.kind === "punct" && token.value === "("
|
|
22120
|
+
);
|
|
22121
|
+
if (open < 0) return void 0;
|
|
22122
|
+
const found = [[]];
|
|
22123
|
+
let depth = 0;
|
|
22124
|
+
for (const token of tokens.slice(open + 1)) {
|
|
22125
|
+
if (token.kind === "punct" && token.value === "(") depth++;
|
|
22126
|
+
if (token.kind === "punct" && token.value === ")") {
|
|
22127
|
+
if (depth === 0) return found;
|
|
22128
|
+
depth--;
|
|
22129
|
+
}
|
|
22130
|
+
if (depth === 0 && token.kind === "punct" && token.value === ",") {
|
|
22131
|
+
found.push([]);
|
|
22132
|
+
continue;
|
|
22133
|
+
}
|
|
22134
|
+
found.at(-1)?.push(token);
|
|
22135
|
+
}
|
|
22136
|
+
return void 0;
|
|
22137
|
+
}
|
|
22138
|
+
function collationOf(definition) {
|
|
22139
|
+
const named = [];
|
|
22140
|
+
let depth = 0;
|
|
22141
|
+
for (const [index, token] of definition.entries()) {
|
|
22142
|
+
if (token.kind === "punct" && token.value === "(") depth++;
|
|
22143
|
+
else if (token.kind === "punct" && token.value === ")") depth--;
|
|
22144
|
+
else if (depth === 0 && index > 0 && isWord2(token, "collate")) {
|
|
22145
|
+
const name = definition[index + 1];
|
|
22146
|
+
if (!name || name.kind === "punct" || name.kind === "other") return null;
|
|
22147
|
+
named.push(asciiUpper2(name.value));
|
|
22148
|
+
}
|
|
22149
|
+
}
|
|
22150
|
+
if (named.length === 0) return "BINARY";
|
|
22151
|
+
const [first] = named;
|
|
22152
|
+
if (named.some((name) => name !== first)) return null;
|
|
22153
|
+
return COLLATIONS.includes(first ?? "") ? first : null;
|
|
22154
|
+
}
|
|
22155
|
+
function declaresStrict(sql) {
|
|
22156
|
+
if (typeof sql !== "string") return void 0;
|
|
22157
|
+
const tokens = tokenize(sql);
|
|
22158
|
+
if (!tokens || !isWord2(tokens[0], "create")) return void 0;
|
|
22159
|
+
const kind = isWord2(tokens[1], "temp") || isWord2(tokens[1], "temporary") ? tokens[2] : tokens[1];
|
|
22160
|
+
if (!isWord2(kind, "table")) return void 0;
|
|
22161
|
+
const open = tokens.findIndex(
|
|
22162
|
+
(token) => token.kind === "punct" && token.value === "("
|
|
22163
|
+
);
|
|
22164
|
+
if (open < 0) return void 0;
|
|
22165
|
+
let depth = 0;
|
|
22166
|
+
for (const [index, token] of tokens.entries()) {
|
|
22167
|
+
if (index < open || token.kind !== "punct") continue;
|
|
22168
|
+
if (token.value === "(") depth++;
|
|
22169
|
+
else if (token.value === ")" && --depth === 0)
|
|
22170
|
+
return tokens.slice(index + 1).some((option) => isWord2(option, "strict"));
|
|
22171
|
+
}
|
|
22172
|
+
return void 0;
|
|
22173
|
+
}
|
|
22174
|
+
function declaredCollations(sql, columns) {
|
|
22175
|
+
const unknown2 = columns.map(() => null);
|
|
22176
|
+
if (typeof sql !== "string") return unknown2;
|
|
22177
|
+
const tokens = tokenize(sql);
|
|
22178
|
+
if (!tokens || !isWord2(tokens[0], "create")) return unknown2;
|
|
22179
|
+
const kind = isWord2(tokens[1], "temp") || isWord2(tokens[1], "temporary") ? tokens[2] : tokens[1];
|
|
22180
|
+
if (!isWord2(kind, "table")) return unknown2;
|
|
22181
|
+
const found = definitions(tokens);
|
|
22182
|
+
if (!found || found.length < columns.length) return unknown2;
|
|
22183
|
+
const collations = [];
|
|
22184
|
+
for (const [index, column2] of columns.entries()) {
|
|
22185
|
+
const definition = found[index] ?? [];
|
|
22186
|
+
const name = definition[0];
|
|
22187
|
+
if (!name || name.kind === "punct" || name.kind === "other" || asciiLower(name.value) !== asciiLower(column2))
|
|
22188
|
+
return unknown2;
|
|
22189
|
+
collations.push(collationOf(definition));
|
|
22190
|
+
}
|
|
22191
|
+
return collations;
|
|
22192
|
+
}
|
|
22193
|
+
|
|
21905
22194
|
// ../../packages/data-core/src/unicode-controls.ts
|
|
21906
22195
|
function hasControlCharacter(text2) {
|
|
21907
22196
|
for (let i = 0; i < text2.length; i += 1) {
|
|
@@ -22046,39 +22335,6 @@ var STORAGE_BUCKET_DELETING_COLUMN = {
|
|
|
22046
22335
|
definition: "TEXT"
|
|
22047
22336
|
};
|
|
22048
22337
|
|
|
22049
|
-
// ../../packages/data-core/src/system-tables.ts
|
|
22050
|
-
var SYSTEM_TABLE_PREFIXES = [
|
|
22051
|
-
"_naro_",
|
|
22052
|
-
"_cf_",
|
|
22053
|
-
"sqlite_"
|
|
22054
|
-
];
|
|
22055
|
-
var SYSTEM_TABLE_NAMES = ["d1_migrations"];
|
|
22056
|
-
function asciiLower(text2) {
|
|
22057
|
-
return text2.replace(/[A-Z]+/g, (run) => run.toLowerCase());
|
|
22058
|
-
}
|
|
22059
|
-
function isSystemTable(name) {
|
|
22060
|
-
const lower = asciiLower(name);
|
|
22061
|
-
return SYSTEM_TABLE_PREFIXES.some((prefix) => lower.startsWith(prefix)) || SYSTEM_TABLE_NAMES.includes(lower);
|
|
22062
|
-
}
|
|
22063
|
-
function likeLiteral(text2) {
|
|
22064
|
-
return text2.replace(/[\\%_]/g, (char) => `\\${char}`).replace(/'/g, "''");
|
|
22065
|
-
}
|
|
22066
|
-
var COLUMN_REFERENCE = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)?$/;
|
|
22067
|
-
function systemTablePredicate(column2 = "name") {
|
|
22068
|
-
if (!COLUMN_REFERENCE.test(column2))
|
|
22069
|
-
throw new Error(`Not a column reference: ${column2}`);
|
|
22070
|
-
return [
|
|
22071
|
-
...SYSTEM_TABLE_PREFIXES.map(
|
|
22072
|
-
(prefix) => `${column2} NOT LIKE '${likeLiteral(prefix)}%' ESCAPE '\\'`
|
|
22073
|
-
),
|
|
22074
|
-
...SYSTEM_TABLE_NAMES.map(
|
|
22075
|
-
(name) => `${column2} NOT LIKE '${likeLiteral(name)}' ESCAPE '\\'`
|
|
22076
|
-
),
|
|
22077
|
-
`${column2} NOT IN (SELECT name FROM pragma_table_list WHERE schema = 'main' AND type = 'shadow')`
|
|
22078
|
-
].join(" AND ");
|
|
22079
|
-
}
|
|
22080
|
-
var SYSTEM_TABLE_SQL_PREDICATE = systemTablePredicate("name");
|
|
22081
|
-
|
|
22082
22338
|
// ../../packages/data-core/src/errors.ts
|
|
22083
22339
|
var DATABASE_FULL_MESSAGE = "The database has reached D1's 10 GB limit, which cannot be raised. Delete data to free space; writes fail until it is under the limit.";
|
|
22084
22340
|
var STORAGE_MIGRATION_PENDING_MESSAGE = "The project backend is partway through an update. Run `naro backend enable` to finish it, then try again.";
|
|
@@ -22356,7 +22612,7 @@ var OPERATORS = [
|
|
|
22356
22612
|
"*",
|
|
22357
22613
|
"-"
|
|
22358
22614
|
];
|
|
22359
|
-
function
|
|
22615
|
+
function isSpace2(char) {
|
|
22360
22616
|
return char === " " || char === " " || char === "\n" || char === "\r" || char === "\f";
|
|
22361
22617
|
}
|
|
22362
22618
|
function isIdentStart(char) {
|
|
@@ -22369,7 +22625,7 @@ function isDigit(char) {
|
|
|
22369
22625
|
return char >= "0" && char <= "9";
|
|
22370
22626
|
}
|
|
22371
22627
|
var NUMBER = /^(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?/;
|
|
22372
|
-
function
|
|
22628
|
+
function tokenize2(text2) {
|
|
22373
22629
|
const tokens = [];
|
|
22374
22630
|
let index = 0;
|
|
22375
22631
|
const at = (offset = 0) => text2.charAt(index + offset);
|
|
@@ -22378,7 +22634,7 @@ function tokenize(text2) {
|
|
|
22378
22634
|
const position = index + 1;
|
|
22379
22635
|
if (char === "\0")
|
|
22380
22636
|
throw new PolicySyntaxError("NUL characters are not allowed", position);
|
|
22381
|
-
if (
|
|
22637
|
+
if (isSpace2(char)) {
|
|
22382
22638
|
index++;
|
|
22383
22639
|
continue;
|
|
22384
22640
|
}
|
|
@@ -22563,133 +22819,6 @@ var TokenStream = class {
|
|
|
22563
22819
|
}
|
|
22564
22820
|
};
|
|
22565
22821
|
|
|
22566
|
-
// ../../packages/data-core/src/collation.ts
|
|
22567
|
-
var COLLATIONS = ["BINARY", "NOCASE", "RTRIM"];
|
|
22568
|
-
function isSpace2(char) {
|
|
22569
|
-
return char === " " || char === " " || char === "\n" || char === "\f" || char === "\r";
|
|
22570
|
-
}
|
|
22571
|
-
function isWordChar(char) {
|
|
22572
|
-
return /[A-Za-z0-9_$]/.test(char) || char.charCodeAt(0) >= 128;
|
|
22573
|
-
}
|
|
22574
|
-
function asciiUpper2(text2) {
|
|
22575
|
-
return text2.replace(/[a-z]/g, (letter) => letter.toUpperCase());
|
|
22576
|
-
}
|
|
22577
|
-
function quoted(sql, start, close, doubles) {
|
|
22578
|
-
let value = "";
|
|
22579
|
-
for (let index = start + 1; index < sql.length; index++) {
|
|
22580
|
-
const char = sql.charAt(index);
|
|
22581
|
-
if (char !== close) {
|
|
22582
|
-
value += char;
|
|
22583
|
-
continue;
|
|
22584
|
-
}
|
|
22585
|
-
if (doubles && sql.charAt(index + 1) === close) {
|
|
22586
|
-
value += close;
|
|
22587
|
-
index++;
|
|
22588
|
-
continue;
|
|
22589
|
-
}
|
|
22590
|
-
return { value, end: index + 1 };
|
|
22591
|
-
}
|
|
22592
|
-
return void 0;
|
|
22593
|
-
}
|
|
22594
|
-
function tokenize2(sql) {
|
|
22595
|
-
const tokens = [];
|
|
22596
|
-
let index = 0;
|
|
22597
|
-
while (index < sql.length) {
|
|
22598
|
-
const char = sql.charAt(index);
|
|
22599
|
-
if (isSpace2(char)) {
|
|
22600
|
-
index++;
|
|
22601
|
-
} else if (char === "-" && sql.charAt(index + 1) === "-") {
|
|
22602
|
-
const end = sql.indexOf("\n", index);
|
|
22603
|
-
index = end < 0 ? sql.length : end + 1;
|
|
22604
|
-
} else if (char === "/" && sql.charAt(index + 1) === "*") {
|
|
22605
|
-
const end = sql.indexOf("*/", index + 2);
|
|
22606
|
-
if (end < 0) return void 0;
|
|
22607
|
-
index = end + 2;
|
|
22608
|
-
} else if (char === '"' || char === "`" || char === "[" || char === "'") {
|
|
22609
|
-
const close = char === "[" ? "]" : char;
|
|
22610
|
-
const read = quoted(sql, index, close, char !== "[");
|
|
22611
|
-
if (!read) return void 0;
|
|
22612
|
-
tokens.push({
|
|
22613
|
-
kind: char === "'" ? "string" : "name",
|
|
22614
|
-
value: read.value
|
|
22615
|
-
});
|
|
22616
|
-
index = read.end;
|
|
22617
|
-
} else if (char === "(" || char === ")" || char === ",") {
|
|
22618
|
-
tokens.push({ kind: "punct", value: char });
|
|
22619
|
-
index++;
|
|
22620
|
-
} else if (isWordChar(char)) {
|
|
22621
|
-
let end = index;
|
|
22622
|
-
while (end < sql.length && isWordChar(sql.charAt(end))) end++;
|
|
22623
|
-
tokens.push({ kind: "word", value: sql.slice(index, end) });
|
|
22624
|
-
index = end;
|
|
22625
|
-
} else {
|
|
22626
|
-
tokens.push({ kind: "other", value: char });
|
|
22627
|
-
index++;
|
|
22628
|
-
}
|
|
22629
|
-
}
|
|
22630
|
-
return tokens;
|
|
22631
|
-
}
|
|
22632
|
-
function isWord2(token, word) {
|
|
22633
|
-
return token?.kind === "word" && asciiLower(token.value) === word;
|
|
22634
|
-
}
|
|
22635
|
-
function definitions(tokens) {
|
|
22636
|
-
const open = tokens.findIndex(
|
|
22637
|
-
(token) => token.kind === "punct" && token.value === "("
|
|
22638
|
-
);
|
|
22639
|
-
if (open < 0) return void 0;
|
|
22640
|
-
const found = [[]];
|
|
22641
|
-
let depth = 0;
|
|
22642
|
-
for (const token of tokens.slice(open + 1)) {
|
|
22643
|
-
if (token.kind === "punct" && token.value === "(") depth++;
|
|
22644
|
-
if (token.kind === "punct" && token.value === ")") {
|
|
22645
|
-
if (depth === 0) return found;
|
|
22646
|
-
depth--;
|
|
22647
|
-
}
|
|
22648
|
-
if (depth === 0 && token.kind === "punct" && token.value === ",") {
|
|
22649
|
-
found.push([]);
|
|
22650
|
-
continue;
|
|
22651
|
-
}
|
|
22652
|
-
found.at(-1)?.push(token);
|
|
22653
|
-
}
|
|
22654
|
-
return void 0;
|
|
22655
|
-
}
|
|
22656
|
-
function collationOf(definition) {
|
|
22657
|
-
const named = [];
|
|
22658
|
-
let depth = 0;
|
|
22659
|
-
for (const [index, token] of definition.entries()) {
|
|
22660
|
-
if (token.kind === "punct" && token.value === "(") depth++;
|
|
22661
|
-
else if (token.kind === "punct" && token.value === ")") depth--;
|
|
22662
|
-
else if (depth === 0 && index > 0 && isWord2(token, "collate")) {
|
|
22663
|
-
const name = definition[index + 1];
|
|
22664
|
-
if (!name || name.kind === "punct" || name.kind === "other") return null;
|
|
22665
|
-
named.push(asciiUpper2(name.value));
|
|
22666
|
-
}
|
|
22667
|
-
}
|
|
22668
|
-
if (named.length === 0) return "BINARY";
|
|
22669
|
-
const [first] = named;
|
|
22670
|
-
if (named.some((name) => name !== first)) return null;
|
|
22671
|
-
return COLLATIONS.includes(first ?? "") ? first : null;
|
|
22672
|
-
}
|
|
22673
|
-
function declaredCollations(sql, columns) {
|
|
22674
|
-
const unknown2 = columns.map(() => null);
|
|
22675
|
-
if (typeof sql !== "string") return unknown2;
|
|
22676
|
-
const tokens = tokenize2(sql);
|
|
22677
|
-
if (!tokens || !isWord2(tokens[0], "create")) return unknown2;
|
|
22678
|
-
const kind = isWord2(tokens[1], "temp") || isWord2(tokens[1], "temporary") ? tokens[2] : tokens[1];
|
|
22679
|
-
if (!isWord2(kind, "table")) return unknown2;
|
|
22680
|
-
const found = definitions(tokens);
|
|
22681
|
-
if (!found || found.length < columns.length) return unknown2;
|
|
22682
|
-
const collations = [];
|
|
22683
|
-
for (const [index, column2] of columns.entries()) {
|
|
22684
|
-
const definition = found[index] ?? [];
|
|
22685
|
-
const name = definition[0];
|
|
22686
|
-
if (!name || name.kind === "punct" || name.kind === "other" || asciiLower(name.value) !== asciiLower(column2))
|
|
22687
|
-
return unknown2;
|
|
22688
|
-
collations.push(collationOf(definition));
|
|
22689
|
-
}
|
|
22690
|
-
return collations;
|
|
22691
|
-
}
|
|
22692
|
-
|
|
22693
22822
|
// ../../packages/data-core/src/realtime-table.ts
|
|
22694
22823
|
var REALTIME_MESSAGES = "realtime.messages";
|
|
22695
22824
|
var REALTIME_MESSAGES_NAMES = ["messages", REALTIME_MESSAGES];
|
|
@@ -22767,6 +22896,9 @@ function columnAffinity(column2) {
|
|
|
22767
22896
|
return "REAL";
|
|
22768
22897
|
return "NUMERIC";
|
|
22769
22898
|
}
|
|
22899
|
+
function isAnyType(type) {
|
|
22900
|
+
return asciiLower(type.trim()) === "any";
|
|
22901
|
+
}
|
|
22770
22902
|
function numberClass(type) {
|
|
22771
22903
|
const affinity2 = columnAffinity({ type });
|
|
22772
22904
|
if (affinity2 === "TEXT" || affinity2 === "BLOB") return void 0;
|
|
@@ -22968,6 +23100,9 @@ function utf8ByteLength(text2) {
|
|
|
22968
23100
|
function quoteIdentifier(name) {
|
|
22969
23101
|
return `"${name.replaceAll('"', '""')}"`;
|
|
22970
23102
|
}
|
|
23103
|
+
function qualifiedColumn(table, column2) {
|
|
23104
|
+
return `${quoteIdentifier(table)}.${quoteIdentifier(column2)}`;
|
|
23105
|
+
}
|
|
22971
23106
|
var SIDE_BY_SIDE = 8;
|
|
22972
23107
|
function joinConditions(terms, op) {
|
|
22973
23108
|
if (terms.length <= SIDE_BY_SIDE) return `(${terms.join(` ${op} `)})`;
|
|
@@ -23059,6 +23194,11 @@ function refusesText(item, text2) {
|
|
|
23059
23194
|
function readsAsIs(item, value) {
|
|
23060
23195
|
return typeof value === "string" && numberClass(item.type) === "fallback" && !storesAsNumber(value);
|
|
23061
23196
|
}
|
|
23197
|
+
function heldAsInteger(item, value) {
|
|
23198
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value)) return false;
|
|
23199
|
+
const affinity2 = columnAffinity(item);
|
|
23200
|
+
return affinity2 === "INTEGER" || affinity2 === "NUMERIC";
|
|
23201
|
+
}
|
|
23062
23202
|
function asStored(item, sql) {
|
|
23063
23203
|
switch (columnAffinity(item)) {
|
|
23064
23204
|
case "INTEGER":
|
|
@@ -23125,6 +23265,9 @@ function checkMarker(action, nonce, restrictive) {
|
|
|
23125
23265
|
function schemaMarker(nonce) {
|
|
23126
23266
|
return `json_extract('{}', 'naro:schema:${nonce}')`;
|
|
23127
23267
|
}
|
|
23268
|
+
function captureMarker(nonce) {
|
|
23269
|
+
return `json_extract('{}', 'naro:capture:${nonce}')`;
|
|
23270
|
+
}
|
|
23128
23271
|
|
|
23129
23272
|
// ../../packages/data-core/src/policy-expr.ts
|
|
23130
23273
|
var MAX_EXPRESSION_BYTES = 3 * 16384;
|
|
@@ -24052,7 +24195,7 @@ function checkExpressionSize(expr, position) {
|
|
|
24052
24195
|
}
|
|
24053
24196
|
function parseExpression(text2) {
|
|
24054
24197
|
try {
|
|
24055
|
-
const stream = new TokenStream(
|
|
24198
|
+
const stream = new TokenStream(tokenize2(text2));
|
|
24056
24199
|
if (stream.peek().kind === "eof")
|
|
24057
24200
|
throw new PolicySyntaxError("the expression is empty", 1);
|
|
24058
24201
|
const expr = readCondition(stream);
|
|
@@ -25064,8 +25207,36 @@ function policyInvalid(policy, action) {
|
|
|
25064
25207
|
policy: policy.name
|
|
25065
25208
|
});
|
|
25066
25209
|
}
|
|
25210
|
+
var ROWID_NAMES = /* @__PURE__ */ new Set(["rowid", "oid", "_rowid_"]);
|
|
25211
|
+
function isRowidName(name) {
|
|
25212
|
+
return ROWID_NAMES.has(asciiLower(name));
|
|
25213
|
+
}
|
|
25214
|
+
function noteRowidColumn(state, table, column2) {
|
|
25215
|
+
const seen = state.rowidColumns.some(
|
|
25216
|
+
(item) => asciiLower(item.table) === asciiLower(table) && asciiLower(item.column) === asciiLower(column2)
|
|
25217
|
+
);
|
|
25218
|
+
if (!seen) state.rowidColumns.push({ table, column: column2 });
|
|
25219
|
+
}
|
|
25220
|
+
function rowidColumnsGuard(columns) {
|
|
25221
|
+
if (columns.length === 0) return null;
|
|
25222
|
+
const terms = columns.map(
|
|
25223
|
+
(item) => `EXISTS (SELECT 1 FROM pragma_table_xinfo(${quoteString(item.table)}) WHERE name = ${quoteString(item.column)} COLLATE NOCASE)`
|
|
25224
|
+
);
|
|
25225
|
+
return {
|
|
25226
|
+
sql: terms.length === 1 ? terms[0] ?? "" : joinConditions(terms, "AND"),
|
|
25227
|
+
params: []
|
|
25228
|
+
};
|
|
25229
|
+
}
|
|
25230
|
+
function rowidGuarded(columns, fragment) {
|
|
25231
|
+
const guard = rowidColumnsGuard(columns);
|
|
25232
|
+
if (!guard) return fragment;
|
|
25233
|
+
return {
|
|
25234
|
+
sql: `(CASE WHEN ${guard.sql} THEN ${fragment.sql} ELSE 0 END)`,
|
|
25235
|
+
params: [...guard.params, ...fragment.params]
|
|
25236
|
+
};
|
|
25237
|
+
}
|
|
25067
25238
|
function newState2() {
|
|
25068
|
-
return { aliases: 0, subqueries: 0, depth: 0, active: [] };
|
|
25239
|
+
return { aliases: 0, subqueries: 0, depth: 0, active: [], rowidColumns: [] };
|
|
25069
25240
|
}
|
|
25070
25241
|
function bind(env, value) {
|
|
25071
25242
|
env.params.push(value);
|
|
@@ -25075,10 +25246,15 @@ function blamed(env, reason) {
|
|
|
25075
25246
|
return fail(policyInvalid(env.blame.policy, env.blame.action), reason);
|
|
25076
25247
|
}
|
|
25077
25248
|
function storedSource(table, names, alias) {
|
|
25249
|
+
const qualifier = alias ?? table.name;
|
|
25078
25250
|
return {
|
|
25079
25251
|
table,
|
|
25080
25252
|
names,
|
|
25081
|
-
read: (column2,
|
|
25253
|
+
read: (column2, env) => {
|
|
25254
|
+
if (isRowidName(column2.name))
|
|
25255
|
+
noteRowidColumn(env.state, table.name, column2.name);
|
|
25256
|
+
return qualifiedColumn(qualifier, column2.name);
|
|
25257
|
+
},
|
|
25082
25258
|
operand: (column2) => ({
|
|
25083
25259
|
stable: true,
|
|
25084
25260
|
newColumnish: true,
|
|
@@ -25147,7 +25323,7 @@ function jwtValue(env, expr) {
|
|
|
25147
25323
|
if (expr.op === "->") return bind(env, JSON.stringify(value));
|
|
25148
25324
|
return bind(env, typeof value === "boolean" ? String(value) : value);
|
|
25149
25325
|
}
|
|
25150
|
-
function valueSql(env, expr, textual = null) {
|
|
25326
|
+
function valueSql(env, expr, textual = null, exact = false, ordered = false) {
|
|
25151
25327
|
switch (expr.kind) {
|
|
25152
25328
|
case "literal":
|
|
25153
25329
|
if (expr.value === null) return "NULL";
|
|
@@ -25157,8 +25333,9 @@ function valueSql(env, expr, textual = null) {
|
|
|
25157
25333
|
case "realtime": {
|
|
25158
25334
|
const { source, column: column2 } = columnOf(env, expr);
|
|
25159
25335
|
return source.read(column2, env, {
|
|
25160
|
-
|
|
25161
|
-
textual
|
|
25336
|
+
textual,
|
|
25337
|
+
exact: textual === null && exact,
|
|
25338
|
+
...textual === null && ordered ? { ordered: true } : {}
|
|
25162
25339
|
});
|
|
25163
25340
|
}
|
|
25164
25341
|
case "auth":
|
|
@@ -25169,7 +25346,10 @@ function valueSql(env, expr, textual = null) {
|
|
|
25169
25346
|
case "func": {
|
|
25170
25347
|
if (expr.name === "now") return "CURRENT_TIMESTAMP";
|
|
25171
25348
|
if (expr.name === "coalesce") {
|
|
25172
|
-
const
|
|
25349
|
+
const one = expr.args.length === 1;
|
|
25350
|
+
const args = expr.args.map(
|
|
25351
|
+
(arg2) => valueSql(env, arg2, textual, exact, one && ordered)
|
|
25352
|
+
);
|
|
25173
25353
|
return args.length === 1 ? `(${String(args[0])})` : `coalesce(${args.join(", ")})`;
|
|
25174
25354
|
}
|
|
25175
25355
|
const [arg] = expr.args;
|
|
@@ -25193,7 +25373,7 @@ function columnOf(env, expr) {
|
|
|
25193
25373
|
return expr.kind === "column" ? resolveColumn(env, expr) : realtimeTopic(env);
|
|
25194
25374
|
}
|
|
25195
25375
|
function pathArray(operand) {
|
|
25196
|
-
return `('[
|
|
25376
|
+
return `('[' || replace(json_quote(${operand()} || ''), '/', '","') || ']')`;
|
|
25197
25377
|
}
|
|
25198
25378
|
function storageHelperSql(fn, index, operand) {
|
|
25199
25379
|
switch (fn) {
|
|
@@ -25224,10 +25404,7 @@ function storageCallSql(env, expr) {
|
|
|
25224
25404
|
return storageHelperSql(
|
|
25225
25405
|
expr.fn,
|
|
25226
25406
|
index,
|
|
25227
|
-
() => source.read(column2, env, {
|
|
25228
|
-
qualified: env.scopes.length > 1,
|
|
25229
|
-
textual: "textual"
|
|
25230
|
-
})
|
|
25407
|
+
() => source.read(column2, env, { textual: "textual" })
|
|
25231
25408
|
);
|
|
25232
25409
|
}
|
|
25233
25410
|
function operandSide(env, value) {
|
|
@@ -25265,10 +25442,73 @@ var ARRAY_OPERATORS3 = {
|
|
|
25265
25442
|
"<@": "containedBy",
|
|
25266
25443
|
"&&": "overlaps"
|
|
25267
25444
|
};
|
|
25445
|
+
function readsBack(env) {
|
|
25446
|
+
return env.scopes.some((scope) => scope.readBack === true);
|
|
25447
|
+
}
|
|
25448
|
+
function textAffinity(env, value) {
|
|
25449
|
+
const expr = comparedValue(value);
|
|
25450
|
+
if (expr.kind === "cast") return true;
|
|
25451
|
+
if (expr.kind !== "column" && expr.kind !== "realtime") return false;
|
|
25452
|
+
try {
|
|
25453
|
+
return columnAffinity(columnOf(env, expr).column) === "TEXT";
|
|
25454
|
+
} catch {
|
|
25455
|
+
return true;
|
|
25456
|
+
}
|
|
25457
|
+
}
|
|
25458
|
+
function selectedTextAffinity(env, subquery) {
|
|
25459
|
+
if (subquery.select === "*") return true;
|
|
25460
|
+
const table = resolveSubqueryTable(env.snapshot, subquery.table);
|
|
25461
|
+
if (!table) return true;
|
|
25462
|
+
const source = storedSource(
|
|
25463
|
+
table,
|
|
25464
|
+
[asciiLower(subqueryName(subquery))],
|
|
25465
|
+
null
|
|
25466
|
+
);
|
|
25467
|
+
return textAffinity(
|
|
25468
|
+
{ ...env, scopes: [...env.scopes, source] },
|
|
25469
|
+
subquery.select
|
|
25470
|
+
);
|
|
25471
|
+
}
|
|
25472
|
+
var ORDERING = /* @__PURE__ */ new Set(["<", "<=", ">", ">="]);
|
|
25473
|
+
function orderSafe(env, value) {
|
|
25474
|
+
const expr = comparedValue(value);
|
|
25475
|
+
switch (expr.kind) {
|
|
25476
|
+
case "literal":
|
|
25477
|
+
return typeof expr.value !== "string" || !storesAsNumber(expr.value);
|
|
25478
|
+
case "func":
|
|
25479
|
+
return expr.name === "now";
|
|
25480
|
+
case "column": {
|
|
25481
|
+
let column2;
|
|
25482
|
+
try {
|
|
25483
|
+
column2 = columnOf(env, expr).column;
|
|
25484
|
+
} catch {
|
|
25485
|
+
return false;
|
|
25486
|
+
}
|
|
25487
|
+
const kind = numberClass(column2.type);
|
|
25488
|
+
return kind === "number" || kind === "fallback" && !isAnyType(column2.type);
|
|
25489
|
+
}
|
|
25490
|
+
default:
|
|
25491
|
+
return false;
|
|
25492
|
+
}
|
|
25493
|
+
}
|
|
25268
25494
|
function comparison(env, left, op, right) {
|
|
25269
|
-
const
|
|
25495
|
+
const back = readsBack(env);
|
|
25496
|
+
const ordered = back && ORDERING.has(op);
|
|
25497
|
+
const l = valueSql(
|
|
25498
|
+
env,
|
|
25499
|
+
left,
|
|
25500
|
+
null,
|
|
25501
|
+
back && !textAffinity(env, right),
|
|
25502
|
+
ordered && !orderSafe(env, right)
|
|
25503
|
+
);
|
|
25270
25504
|
const collate = env.check ? checkCollation(env, operandSide(env, left), operandSide(env, right)) : "";
|
|
25271
|
-
const r = valueSql(
|
|
25505
|
+
const r = valueSql(
|
|
25506
|
+
env,
|
|
25507
|
+
right,
|
|
25508
|
+
null,
|
|
25509
|
+
back && !textAffinity(env, left),
|
|
25510
|
+
ordered && !orderSafe(env, left)
|
|
25511
|
+
);
|
|
25272
25512
|
return `(${l}${collate} ${op} ${r})`;
|
|
25273
25513
|
}
|
|
25274
25514
|
function knownNullTest(env, expr) {
|
|
@@ -25313,22 +25553,36 @@ function conditionSql(env, expr) {
|
|
|
25313
25553
|
if (untestable !== void 0) return blamed(env, untestable);
|
|
25314
25554
|
const known = knownNullTest(env, expr);
|
|
25315
25555
|
if (known !== void 0) return known;
|
|
25316
|
-
const target2 = valueSql(env, expr.operand);
|
|
25556
|
+
const target2 = valueSql(env, expr.operand, null, true);
|
|
25317
25557
|
if (expr.value === null)
|
|
25318
25558
|
return `(${target2} IS ${expr.not ? "NOT " : ""}NULL)`;
|
|
25319
25559
|
const test = isBoolean(target2, expr.value);
|
|
25320
25560
|
return expr.not ? `(NOT (${test}))` : `(${test})`;
|
|
25321
25561
|
}
|
|
25322
25562
|
case "in": {
|
|
25323
|
-
const left = valueSql(env, expr.operand);
|
|
25563
|
+
const left = valueSql(env, expr.operand, null, true);
|
|
25324
25564
|
const collate = env.check ? checkCollation(env, operandSide(env, expr.operand), null) : "";
|
|
25325
|
-
const
|
|
25565
|
+
const itemsExact = readsBack(env) && !textAffinity(env, expr.operand);
|
|
25566
|
+
const list = expr.list.map(
|
|
25567
|
+
(item) => valueSql(env, item, null, itemsExact)
|
|
25568
|
+
);
|
|
25326
25569
|
return `(${left}${collate} ${expr.not ? "NOT " : ""}IN (${list.join(", ")}))`;
|
|
25327
25570
|
}
|
|
25328
25571
|
case "inSelect": {
|
|
25329
|
-
const
|
|
25572
|
+
const back = readsBack(env);
|
|
25573
|
+
const left = valueSql(
|
|
25574
|
+
env,
|
|
25575
|
+
expr.operand,
|
|
25576
|
+
null,
|
|
25577
|
+
back && !selectedTextAffinity(env, expr.subquery)
|
|
25578
|
+
);
|
|
25330
25579
|
const leftSide = env.check ? operandSide(env, expr.operand) : null;
|
|
25331
|
-
const sub = subquerySql(
|
|
25580
|
+
const sub = subquerySql(
|
|
25581
|
+
env,
|
|
25582
|
+
expr.subquery,
|
|
25583
|
+
"value",
|
|
25584
|
+
back && !textAffinity(env, expr.operand)
|
|
25585
|
+
);
|
|
25332
25586
|
const collate = leftSide && sub.item ? checkCollation(env, leftSide, sub.item) : "";
|
|
25333
25587
|
return `(${left}${collate} ${expr.not ? "NOT " : ""}IN (${sub.sql}))`;
|
|
25334
25588
|
}
|
|
@@ -25365,7 +25619,7 @@ function conditionSql(env, expr) {
|
|
|
25365
25619
|
return arraySql(
|
|
25366
25620
|
() => (() => {
|
|
25367
25621
|
const { source, column: column2 } = resolveColumn(env, expr.operand);
|
|
25368
|
-
return source.read(column2, env, {
|
|
25622
|
+
return source.read(column2, env, { textual: null });
|
|
25369
25623
|
})(),
|
|
25370
25624
|
ARRAY_OPERATORS3[expr.op],
|
|
25371
25625
|
values.length,
|
|
@@ -25377,7 +25631,7 @@ function conditionSql(env, expr) {
|
|
|
25377
25631
|
return `(EXISTS (${subquerySql(env, expr.subquery, "one").sql}))`;
|
|
25378
25632
|
}
|
|
25379
25633
|
}
|
|
25380
|
-
function subquerySql(env, subquery, select) {
|
|
25634
|
+
function subquerySql(env, subquery, select, selectExact = false) {
|
|
25381
25635
|
const table = resolveSubqueryTable(env.snapshot, subquery.table);
|
|
25382
25636
|
if (!table) return blamed(env, unresolvedSubqueryReason(subquery.table));
|
|
25383
25637
|
const { state } = env;
|
|
@@ -25402,7 +25656,7 @@ function subquerySql(env, subquery, select) {
|
|
|
25402
25656
|
if (select === "value") {
|
|
25403
25657
|
if (subquery.select === "*")
|
|
25404
25658
|
return blamed(env, "IN (SELECT \u2026) selects one value, not *");
|
|
25405
|
-
selected = valueSql(inner, subquery.select);
|
|
25659
|
+
selected = valueSql(inner, subquery.select, null, selectExact);
|
|
25406
25660
|
if (env.check) item = operandSide(inner, subquery.select);
|
|
25407
25661
|
}
|
|
25408
25662
|
const own2 = storedSource(table, ownNames(table), alias);
|
|
@@ -25755,7 +26009,9 @@ function selectCheckRefusal(path, column2, problem) {
|
|
|
25755
26009
|
generated: `is not available: the select policy reads the generated column ${column2}, which a new row cannot be checked against`,
|
|
25756
26010
|
collation: `is not available: the select policy reads ${column2}, whose collation naro cannot read, so a new row cannot be checked against it`,
|
|
25757
26011
|
pattern: `is not available: the select policy compares the number column ${column2} with like or ilike, which a new row cannot be checked against`,
|
|
25758
|
-
textual: `is not available: the select policy turns the number column ${column2} into text, which a new row cannot be checked against
|
|
26012
|
+
textual: `is not available: the select policy turns the number column ${column2} into text, which a new row cannot be checked against`,
|
|
26013
|
+
readBack: `is not available: the select policy reads ${column2}, a number in a column that declares no number type, as text, which a new row cannot be checked against`,
|
|
26014
|
+
orderedText: `is not available: the select policy orders ${column2}, text in a column of NUMERIC affinity, against what may read as a number, which a new row cannot be checked against`
|
|
25759
26015
|
}[problem];
|
|
25760
26016
|
return invalidQuery(path, reason);
|
|
25761
26017
|
}
|
|
@@ -25817,6 +26073,15 @@ function decideQuery(context, query, policies, table) {
|
|
|
25817
26073
|
var MAX_PARAMETERS = 100;
|
|
25818
26074
|
var MAX_STATEMENT_BYTES = 1e5;
|
|
25819
26075
|
var MAX_INSERT_STATEMENTS = 100;
|
|
26076
|
+
var MAX_CAPTURE_ROWS = 1e3;
|
|
26077
|
+
var MAX_CAPTURE_BYTES = 8388608;
|
|
26078
|
+
function triggersRead(table) {
|
|
26079
|
+
const name = table.name;
|
|
26080
|
+
return statement(
|
|
26081
|
+
"SELECT sql, tbl_name = ? COLLATE NOCASE AS own FROM sqlite_master WHERE type = 'trigger' AND (tbl_name = ? COLLATE NOCASE OR instr(lower(sql), lower(?)) > 0 OR instr(lower(sql), lower(?)) > 0 OR instr(lower(sql), lower(?)) > 0)",
|
|
26082
|
+
[name, name, name, name.replaceAll('"', '""'), name.replaceAll("`", "``")]
|
|
26083
|
+
);
|
|
26084
|
+
}
|
|
25820
26085
|
var OR_ABORT = "OR ABORT";
|
|
25821
26086
|
function column(table, name) {
|
|
25822
26087
|
return table.byName.get(asciiLower(name)) ?? fail(dataError("COLUMN_NOT_FOUND", { column: name, table: table.name }));
|
|
@@ -25832,7 +26097,13 @@ function columnList(table, names) {
|
|
|
25832
26097
|
}
|
|
25833
26098
|
return columns;
|
|
25834
26099
|
}
|
|
25835
|
-
function
|
|
26100
|
+
function columnSql(table, item) {
|
|
26101
|
+
return qualifiedColumn(table.name, item.name);
|
|
26102
|
+
}
|
|
26103
|
+
function outputList(table, columns) {
|
|
26104
|
+
return columns.map((item) => columnSql(table, item)).join(", ");
|
|
26105
|
+
}
|
|
26106
|
+
function columnNames(columns) {
|
|
25836
26107
|
return columns.map((item) => quoteIdentifier(item.name)).join(", ");
|
|
25837
26108
|
}
|
|
25838
26109
|
function returningClause(table, returning, action) {
|
|
@@ -25847,7 +26118,31 @@ function returningClause(table, returning, action) {
|
|
|
25847
26118
|
)
|
|
25848
26119
|
);
|
|
25849
26120
|
const columns = returning === "*" ? table.columns : columnList(table, returning);
|
|
25850
|
-
return ` RETURNING ${
|
|
26121
|
+
return ` RETURNING ${outputList(table, columns)}`;
|
|
26122
|
+
}
|
|
26123
|
+
function writeReturning(table, returning, action, capture) {
|
|
26124
|
+
const own2 = returningClause(table, returning, action);
|
|
26125
|
+
return capture ? ` RETURNING ${outputList(table, table.columns)}` : own2;
|
|
26126
|
+
}
|
|
26127
|
+
function balancedSum(terms) {
|
|
26128
|
+
if (terms.length === 0) return "0";
|
|
26129
|
+
if (terms.length === 1) return terms[0] ?? "0";
|
|
26130
|
+
const half = Math.ceil(terms.length / 2);
|
|
26131
|
+
return `(${balancedSum(terms.slice(0, half))} + ${balancedSum(terms.slice(half))})`;
|
|
26132
|
+
}
|
|
26133
|
+
function boundBytes(value) {
|
|
26134
|
+
return typeof value === "string" ? utf8ByteLength(value) : 8;
|
|
26135
|
+
}
|
|
26136
|
+
function captureGuard(table, where, params, nonce, set2) {
|
|
26137
|
+
const bytes = balancedSum(
|
|
26138
|
+
table.columns.map(
|
|
26139
|
+
(item) => set2.has(item.name) ? String(boundBytes(set2.get(item.name) ?? null)) : `coalesce(length(CAST(${qualifiedColumn(table.name, item.name)} AS BLOB)), 8)`
|
|
26140
|
+
)
|
|
26141
|
+
);
|
|
26142
|
+
return statement(
|
|
26143
|
+
`SELECT CASE WHEN n > ${String(MAX_CAPTURE_ROWS)} OR b > ${String(MAX_CAPTURE_BYTES)} THEN ${captureMarker(nonce)} ELSE 1 END AS ok FROM (SELECT count(*) AS n, coalesce(sum(r), 0) AS b FROM (SELECT ${bytes} AS r FROM ${quoteIdentifier(table.name)}${where} LIMIT ${String(MAX_CAPTURE_ROWS + 1)}))`,
|
|
26144
|
+
params
|
|
26145
|
+
);
|
|
25851
26146
|
}
|
|
25852
26147
|
function scalar(value, path) {
|
|
25853
26148
|
if (Array.isArray(value) || !isValue(value))
|
|
@@ -25868,7 +26163,7 @@ function arrayValues(value, path) {
|
|
|
25868
26163
|
}
|
|
25869
26164
|
function filterSql(table, filter, params, path) {
|
|
25870
26165
|
const resolved = column(table, filter.column);
|
|
25871
|
-
const target2 =
|
|
26166
|
+
const target2 = columnSql(table, resolved);
|
|
25872
26167
|
const valuePath = `${path}.value`;
|
|
25873
26168
|
switch (filter.operator) {
|
|
25874
26169
|
case "eq":
|
|
@@ -25920,10 +26215,9 @@ function filterSql(table, filter, params, path) {
|
|
|
25920
26215
|
case "containedBy":
|
|
25921
26216
|
case "overlaps": {
|
|
25922
26217
|
const values = arrayValues(filter.value, valuePath);
|
|
25923
|
-
const qualified = `${quoteIdentifier(table.name)}.${target2}`;
|
|
25924
26218
|
let next = 0;
|
|
25925
26219
|
return arraySql(
|
|
25926
|
-
() =>
|
|
26220
|
+
() => target2,
|
|
25927
26221
|
filter.operator,
|
|
25928
26222
|
values.length,
|
|
25929
26223
|
() => {
|
|
@@ -25946,8 +26240,12 @@ function nodeSql(table, node, params, path) {
|
|
|
25946
26240
|
);
|
|
25947
26241
|
return joinConditions(terms, key === "or" ? "OR" : "AND");
|
|
25948
26242
|
}
|
|
25949
|
-
function whereClause(table, filters, policy, params) {
|
|
26243
|
+
function whereClause(table, filters, policy, params, guard = null) {
|
|
25950
26244
|
const parts = [];
|
|
26245
|
+
if (guard) {
|
|
26246
|
+
parts.push(guard.sql);
|
|
26247
|
+
params.push(...guard.params);
|
|
26248
|
+
}
|
|
25951
26249
|
if (policy) {
|
|
25952
26250
|
parts.push(policy.sql);
|
|
25953
26251
|
params.push(...policy.params);
|
|
@@ -25963,7 +26261,7 @@ function orderClause(table, order) {
|
|
|
25963
26261
|
const terms = order.map((term) => {
|
|
25964
26262
|
const direction = term.ascending ? "ASC" : "DESC";
|
|
25965
26263
|
const nulls = term.nullsFirst === void 0 ? "" : term.nullsFirst ? " NULLS FIRST" : " NULLS LAST";
|
|
25966
|
-
return `${
|
|
26264
|
+
return `${columnSql(table, column(table, term.column))} ${direction}${nulls}`;
|
|
25967
26265
|
});
|
|
25968
26266
|
return ` ORDER BY ${terms.join(", ")}`;
|
|
25969
26267
|
}
|
|
@@ -26112,6 +26410,10 @@ function checkProblemReason(column2, problem) {
|
|
|
26112
26410
|
return `${column2} is a number column, which a WITH CHECK cannot compare with LIKE or ILIKE`;
|
|
26113
26411
|
case "textual":
|
|
26114
26412
|
return `${column2} is a number column, which a WITH CHECK cannot turn into text (lower, upper, length, ::text)`;
|
|
26413
|
+
case "readBack":
|
|
26414
|
+
return `${column2} holds a number in a column that declares no number type, which a WITH CHECK cannot read as text (lower, upper, length, ::text, LIKE, or beside text)`;
|
|
26415
|
+
case "orderedText":
|
|
26416
|
+
return `${column2} holds text in a column of NUMERIC affinity (a date, uuid or json type), which a WITH CHECK cannot order against anything but a number, a number column or text that reads as no number (<, <=, >, >=, BETWEEN)`;
|
|
26115
26417
|
}
|
|
26116
26418
|
}
|
|
26117
26419
|
function usingProblemReason(name, problem) {
|
|
@@ -26124,6 +26426,10 @@ function usingProblemReason(name, problem) {
|
|
|
26124
26426
|
return `${name} is a number column, which a USING judged on a row's values cannot compare with LIKE or ILIKE`;
|
|
26125
26427
|
case "textual":
|
|
26126
26428
|
return `${name} is a number column, which a USING judged on a row's values cannot turn into text (lower, upper, length, ::text)`;
|
|
26429
|
+
case "readBack":
|
|
26430
|
+
return `${name} holds a number in a column that declares no number type, which a USING judged on a row's values cannot read as text (lower, upper, length, ::text, LIKE, or beside text)`;
|
|
26431
|
+
case "orderedText":
|
|
26432
|
+
return `${name} holds text in a column of NUMERIC affinity (a date, uuid or json type), which a USING judged on a row's values cannot order against anything but a number, a number column or text that reads as no number (<, <=, >, >=, BETWEEN)`;
|
|
26127
26433
|
}
|
|
26128
26434
|
}
|
|
26129
26435
|
function isTrue(term) {
|
|
@@ -26532,6 +26838,19 @@ function schemaGuard(name, sql, kind, nonce) {
|
|
|
26532
26838
|
policy: void 0
|
|
26533
26839
|
};
|
|
26534
26840
|
}
|
|
26841
|
+
function rowidTerm(table, state, nonce, kind) {
|
|
26842
|
+
const own2 = newState2();
|
|
26843
|
+
for (const item of table.columns)
|
|
26844
|
+
if (isRowidName(item.name)) noteRowidColumn(own2, table.name, item.name);
|
|
26845
|
+
for (const read of state.rowidColumns)
|
|
26846
|
+
noteRowidColumn(own2, read.table, read.column);
|
|
26847
|
+
const guard = rowidColumnsGuard(own2.rowidColumns);
|
|
26848
|
+
return guard ? { ...guard, marker: schemaMarker(nonce), kind, policy: void 0 } : void 0;
|
|
26849
|
+
}
|
|
26850
|
+
function rowidWhere(table, state, nonce, kind) {
|
|
26851
|
+
const term = rowidTerm(table, state, nonce, kind);
|
|
26852
|
+
return term ? nestedChecks([term], { sql: "1", params: [] }) : null;
|
|
26853
|
+
}
|
|
26535
26854
|
function nestedChecks(terms, pass) {
|
|
26536
26855
|
let sql = pass.sql;
|
|
26537
26856
|
let params = pass.params;
|
|
@@ -26559,11 +26878,15 @@ function usingFragment(target2, req, snapshot, commands, alias) {
|
|
|
26559
26878
|
names: targetNames(target2),
|
|
26560
26879
|
alias
|
|
26561
26880
|
});
|
|
26562
|
-
return
|
|
26881
|
+
return rowidGuarded(
|
|
26882
|
+
rls.state.rowidColumns,
|
|
26883
|
+
rls.using(commands) ?? { sql: "1", params: [] }
|
|
26884
|
+
);
|
|
26563
26885
|
}
|
|
26564
|
-
function rowSource(target2, row, action, stored) {
|
|
26886
|
+
function rowSource(target2, row, action, stored, readBack = false) {
|
|
26565
26887
|
const { table } = target2;
|
|
26566
26888
|
const kept = new Set(stored?.columns ?? []);
|
|
26889
|
+
const strict = readBack ? declaresStrict(table.sql) : false;
|
|
26567
26890
|
const storedRow = stored ? storedSource(table, targetNames(target2), stored.alias) : void 0;
|
|
26568
26891
|
const source = {
|
|
26569
26892
|
table,
|
|
@@ -26588,14 +26911,21 @@ function rowSource(target2, row, action, stored) {
|
|
|
26588
26911
|
`the new row of ${target2.name} has no value for ${item.name}`
|
|
26589
26912
|
);
|
|
26590
26913
|
const bound = row[item.name] ?? null;
|
|
26591
|
-
|
|
26914
|
+
const anyStrict = readBack && isAnyType(item.type) ? strict : false;
|
|
26915
|
+
if (anyStrict !== true && typeof bound === "string" && refusesText(item, bound))
|
|
26592
26916
|
fail(invalidQuery(`row.${item.name}`, mustBeNumber(action)));
|
|
26917
|
+
if (readBack && typeof bound === "number" && (anyStrict === void 0 || (!isNumeric(item) || anyStrict) && how.exact !== true))
|
|
26918
|
+
check2.problem(item.name, "readBack", env.blame.policy);
|
|
26919
|
+
if (readBack && anyStrict !== true && how.ordered === true && readsAsIs(item, bound))
|
|
26920
|
+
check2.problem(item.name, "orderedText", env.blame.policy);
|
|
26593
26921
|
env.params.push(bound);
|
|
26594
|
-
|
|
26922
|
+
if (anyStrict === true || readsAsIs(item, bound)) return "?";
|
|
26923
|
+
return readBack && heldAsInteger(item, bound) ? "CAST(? AS INTEGER)" : asStored(item, "?");
|
|
26595
26924
|
},
|
|
26596
26925
|
// A stored column is the statement's own table's: SQLite compares it
|
|
26597
26926
|
// with its own collation, the snapshot's — which the guard holds to.
|
|
26598
|
-
operand: (item) => kept.has(item.name) ? { stable: true, newColumnish: true, newCollation: item.collation } : { stable: false, newColumnish: false, newCollation: null }
|
|
26927
|
+
operand: (item) => kept.has(item.name) ? { stable: true, newColumnish: true, newCollation: item.collation } : { stable: false, newColumnish: false, newCollation: null },
|
|
26928
|
+
...readBack ? { readBack } : {}
|
|
26599
26929
|
};
|
|
26600
26930
|
return source;
|
|
26601
26931
|
}
|
|
@@ -26635,7 +26965,17 @@ function checkFragment(target2, req, snapshot, command, row, nonce, stored, with
|
|
|
26635
26965
|
() => false,
|
|
26636
26966
|
() => false
|
|
26637
26967
|
);
|
|
26638
|
-
if (
|
|
26968
|
+
if (terms.length === 0) return terms;
|
|
26969
|
+
const rowid = rowidColumnsGuard(rls.state.rowidColumns);
|
|
26970
|
+
const guards = rowid ? [
|
|
26971
|
+
{
|
|
26972
|
+
...rowid,
|
|
26973
|
+
marker: schemaMarker(checked),
|
|
26974
|
+
kind: command,
|
|
26975
|
+
policy: void 0
|
|
26976
|
+
}
|
|
26977
|
+
] : [];
|
|
26978
|
+
if (!source.storedRead) return [...guards, ...terms];
|
|
26639
26979
|
const { name, sql } = target2.table;
|
|
26640
26980
|
if (sql === null) {
|
|
26641
26981
|
const first = terms.find((term) => term.policy !== void 0)?.policy;
|
|
@@ -26644,7 +26984,7 @@ function checkFragment(target2, req, snapshot, command, row, nonce, stored, with
|
|
|
26644
26984
|
`naro cannot read the schema of ${target2.name}, so a check of the stored row cannot be guarded`
|
|
26645
26985
|
);
|
|
26646
26986
|
}
|
|
26647
|
-
return [schemaGuard(name, sql, command, checked), ...terms];
|
|
26987
|
+
return [schemaGuard(name, sql, command, checked), ...guards, ...terms];
|
|
26648
26988
|
}
|
|
26649
26989
|
var Unsupported = class extends Error {
|
|
26650
26990
|
constructor(columnName, problem, policy) {
|
|
@@ -26654,9 +26994,15 @@ var Unsupported = class extends Error {
|
|
|
26654
26994
|
this.policy = policy;
|
|
26655
26995
|
}
|
|
26656
26996
|
};
|
|
26657
|
-
function policyValue(target2, req, snapshot, command, row, nonce, state = newState2()) {
|
|
26997
|
+
function policyValue(target2, req, snapshot, command, row, nonce, state = newState2(), options = {}) {
|
|
26658
26998
|
const checked = checkNonceOf(nonce, "policyValue");
|
|
26659
|
-
const source = rowSource(
|
|
26999
|
+
const source = rowSource(
|
|
27000
|
+
target2,
|
|
27001
|
+
row,
|
|
27002
|
+
"insert",
|
|
27003
|
+
void 0,
|
|
27004
|
+
options.readBack === true
|
|
27005
|
+
);
|
|
26660
27006
|
const rls = new Rls(
|
|
26661
27007
|
req,
|
|
26662
27008
|
snapshot,
|
|
@@ -26703,34 +27049,42 @@ function policyValue(target2, req, snapshot, command, row, nonce, state = newSta
|
|
|
26703
27049
|
].filter((term) => !isTrue(term));
|
|
26704
27050
|
const [only] = kept;
|
|
26705
27051
|
if (!only) return { ok: true, fragment: { sql: "1", params: [] } };
|
|
26706
|
-
|
|
27052
|
+
const read = state.rowidColumns;
|
|
27053
|
+
if (kept.length === 1)
|
|
27054
|
+
return { ok: true, fragment: rowidGuarded(read, only) };
|
|
26707
27055
|
return {
|
|
26708
27056
|
ok: true,
|
|
26709
|
-
fragment: {
|
|
27057
|
+
fragment: rowidGuarded(read, {
|
|
26710
27058
|
sql: `(${kept.map((term) => term.sql).join(" AND ")})`,
|
|
26711
27059
|
params: kept.flatMap((term) => term.params)
|
|
26712
|
-
}
|
|
27060
|
+
})
|
|
26713
27061
|
};
|
|
26714
27062
|
}
|
|
26715
|
-
function compileSelect(query, table, rls) {
|
|
27063
|
+
function compileSelect(query, table, rls, { state, nonce }) {
|
|
26716
27064
|
if (query.columns !== "*" && query.columns.length === 0)
|
|
26717
27065
|
fail(invalidQuery("columns", "must name at least one column"));
|
|
26718
27066
|
const columns = query.columns === "*" ? table.columns : columnList(table, query.columns);
|
|
26719
27067
|
const params = [];
|
|
26720
27068
|
const policy = rls?.where("select") ?? null;
|
|
26721
27069
|
if (rls && policy) rls.budget([policy]);
|
|
26722
|
-
const where = whereClause(
|
|
27070
|
+
const where = whereClause(
|
|
27071
|
+
table,
|
|
27072
|
+
query.filters ?? [],
|
|
27073
|
+
policy,
|
|
27074
|
+
params,
|
|
27075
|
+
rowidWhere(table, state, nonce, "select")
|
|
27076
|
+
);
|
|
26723
27077
|
const order = orderClause(table, query.order ?? []);
|
|
26724
27078
|
const limit = query.limit ?? MAX_LIMIT;
|
|
26725
27079
|
params.push(query.single ? Math.min(limit, 2) : limit, query.offset ?? 0);
|
|
26726
27080
|
return [
|
|
26727
27081
|
statement(
|
|
26728
|
-
`SELECT ${
|
|
27082
|
+
`SELECT ${outputList(table, columns)} FROM ${quoteIdentifier(table.name)}${where}${order} LIMIT ? OFFSET ?`,
|
|
26729
27083
|
params
|
|
26730
27084
|
)
|
|
26731
27085
|
];
|
|
26732
27086
|
}
|
|
26733
|
-
function compileInsert(query, table, rls, nonce) {
|
|
27087
|
+
function compileInsert(query, table, rls, { state, nonce }, capture) {
|
|
26734
27088
|
const uid = rls?.req.uid ?? null;
|
|
26735
27089
|
const ownerInsert = rls?.ownerOnly("insert");
|
|
26736
27090
|
const ownerRead = rls && query.returning !== void 0 ? rls.ownerOnly("select") : void 0;
|
|
@@ -26799,6 +27153,12 @@ function compileInsert(query, table, rls, nonce) {
|
|
|
26799
27153
|
]);
|
|
26800
27154
|
}
|
|
26801
27155
|
}
|
|
27156
|
+
const rowid = rowidTerm(table, state, nonce, "insert");
|
|
27157
|
+
if (rowid)
|
|
27158
|
+
where = nestedChecks(
|
|
27159
|
+
[rowid],
|
|
27160
|
+
where ?? { sql: width === 0 ? "0" : "1", params: [] }
|
|
27161
|
+
);
|
|
26802
27162
|
const checkParams = where?.params ?? [];
|
|
26803
27163
|
const room = MAX_PARAMETERS - checkParams.length;
|
|
26804
27164
|
if (width > 0 && room < width) fail(dataError("TOO_MANY_PARAMETERS"));
|
|
@@ -26815,7 +27175,7 @@ function compileInsert(query, table, rls, nonce) {
|
|
|
26815
27175
|
)
|
|
26816
27176
|
);
|
|
26817
27177
|
const into = `INSERT ${OR_ABORT} INTO ${quoteIdentifier(table.name)}`;
|
|
26818
|
-
const returning =
|
|
27178
|
+
const returning = writeReturning(table, query.returning, "insert", capture);
|
|
26819
27179
|
if (rls) {
|
|
26820
27180
|
for (const { group } of plans)
|
|
26821
27181
|
for (const [row, values] of group.rows.entries())
|
|
@@ -26841,7 +27201,7 @@ function compileInsert(query, table, rls, nonce) {
|
|
|
26841
27201
|
continue;
|
|
26842
27202
|
}
|
|
26843
27203
|
const tuple2 = `(${group.columns.map(() => "?").join(", ")})`;
|
|
26844
|
-
const names =
|
|
27204
|
+
const names = columnNames(group.columns);
|
|
26845
27205
|
for (let start = 0; start < group.rows.length; start += perStatement) {
|
|
26846
27206
|
const chunk = group.rows.slice(start, start + perStatement);
|
|
26847
27207
|
const values = chunk.map(() => tuple2).join(", ");
|
|
@@ -26858,7 +27218,7 @@ function compileInsert(query, table, rls, nonce) {
|
|
|
26858
27218
|
}
|
|
26859
27219
|
return statements;
|
|
26860
27220
|
}
|
|
26861
|
-
function compileUpdate(query, table, context, rls, nonce) {
|
|
27221
|
+
function compileUpdate(query, table, context, rls, { state, nonce }, capture) {
|
|
26862
27222
|
requireFilter(query, context);
|
|
26863
27223
|
const values = assignments(table, query.values, "values");
|
|
26864
27224
|
if (values.size === 0)
|
|
@@ -26896,8 +27256,9 @@ function compileUpdate(query, table, context, rls, nonce) {
|
|
|
26896
27256
|
{ sql: checkSql, params: terms.flatMap((term) => term.params) },
|
|
26897
27257
|
...policy ? [policy] : []
|
|
26898
27258
|
]);
|
|
26899
|
-
const
|
|
26900
|
-
const
|
|
27259
|
+
const rowid = rowidWhere(table, state, nonce, "update");
|
|
27260
|
+
const where = whereClause(table, query.filters ?? [], policy, params, rowid);
|
|
27261
|
+
const returning = writeReturning(table, query.returning, "update", capture);
|
|
26901
27262
|
for (const item of values.values())
|
|
26902
27263
|
rls?.refuseText(
|
|
26903
27264
|
"update",
|
|
@@ -26905,63 +27266,170 @@ function compileUpdate(query, table, context, rls, nonce) {
|
|
|
26905
27266
|
item.column,
|
|
26906
27267
|
toBoundValue(item.value)
|
|
26907
27268
|
);
|
|
26908
|
-
|
|
26909
|
-
|
|
26910
|
-
|
|
26911
|
-
|
|
26912
|
-
|
|
26913
|
-
];
|
|
27269
|
+
const write = statement(
|
|
27270
|
+
`UPDATE ${OR_ABORT} ${quoteIdentifier(table.name)} SET ${assigned.join(", ")}${where}${returning}`,
|
|
27271
|
+
params
|
|
27272
|
+
);
|
|
27273
|
+
if (!capture) return { statements: [write], guard: null };
|
|
27274
|
+
const guardParams = [];
|
|
27275
|
+
const guardWhere = whereClause(
|
|
27276
|
+
table,
|
|
27277
|
+
query.filters ?? [],
|
|
27278
|
+
policy,
|
|
27279
|
+
guardParams,
|
|
27280
|
+
rowid
|
|
27281
|
+
);
|
|
27282
|
+
const sent = new Map(
|
|
27283
|
+
[...values.values()].map((item) => [
|
|
27284
|
+
item.column.name,
|
|
27285
|
+
toBoundValue(item.value)
|
|
27286
|
+
])
|
|
27287
|
+
);
|
|
27288
|
+
return {
|
|
27289
|
+
statements: [write],
|
|
27290
|
+
guard: captureGuard(table, guardWhere, guardParams, nonce, sent)
|
|
27291
|
+
};
|
|
26914
27292
|
}
|
|
26915
|
-
function compileDelete(query, table, context, rls) {
|
|
27293
|
+
function compileDelete(query, table, context, rls, { state, nonce }, capture) {
|
|
26916
27294
|
requireFilter(query, context);
|
|
26917
27295
|
const params = [];
|
|
26918
27296
|
const policy = rls?.where("delete") ?? null;
|
|
26919
27297
|
if (rls && policy) rls.budget([policy]);
|
|
26920
|
-
const
|
|
26921
|
-
|
|
26922
|
-
|
|
26923
|
-
|
|
26924
|
-
|
|
26925
|
-
)
|
|
26926
|
-
];
|
|
26927
|
-
}
|
|
26928
|
-
function compile(query, snapshot, decision, context, options = {}) {
|
|
26929
|
-
const nonce = checkNonceOf(
|
|
26930
|
-
options.checkNonce ?? DEFAULT_CHECK_NONCE,
|
|
26931
|
-
"compile"
|
|
27298
|
+
const rowid = rowidWhere(table, state, nonce, "select");
|
|
27299
|
+
const where = whereClause(table, query.filters ?? [], policy, params, rowid);
|
|
27300
|
+
const write = statement(
|
|
27301
|
+
`DELETE FROM ${quoteIdentifier(table.name)}${where}${writeReturning(table, query.returning, "delete", capture)}`,
|
|
27302
|
+
params
|
|
26932
27303
|
);
|
|
26933
|
-
if (!
|
|
26934
|
-
|
|
26935
|
-
const
|
|
26936
|
-
|
|
26937
|
-
|
|
26938
|
-
|
|
26939
|
-
|
|
26940
|
-
|
|
27304
|
+
if (!capture) return { statements: [write], guard: null };
|
|
27305
|
+
const guardParams = [];
|
|
27306
|
+
const guardWhere = whereClause(
|
|
27307
|
+
table,
|
|
27308
|
+
query.filters ?? [],
|
|
27309
|
+
policy,
|
|
27310
|
+
guardParams,
|
|
27311
|
+
rowid
|
|
27312
|
+
);
|
|
27313
|
+
return {
|
|
27314
|
+
statements: [write],
|
|
27315
|
+
guard: captureGuard(table, guardWhere, guardParams, nonce, /* @__PURE__ */ new Map())
|
|
27316
|
+
};
|
|
27317
|
+
}
|
|
27318
|
+
function ownReturning(table, query) {
|
|
27319
|
+
if (query.action === "select" || query.returning === void 0) return null;
|
|
27320
|
+
if (query.returning === "*") return table.columns.map((item) => item.name);
|
|
27321
|
+
return columnList(table, query.returning).map((item) => item.name);
|
|
27322
|
+
}
|
|
27323
|
+
function bulkPlan(table) {
|
|
27324
|
+
return {
|
|
27325
|
+
columns: table.columns,
|
|
27326
|
+
guard: null,
|
|
27327
|
+
triggers: null,
|
|
27328
|
+
returning: null,
|
|
27329
|
+
bulk: true
|
|
27330
|
+
};
|
|
27331
|
+
}
|
|
27332
|
+
function compileWith(query, snapshot, decision, context, table, nonce, capture) {
|
|
26941
27333
|
try {
|
|
26942
|
-
const
|
|
27334
|
+
const state = newState2();
|
|
27335
|
+
const rls = decision.rls ? new Rls(
|
|
27336
|
+
decision.rls,
|
|
27337
|
+
snapshot,
|
|
27338
|
+
table,
|
|
27339
|
+
nonce,
|
|
27340
|
+
commandsOf(query),
|
|
27341
|
+
void 0,
|
|
27342
|
+
state
|
|
27343
|
+
) : void 0;
|
|
27344
|
+
const statementContext = { state, nonce };
|
|
26943
27345
|
let statements;
|
|
27346
|
+
let guard = null;
|
|
26944
27347
|
switch (query.action) {
|
|
26945
27348
|
case "select":
|
|
26946
|
-
statements = compileSelect(query, table, rls);
|
|
27349
|
+
statements = compileSelect(query, table, rls, statementContext);
|
|
26947
27350
|
break;
|
|
26948
27351
|
case "insert":
|
|
26949
|
-
statements = compileInsert(
|
|
27352
|
+
statements = compileInsert(
|
|
27353
|
+
query,
|
|
27354
|
+
table,
|
|
27355
|
+
rls,
|
|
27356
|
+
statementContext,
|
|
27357
|
+
capture
|
|
27358
|
+
);
|
|
26950
27359
|
break;
|
|
26951
27360
|
case "update":
|
|
26952
|
-
statements = compileUpdate(
|
|
27361
|
+
({ statements, guard } = compileUpdate(
|
|
27362
|
+
query,
|
|
27363
|
+
table,
|
|
27364
|
+
context,
|
|
27365
|
+
rls,
|
|
27366
|
+
statementContext,
|
|
27367
|
+
capture
|
|
27368
|
+
));
|
|
26953
27369
|
break;
|
|
26954
27370
|
case "delete":
|
|
26955
|
-
statements = compileDelete(
|
|
27371
|
+
({ statements, guard } = compileDelete(
|
|
27372
|
+
query,
|
|
27373
|
+
table,
|
|
27374
|
+
context,
|
|
27375
|
+
rls,
|
|
27376
|
+
statementContext,
|
|
27377
|
+
capture
|
|
27378
|
+
));
|
|
26956
27379
|
break;
|
|
26957
27380
|
}
|
|
26958
|
-
|
|
27381
|
+
const compiled = {
|
|
27382
|
+
ok: true,
|
|
27383
|
+
statements,
|
|
27384
|
+
restrictive: rls?.restrictive ?? []
|
|
27385
|
+
};
|
|
27386
|
+
if (!capture) return compiled;
|
|
27387
|
+
return {
|
|
27388
|
+
...compiled,
|
|
27389
|
+
capture: {
|
|
27390
|
+
columns: table.columns,
|
|
27391
|
+
guard,
|
|
27392
|
+
// A DELETE is judged on the row as it was before the write
|
|
27393
|
+
// (original spec §8.5), which its RETURNING is.
|
|
27394
|
+
triggers: query.action === "insert" || query.action === "update" ? triggersRead(table) : null,
|
|
27395
|
+
returning: ownReturning(table, query),
|
|
27396
|
+
bulk: false
|
|
27397
|
+
}
|
|
27398
|
+
};
|
|
26959
27399
|
} catch (error51) {
|
|
26960
27400
|
if (error51 instanceof Failure)
|
|
26961
27401
|
return error51.reason === void 0 ? { ok: false, error: error51.error } : { ok: false, error: error51.error, reason: error51.reason };
|
|
26962
27402
|
throw error51;
|
|
26963
27403
|
}
|
|
26964
27404
|
}
|
|
27405
|
+
function compile(query, snapshot, decision, context, options = {}) {
|
|
27406
|
+
const nonce = checkNonceOf(
|
|
27407
|
+
options.checkNonce ?? DEFAULT_CHECK_NONCE,
|
|
27408
|
+
"compile"
|
|
27409
|
+
);
|
|
27410
|
+
if (!decision.allow)
|
|
27411
|
+
return decision.reason === void 0 ? { ok: false, error: decision.error } : { ok: false, error: decision.error, reason: decision.reason };
|
|
27412
|
+
const table = resolveTable(snapshot, query.table);
|
|
27413
|
+
if (!table)
|
|
27414
|
+
return {
|
|
27415
|
+
ok: false,
|
|
27416
|
+
error: dataError("TABLE_NOT_FOUND", { table: query.table })
|
|
27417
|
+
};
|
|
27418
|
+
if (options.capture !== true || query.action === "select")
|
|
27419
|
+
return compileWith(query, snapshot, decision, context, table, nonce, false);
|
|
27420
|
+
const captured = table.kind === "virtual" && query.action !== "insert" ? void 0 : compileWith(query, snapshot, decision, context, table, nonce, true);
|
|
27421
|
+
if (captured?.ok) return captured;
|
|
27422
|
+
const plain = compileWith(
|
|
27423
|
+
query,
|
|
27424
|
+
snapshot,
|
|
27425
|
+
decision,
|
|
27426
|
+
context,
|
|
27427
|
+
table,
|
|
27428
|
+
nonce,
|
|
27429
|
+
false
|
|
27430
|
+
);
|
|
27431
|
+
return plain.ok ? { ...plain, capture: bulkPlan(table) } : plain;
|
|
27432
|
+
}
|
|
26965
27433
|
|
|
26966
27434
|
// ../../packages/data-core/src/sql-depth.ts
|
|
26967
27435
|
var D1_EXPRESSION_DEPTH = 100;
|
|
@@ -27735,6 +28203,231 @@ function expressionDepth(sql, { planner = true } = {}) {
|
|
|
27735
28203
|
}
|
|
27736
28204
|
}
|
|
27737
28205
|
|
|
28206
|
+
// ../../packages/data-core/src/sql-head.ts
|
|
28207
|
+
var HEAD_TOKENS = 12;
|
|
28208
|
+
var BOM2 = 65279;
|
|
28209
|
+
function isBlankStart(char) {
|
|
28210
|
+
return char === " " || char === " " || char === "\n" || char === "\f" || char === "\r";
|
|
28211
|
+
}
|
|
28212
|
+
function isBlank(char) {
|
|
28213
|
+
return isBlankStart(char) || char === "\v";
|
|
28214
|
+
}
|
|
28215
|
+
function isWordStart2(char) {
|
|
28216
|
+
return /[A-Za-z_]/.test(char) || char.charCodeAt(0) >= 128;
|
|
28217
|
+
}
|
|
28218
|
+
function isWordPart2(char) {
|
|
28219
|
+
return /[A-Za-z0-9_$]/.test(char) || char.charCodeAt(0) >= 128;
|
|
28220
|
+
}
|
|
28221
|
+
function skipBlanks(text2, from) {
|
|
28222
|
+
let index = from;
|
|
28223
|
+
for (; ; ) {
|
|
28224
|
+
const char = text2.charAt(index);
|
|
28225
|
+
if (isBlankStart(char)) {
|
|
28226
|
+
index++;
|
|
28227
|
+
while (index < text2.length && isBlank(text2.charAt(index))) index++;
|
|
28228
|
+
} else if (text2.charCodeAt(index) === BOM2) index++;
|
|
28229
|
+
else if (char === "-" && text2.charAt(index + 1) === "-") {
|
|
28230
|
+
const end = text2.indexOf("\n", index + 2);
|
|
28231
|
+
index = end < 0 ? text2.length : end;
|
|
28232
|
+
} else if (char === "/" && text2.charAt(index + 1) === "*") {
|
|
28233
|
+
const end = text2.indexOf("*/", index + 2);
|
|
28234
|
+
index = end < 0 ? text2.length : end + 2;
|
|
28235
|
+
} else return index;
|
|
28236
|
+
}
|
|
28237
|
+
}
|
|
28238
|
+
function readQuoted(text2, start, delimiter) {
|
|
28239
|
+
let value = "";
|
|
28240
|
+
let index = start + 1;
|
|
28241
|
+
for (; ; ) {
|
|
28242
|
+
const close = text2.indexOf(delimiter, index);
|
|
28243
|
+
if (close < 0) return void 0;
|
|
28244
|
+
value += text2.slice(index, close);
|
|
28245
|
+
if (text2.charAt(close + 1) === delimiter) {
|
|
28246
|
+
value += delimiter;
|
|
28247
|
+
index = close + 2;
|
|
28248
|
+
continue;
|
|
28249
|
+
}
|
|
28250
|
+
return { text: value, end: close + 1 };
|
|
28251
|
+
}
|
|
28252
|
+
}
|
|
28253
|
+
function headTokens(text2) {
|
|
28254
|
+
const tokens = [];
|
|
28255
|
+
let index = 0;
|
|
28256
|
+
while (tokens.length < HEAD_TOKENS) {
|
|
28257
|
+
index = skipBlanks(text2, index);
|
|
28258
|
+
const char = text2.charAt(index);
|
|
28259
|
+
if (index >= text2.length) break;
|
|
28260
|
+
if (char === '"' || char === "`" || char === "'") {
|
|
28261
|
+
const quoted2 = readQuoted(text2, index, char);
|
|
28262
|
+
if (!quoted2) break;
|
|
28263
|
+
tokens.push({ kind: "name", text: quoted2.text });
|
|
28264
|
+
index = quoted2.end;
|
|
28265
|
+
} else if (char === "[") {
|
|
28266
|
+
const close = text2.indexOf("]", index + 1);
|
|
28267
|
+
if (close < 0) break;
|
|
28268
|
+
tokens.push({ kind: "name", text: text2.slice(index + 1, close) });
|
|
28269
|
+
index = close + 1;
|
|
28270
|
+
} else if ((char === "x" || char === "X") && text2.charAt(index + 1) === "'") {
|
|
28271
|
+
break;
|
|
28272
|
+
} else if (isWordStart2(char)) {
|
|
28273
|
+
let end = index + 1;
|
|
28274
|
+
while (end < text2.length && isWordPart2(text2.charAt(end))) end++;
|
|
28275
|
+
tokens.push({ kind: "word", text: text2.slice(index, end) });
|
|
28276
|
+
index = end;
|
|
28277
|
+
} else if (char === "." && !/[0-9]/.test(text2.charAt(index + 1))) {
|
|
28278
|
+
tokens.push({ kind: "dot" });
|
|
28279
|
+
index++;
|
|
28280
|
+
} else break;
|
|
28281
|
+
}
|
|
28282
|
+
tokens.push({ kind: "stop" });
|
|
28283
|
+
return tokens;
|
|
28284
|
+
}
|
|
28285
|
+
var OTHER = { kind: "other" };
|
|
28286
|
+
var NO_NAME = {
|
|
28287
|
+
kind: "unreadable",
|
|
28288
|
+
reason: "the table name could not be read"
|
|
28289
|
+
};
|
|
28290
|
+
var NO_COLUMN = {
|
|
28291
|
+
kind: "unreadable",
|
|
28292
|
+
reason: "the column name could not be read"
|
|
28293
|
+
};
|
|
28294
|
+
var OTHER_SCHEMA = {
|
|
28295
|
+
kind: "unreadable",
|
|
28296
|
+
reason: "a table in another schema"
|
|
28297
|
+
};
|
|
28298
|
+
var PUBLIC_SCHEMA = {
|
|
28299
|
+
kind: "unreadable",
|
|
28300
|
+
reason: 'SQLite has no schema "public": write the table name without "public."'
|
|
28301
|
+
};
|
|
28302
|
+
var Head = class {
|
|
28303
|
+
constructor(tokens) {
|
|
28304
|
+
this.tokens = tokens;
|
|
28305
|
+
}
|
|
28306
|
+
token(at) {
|
|
28307
|
+
return this.tokens[Math.min(at, this.tokens.length - 1)] ?? { kind: "stop" };
|
|
28308
|
+
}
|
|
28309
|
+
/** The bare word `word` (lower case), in any ASCII case. */
|
|
28310
|
+
is(at, word) {
|
|
28311
|
+
const token = this.token(at);
|
|
28312
|
+
return token.kind === "word" && asciiLower(token.text) === word;
|
|
28313
|
+
}
|
|
28314
|
+
nameAt(at) {
|
|
28315
|
+
const token = this.token(at);
|
|
28316
|
+
return token.kind === "word" || token.kind === "name" ? token.text : void 0;
|
|
28317
|
+
}
|
|
28318
|
+
/**
|
|
28319
|
+
* SQLite's `fullname`. `main.` is the database a migration writes: the
|
|
28320
|
+
* name goes without it, and `main` says it was written (known-issues
|
|
28321
|
+
* #226); `temp.` (in any case, quoted or not, as sqlite3FindDbName
|
|
28322
|
+
* matches it) is a table that goes with the connection; `public.` is
|
|
28323
|
+
* what a Postgres migration writes, said in its own words; any other
|
|
28324
|
+
* schema is one D1 does not have.
|
|
28325
|
+
*/
|
|
28326
|
+
table(at) {
|
|
28327
|
+
const first = this.nameAt(at);
|
|
28328
|
+
if (first === void 0) return { ok: false, head: NO_NAME };
|
|
28329
|
+
if (this.token(at + 1).kind !== "dot")
|
|
28330
|
+
return { ok: true, name: first, next: at + 1, main: false };
|
|
28331
|
+
const second = this.nameAt(at + 2);
|
|
28332
|
+
if (second === void 0) return { ok: false, head: NO_NAME };
|
|
28333
|
+
const schema = asciiLower(first);
|
|
28334
|
+
if (schema === "main")
|
|
28335
|
+
return { ok: true, name: second, next: at + 3, main: true };
|
|
28336
|
+
let head = OTHER_SCHEMA;
|
|
28337
|
+
if (schema === "temp") head = OTHER;
|
|
28338
|
+
else if (schema === "public") head = PUBLIC_SCHEMA;
|
|
28339
|
+
return { ok: false, head, next: at + 3 };
|
|
28340
|
+
}
|
|
28341
|
+
};
|
|
28342
|
+
function inMain(read) {
|
|
28343
|
+
return read.main ? { main: true } : {};
|
|
28344
|
+
}
|
|
28345
|
+
function readCreate(head) {
|
|
28346
|
+
if (head.is(1, "policy")) return { kind: "create-policy" };
|
|
28347
|
+
if (head.is(1, "temp") || head.is(1, "temporary")) return OTHER;
|
|
28348
|
+
let at;
|
|
28349
|
+
if (head.is(1, "table")) at = 2;
|
|
28350
|
+
else if (head.is(1, "virtual") && head.is(2, "table")) at = 3;
|
|
28351
|
+
else return OTHER;
|
|
28352
|
+
if (head.is(at, "if")) {
|
|
28353
|
+
if (!head.is(at + 1, "not") || !head.is(at + 2, "exists")) return NO_NAME;
|
|
28354
|
+
at += 3;
|
|
28355
|
+
}
|
|
28356
|
+
const table = head.table(at);
|
|
28357
|
+
return table.ok ? { kind: "create-table", table: table.name } : table.head;
|
|
28358
|
+
}
|
|
28359
|
+
function readDrop(head) {
|
|
28360
|
+
if (head.is(1, "policy")) return { kind: "drop-policy" };
|
|
28361
|
+
if (!head.is(1, "table")) return OTHER;
|
|
28362
|
+
let at = 2;
|
|
28363
|
+
if (head.is(at, "if")) {
|
|
28364
|
+
if (!head.is(at + 1, "exists")) return NO_NAME;
|
|
28365
|
+
at += 2;
|
|
28366
|
+
}
|
|
28367
|
+
const table = head.table(at);
|
|
28368
|
+
return table.ok ? { kind: "drop-table", table: table.name, ...inMain(table) } : table.head;
|
|
28369
|
+
}
|
|
28370
|
+
var RLS_ACTIONS = ["enable", "disable", "force", "no"];
|
|
28371
|
+
function readRenameColumn(head, table, at) {
|
|
28372
|
+
let from = at;
|
|
28373
|
+
if (head.is(from, "column") && head.nameAt(from + 1) !== void 0 && head.is(from + 2, "to"))
|
|
28374
|
+
from += 1;
|
|
28375
|
+
const column2 = head.nameAt(from);
|
|
28376
|
+
if (column2 === void 0 || !head.is(from + 1, "to")) return NO_COLUMN;
|
|
28377
|
+
const to = head.nameAt(from + 2);
|
|
28378
|
+
return to === void 0 ? NO_COLUMN : {
|
|
28379
|
+
kind: "rename-column",
|
|
28380
|
+
table: table.name,
|
|
28381
|
+
column: column2,
|
|
28382
|
+
to,
|
|
28383
|
+
...inMain(table)
|
|
28384
|
+
};
|
|
28385
|
+
}
|
|
28386
|
+
function readAlter(head) {
|
|
28387
|
+
if (head.is(1, "policy")) return { kind: "alter-policy" };
|
|
28388
|
+
if (!head.is(1, "table")) return OTHER;
|
|
28389
|
+
const sqlite = head.table(2);
|
|
28390
|
+
const action = sqlite.next;
|
|
28391
|
+
if (action !== void 0) {
|
|
28392
|
+
if (head.is(action, "rename") && head.is(action + 1, "to")) {
|
|
28393
|
+
if (!sqlite.ok) return sqlite.head;
|
|
28394
|
+
const to = head.table(action + 2);
|
|
28395
|
+
return to.ok ? {
|
|
28396
|
+
kind: "rename-table",
|
|
28397
|
+
table: sqlite.name,
|
|
28398
|
+
to: to.name,
|
|
28399
|
+
...inMain(sqlite)
|
|
28400
|
+
} : to.head;
|
|
28401
|
+
}
|
|
28402
|
+
if (head.is(action, "rename")) {
|
|
28403
|
+
if (!sqlite.ok) return sqlite.head;
|
|
28404
|
+
return readRenameColumn(head, sqlite, action + 1);
|
|
28405
|
+
}
|
|
28406
|
+
if (head.is(action, "add") || head.is(action, "drop"))
|
|
28407
|
+
return sqlite.ok ? { kind: "alter-table", table: sqlite.name } : sqlite.head;
|
|
28408
|
+
}
|
|
28409
|
+
let at = 2;
|
|
28410
|
+
if (head.is(at, "if") && head.is(at + 1, "exists")) at += 2;
|
|
28411
|
+
if (head.is(at, "only")) at++;
|
|
28412
|
+
const next = head.table(at).next;
|
|
28413
|
+
if (next !== void 0 && RLS_ACTIONS.some((word) => head.is(next, word)))
|
|
28414
|
+
return { kind: "rls" };
|
|
28415
|
+
return sqlite.ok ? OTHER : sqlite.head;
|
|
28416
|
+
}
|
|
28417
|
+
function readSqlHead(text2) {
|
|
28418
|
+
if (text2.includes("\0"))
|
|
28419
|
+
return { kind: "unreadable", reason: "the statement has a NUL character" };
|
|
28420
|
+
const head = new Head(headTokens(text2));
|
|
28421
|
+
if (head.is(0, "create")) return readCreate(head);
|
|
28422
|
+
if (head.is(0, "drop")) return readDrop(head);
|
|
28423
|
+
if (head.is(0, "alter")) return readAlter(head);
|
|
28424
|
+
if (head.is(0, "comment") && head.is(1, "on") && head.is(2, "policy"))
|
|
28425
|
+
return { kind: "comment-policy" };
|
|
28426
|
+
if (head.is(0, "grant")) return { kind: "grant" };
|
|
28427
|
+
if (head.is(0, "revoke")) return { kind: "revoke" };
|
|
28428
|
+
return OTHER;
|
|
28429
|
+
}
|
|
28430
|
+
|
|
27738
28431
|
// ../../packages/data-core/src/policy-index.ts
|
|
27739
28432
|
var INDEX_SQL = `SELECT t.name AS table_name, il.name AS index_name, il."partial" AS partial, ix.name AS column_name, ix.coll AS collation FROM pragma_table_list AS t JOIN pragma_index_list(t.name, t.schema) AS il JOIN pragma_index_xinfo(il.name, t.schema) AS ix WHERE t.schema = 'main' AND t.type = 'table' AND ${systemTablePredicate("t.name")} AND ix.seqno = 0`;
|
|
27740
28433
|
function indexesFromRows(rows) {
|
|
@@ -28011,8 +28704,34 @@ function unindexedSubqueries(snapshot, indexes, policies) {
|
|
|
28011
28704
|
return found;
|
|
28012
28705
|
}
|
|
28013
28706
|
|
|
28707
|
+
// ../../packages/data-core/src/realtime-filter.ts
|
|
28708
|
+
var FILTER_REASONS = {
|
|
28709
|
+
bytes: "must be a string of up to 1024 bytes in UTF-8",
|
|
28710
|
+
control: "must have no control character",
|
|
28711
|
+
syntax: "supports eq, neq, lt, lte, gt, gte and in, one condition",
|
|
28712
|
+
list: "needs in.(a,b) with 1 to 100 values"
|
|
28713
|
+
};
|
|
28714
|
+
|
|
28014
28715
|
// ../../packages/data-core/src/realtime-protocol.ts
|
|
28015
28716
|
var REALTIME_PROTOCOL_VERSION = "1.0.0";
|
|
28717
|
+
var MAX_CHANGE_CHANNELS_PER_TABLE = 4;
|
|
28718
|
+
var JOIN_CONFIG_REASONS = {
|
|
28719
|
+
object: "must be an object",
|
|
28720
|
+
unsupported: "is not supported",
|
|
28721
|
+
boolean: "must be true or false",
|
|
28722
|
+
presenceKey: "must be 1 to 128 characters",
|
|
28723
|
+
changes: "must be an array of up to 16 subscriptions",
|
|
28724
|
+
changeEvent: "must be *, INSERT, UPDATE or DELETE",
|
|
28725
|
+
schema: "must be public",
|
|
28726
|
+
table: "must be a table name of 1 to 128 characters, or *",
|
|
28727
|
+
filter: FILTER_REASONS.bytes,
|
|
28728
|
+
filterControl: FILTER_REASONS.control,
|
|
28729
|
+
filterSyntax: FILTER_REASONS.syntax,
|
|
28730
|
+
filterList: FILTER_REASONS.list,
|
|
28731
|
+
filterTable: "needs a table: a filter cannot go with *",
|
|
28732
|
+
/** The hub's, after `config.postgres_changes[<i>].table` (3-2c-1): `MAX_CHANGE_CHANNELS_PER_TABLE` against the connection's joins. */
|
|
28733
|
+
changeChannels: `would put more than ${String(MAX_CHANGE_CHANNELS_PER_TABLE)} channels of this connection on one table's changes (* counts for every table): add the subscription to a channel it already has`
|
|
28734
|
+
};
|
|
28016
28735
|
var REALTIME_CLOSE = {
|
|
28017
28736
|
UNSUPPORTED_PROTOCOL: {
|
|
28018
28737
|
code: 4e3,
|
|
@@ -29203,7 +29922,7 @@ function readClause(stream) {
|
|
|
29203
29922
|
checkExpressionSize(expr, open.position);
|
|
29204
29923
|
return { text: printExpr(expr), position: open.position };
|
|
29205
29924
|
}
|
|
29206
|
-
function
|
|
29925
|
+
function readCreate2(stream, start) {
|
|
29207
29926
|
stream.expectKeyword("policy");
|
|
29208
29927
|
const name = readPolicyName(stream);
|
|
29209
29928
|
stream.expectKeyword("on");
|
|
@@ -29263,7 +29982,7 @@ function readCreate(stream, start) {
|
|
|
29263
29982
|
throw new PolicySyntaxError(problem.replace(/\.$/, ""), position);
|
|
29264
29983
|
return { kind: "create", policy };
|
|
29265
29984
|
}
|
|
29266
|
-
function
|
|
29985
|
+
function readDrop2(stream) {
|
|
29267
29986
|
stream.expectKeyword("policy");
|
|
29268
29987
|
let ifExists = false;
|
|
29269
29988
|
if (stream.acceptKeyword("if")) {
|
|
@@ -29294,11 +30013,11 @@ function parsePolicyStatement(text2) {
|
|
|
29294
30013
|
position: 1
|
|
29295
30014
|
};
|
|
29296
30015
|
try {
|
|
29297
|
-
const stream = new TokenStream(
|
|
30016
|
+
const stream = new TokenStream(tokenize2(text2));
|
|
29298
30017
|
const start = stream.next();
|
|
29299
30018
|
let statement2;
|
|
29300
|
-
if (isKeyword(start, "create")) statement2 =
|
|
29301
|
-
else if (isKeyword(start, "drop")) statement2 =
|
|
30019
|
+
if (isKeyword(start, "create")) statement2 = readCreate2(stream, start);
|
|
30020
|
+
else if (isKeyword(start, "drop")) statement2 = readDrop2(stream);
|
|
29302
30021
|
else if (isKeyword(start, "alter"))
|
|
29303
30022
|
throw new PolicySyntaxError(
|
|
29304
30023
|
"ALTER POLICY is not supported here yet: DROP POLICY and CREATE POLICY again",
|
|
@@ -29321,7 +30040,7 @@ function parsePolicyStatement(text2) {
|
|
|
29321
30040
|
function splitPolicyStatements(text2) {
|
|
29322
30041
|
let tokens;
|
|
29323
30042
|
try {
|
|
29324
|
-
tokens =
|
|
30043
|
+
tokens = tokenize2(text2);
|
|
29325
30044
|
} catch (error51) {
|
|
29326
30045
|
if (error51 instanceof PolicySyntaxError)
|
|
29327
30046
|
return { ok: false, reason: error51.reason, position: error51.position };
|
|
@@ -29410,7 +30129,7 @@ function parseMigrationPolicyStatement(text2) {
|
|
|
29410
30129
|
position: 1
|
|
29411
30130
|
};
|
|
29412
30131
|
try {
|
|
29413
|
-
const stream = new TokenStream(
|
|
30132
|
+
const stream = new TokenStream(tokenize2(text2));
|
|
29414
30133
|
let statement2;
|
|
29415
30134
|
if (stream.acceptKeyword("comment")) statement2 = readComment(stream);
|
|
29416
30135
|
else if (isKeyword(stream.peek(), "alter") && isKeyword(stream.peek(1), "table")) {
|
|
@@ -29427,230 +30146,11 @@ function parseMigrationPolicyStatement(text2) {
|
|
|
29427
30146
|
}
|
|
29428
30147
|
}
|
|
29429
30148
|
|
|
29430
|
-
// ../../packages/data-core/src/
|
|
29431
|
-
var
|
|
29432
|
-
var
|
|
29433
|
-
|
|
29434
|
-
|
|
29435
|
-
}
|
|
29436
|
-
function isBlank(char) {
|
|
29437
|
-
return isBlankStart(char) || char === "\v";
|
|
29438
|
-
}
|
|
29439
|
-
function isWordStart2(char) {
|
|
29440
|
-
return /[A-Za-z_]/.test(char) || char.charCodeAt(0) >= 128;
|
|
29441
|
-
}
|
|
29442
|
-
function isWordPart2(char) {
|
|
29443
|
-
return /[A-Za-z0-9_$]/.test(char) || char.charCodeAt(0) >= 128;
|
|
29444
|
-
}
|
|
29445
|
-
function skipBlanks(text2, from) {
|
|
29446
|
-
let index = from;
|
|
29447
|
-
for (; ; ) {
|
|
29448
|
-
const char = text2.charAt(index);
|
|
29449
|
-
if (isBlankStart(char)) {
|
|
29450
|
-
index++;
|
|
29451
|
-
while (index < text2.length && isBlank(text2.charAt(index))) index++;
|
|
29452
|
-
} else if (text2.charCodeAt(index) === BOM2) index++;
|
|
29453
|
-
else if (char === "-" && text2.charAt(index + 1) === "-") {
|
|
29454
|
-
const end = text2.indexOf("\n", index + 2);
|
|
29455
|
-
index = end < 0 ? text2.length : end;
|
|
29456
|
-
} else if (char === "/" && text2.charAt(index + 1) === "*") {
|
|
29457
|
-
const end = text2.indexOf("*/", index + 2);
|
|
29458
|
-
index = end < 0 ? text2.length : end + 2;
|
|
29459
|
-
} else return index;
|
|
29460
|
-
}
|
|
29461
|
-
}
|
|
29462
|
-
function readQuoted(text2, start, delimiter) {
|
|
29463
|
-
let value = "";
|
|
29464
|
-
let index = start + 1;
|
|
29465
|
-
for (; ; ) {
|
|
29466
|
-
const close = text2.indexOf(delimiter, index);
|
|
29467
|
-
if (close < 0) return void 0;
|
|
29468
|
-
value += text2.slice(index, close);
|
|
29469
|
-
if (text2.charAt(close + 1) === delimiter) {
|
|
29470
|
-
value += delimiter;
|
|
29471
|
-
index = close + 2;
|
|
29472
|
-
continue;
|
|
29473
|
-
}
|
|
29474
|
-
return { text: value, end: close + 1 };
|
|
29475
|
-
}
|
|
29476
|
-
}
|
|
29477
|
-
function headTokens(text2) {
|
|
29478
|
-
const tokens = [];
|
|
29479
|
-
let index = 0;
|
|
29480
|
-
while (tokens.length < HEAD_TOKENS) {
|
|
29481
|
-
index = skipBlanks(text2, index);
|
|
29482
|
-
const char = text2.charAt(index);
|
|
29483
|
-
if (index >= text2.length) break;
|
|
29484
|
-
if (char === '"' || char === "`" || char === "'") {
|
|
29485
|
-
const quoted2 = readQuoted(text2, index, char);
|
|
29486
|
-
if (!quoted2) break;
|
|
29487
|
-
tokens.push({ kind: "name", text: quoted2.text });
|
|
29488
|
-
index = quoted2.end;
|
|
29489
|
-
} else if (char === "[") {
|
|
29490
|
-
const close = text2.indexOf("]", index + 1);
|
|
29491
|
-
if (close < 0) break;
|
|
29492
|
-
tokens.push({ kind: "name", text: text2.slice(index + 1, close) });
|
|
29493
|
-
index = close + 1;
|
|
29494
|
-
} else if ((char === "x" || char === "X") && text2.charAt(index + 1) === "'") {
|
|
29495
|
-
break;
|
|
29496
|
-
} else if (isWordStart2(char)) {
|
|
29497
|
-
let end = index + 1;
|
|
29498
|
-
while (end < text2.length && isWordPart2(text2.charAt(end))) end++;
|
|
29499
|
-
tokens.push({ kind: "word", text: text2.slice(index, end) });
|
|
29500
|
-
index = end;
|
|
29501
|
-
} else if (char === "." && !/[0-9]/.test(text2.charAt(index + 1))) {
|
|
29502
|
-
tokens.push({ kind: "dot" });
|
|
29503
|
-
index++;
|
|
29504
|
-
} else break;
|
|
29505
|
-
}
|
|
29506
|
-
tokens.push({ kind: "stop" });
|
|
29507
|
-
return tokens;
|
|
29508
|
-
}
|
|
29509
|
-
var OTHER = { kind: "other" };
|
|
29510
|
-
var NO_NAME = {
|
|
29511
|
-
kind: "unreadable",
|
|
29512
|
-
reason: "the table name could not be read"
|
|
29513
|
-
};
|
|
29514
|
-
var NO_COLUMN = {
|
|
29515
|
-
kind: "unreadable",
|
|
29516
|
-
reason: "the column name could not be read"
|
|
29517
|
-
};
|
|
29518
|
-
var OTHER_SCHEMA = {
|
|
29519
|
-
kind: "unreadable",
|
|
29520
|
-
reason: "a table in another schema"
|
|
29521
|
-
};
|
|
29522
|
-
var PUBLIC_SCHEMA = {
|
|
29523
|
-
kind: "unreadable",
|
|
29524
|
-
reason: 'SQLite has no schema "public": write the table name without "public."'
|
|
29525
|
-
};
|
|
29526
|
-
var Head = class {
|
|
29527
|
-
constructor(tokens) {
|
|
29528
|
-
this.tokens = tokens;
|
|
29529
|
-
}
|
|
29530
|
-
token(at) {
|
|
29531
|
-
return this.tokens[Math.min(at, this.tokens.length - 1)] ?? { kind: "stop" };
|
|
29532
|
-
}
|
|
29533
|
-
/** The bare word `word` (lower case), in any ASCII case. */
|
|
29534
|
-
is(at, word) {
|
|
29535
|
-
const token = this.token(at);
|
|
29536
|
-
return token.kind === "word" && asciiLower(token.text) === word;
|
|
29537
|
-
}
|
|
29538
|
-
nameAt(at) {
|
|
29539
|
-
const token = this.token(at);
|
|
29540
|
-
return token.kind === "word" || token.kind === "name" ? token.text : void 0;
|
|
29541
|
-
}
|
|
29542
|
-
/**
|
|
29543
|
-
* SQLite's `fullname`. `main.` is the database a migration writes: the
|
|
29544
|
-
* name goes without it, and `main` says it was written (known-issues
|
|
29545
|
-
* #226); `temp.` (in any case, quoted or not, as sqlite3FindDbName
|
|
29546
|
-
* matches it) is a table that goes with the connection; `public.` is
|
|
29547
|
-
* what a Postgres migration writes, said in its own words; any other
|
|
29548
|
-
* schema is one D1 does not have.
|
|
29549
|
-
*/
|
|
29550
|
-
table(at) {
|
|
29551
|
-
const first = this.nameAt(at);
|
|
29552
|
-
if (first === void 0) return { ok: false, head: NO_NAME };
|
|
29553
|
-
if (this.token(at + 1).kind !== "dot")
|
|
29554
|
-
return { ok: true, name: first, next: at + 1, main: false };
|
|
29555
|
-
const second = this.nameAt(at + 2);
|
|
29556
|
-
if (second === void 0) return { ok: false, head: NO_NAME };
|
|
29557
|
-
const schema = asciiLower(first);
|
|
29558
|
-
if (schema === "main")
|
|
29559
|
-
return { ok: true, name: second, next: at + 3, main: true };
|
|
29560
|
-
let head = OTHER_SCHEMA;
|
|
29561
|
-
if (schema === "temp") head = OTHER;
|
|
29562
|
-
else if (schema === "public") head = PUBLIC_SCHEMA;
|
|
29563
|
-
return { ok: false, head, next: at + 3 };
|
|
29564
|
-
}
|
|
29565
|
-
};
|
|
29566
|
-
function inMain(read) {
|
|
29567
|
-
return read.main ? { main: true } : {};
|
|
29568
|
-
}
|
|
29569
|
-
function readCreate2(head) {
|
|
29570
|
-
if (head.is(1, "policy")) return { kind: "create-policy" };
|
|
29571
|
-
if (head.is(1, "temp") || head.is(1, "temporary")) return OTHER;
|
|
29572
|
-
let at;
|
|
29573
|
-
if (head.is(1, "table")) at = 2;
|
|
29574
|
-
else if (head.is(1, "virtual") && head.is(2, "table")) at = 3;
|
|
29575
|
-
else return OTHER;
|
|
29576
|
-
if (head.is(at, "if")) {
|
|
29577
|
-
if (!head.is(at + 1, "not") || !head.is(at + 2, "exists")) return NO_NAME;
|
|
29578
|
-
at += 3;
|
|
29579
|
-
}
|
|
29580
|
-
const table = head.table(at);
|
|
29581
|
-
return table.ok ? { kind: "create-table", table: table.name } : table.head;
|
|
29582
|
-
}
|
|
29583
|
-
function readDrop2(head) {
|
|
29584
|
-
if (head.is(1, "policy")) return { kind: "drop-policy" };
|
|
29585
|
-
if (!head.is(1, "table")) return OTHER;
|
|
29586
|
-
let at = 2;
|
|
29587
|
-
if (head.is(at, "if")) {
|
|
29588
|
-
if (!head.is(at + 1, "exists")) return NO_NAME;
|
|
29589
|
-
at += 2;
|
|
29590
|
-
}
|
|
29591
|
-
const table = head.table(at);
|
|
29592
|
-
return table.ok ? { kind: "drop-table", table: table.name, ...inMain(table) } : table.head;
|
|
29593
|
-
}
|
|
29594
|
-
var RLS_ACTIONS = ["enable", "disable", "force", "no"];
|
|
29595
|
-
function readRenameColumn(head, table, at) {
|
|
29596
|
-
let from = at;
|
|
29597
|
-
if (head.is(from, "column") && head.nameAt(from + 1) !== void 0 && head.is(from + 2, "to"))
|
|
29598
|
-
from += 1;
|
|
29599
|
-
const column2 = head.nameAt(from);
|
|
29600
|
-
if (column2 === void 0 || !head.is(from + 1, "to")) return NO_COLUMN;
|
|
29601
|
-
const to = head.nameAt(from + 2);
|
|
29602
|
-
return to === void 0 ? NO_COLUMN : {
|
|
29603
|
-
kind: "rename-column",
|
|
29604
|
-
table: table.name,
|
|
29605
|
-
column: column2,
|
|
29606
|
-
to,
|
|
29607
|
-
...inMain(table)
|
|
29608
|
-
};
|
|
29609
|
-
}
|
|
29610
|
-
function readAlter(head) {
|
|
29611
|
-
if (head.is(1, "policy")) return { kind: "alter-policy" };
|
|
29612
|
-
if (!head.is(1, "table")) return OTHER;
|
|
29613
|
-
const sqlite = head.table(2);
|
|
29614
|
-
const action = sqlite.next;
|
|
29615
|
-
if (action !== void 0) {
|
|
29616
|
-
if (head.is(action, "rename") && head.is(action + 1, "to")) {
|
|
29617
|
-
if (!sqlite.ok) return sqlite.head;
|
|
29618
|
-
const to = head.table(action + 2);
|
|
29619
|
-
return to.ok ? {
|
|
29620
|
-
kind: "rename-table",
|
|
29621
|
-
table: sqlite.name,
|
|
29622
|
-
to: to.name,
|
|
29623
|
-
...inMain(sqlite)
|
|
29624
|
-
} : to.head;
|
|
29625
|
-
}
|
|
29626
|
-
if (head.is(action, "rename")) {
|
|
29627
|
-
if (!sqlite.ok) return sqlite.head;
|
|
29628
|
-
return readRenameColumn(head, sqlite, action + 1);
|
|
29629
|
-
}
|
|
29630
|
-
if (head.is(action, "add") || head.is(action, "drop"))
|
|
29631
|
-
return sqlite.ok ? { kind: "alter-table", table: sqlite.name } : sqlite.head;
|
|
29632
|
-
}
|
|
29633
|
-
let at = 2;
|
|
29634
|
-
if (head.is(at, "if") && head.is(at + 1, "exists")) at += 2;
|
|
29635
|
-
if (head.is(at, "only")) at++;
|
|
29636
|
-
const next = head.table(at).next;
|
|
29637
|
-
if (next !== void 0 && RLS_ACTIONS.some((word) => head.is(next, word)))
|
|
29638
|
-
return { kind: "rls" };
|
|
29639
|
-
return sqlite.ok ? OTHER : sqlite.head;
|
|
29640
|
-
}
|
|
29641
|
-
function readSqlHead(text2) {
|
|
29642
|
-
if (text2.includes("\0"))
|
|
29643
|
-
return { kind: "unreadable", reason: "the statement has a NUL character" };
|
|
29644
|
-
const head = new Head(headTokens(text2));
|
|
29645
|
-
if (head.is(0, "create")) return readCreate2(head);
|
|
29646
|
-
if (head.is(0, "drop")) return readDrop2(head);
|
|
29647
|
-
if (head.is(0, "alter")) return readAlter(head);
|
|
29648
|
-
if (head.is(0, "comment") && head.is(1, "on") && head.is(2, "policy"))
|
|
29649
|
-
return { kind: "comment-policy" };
|
|
29650
|
-
if (head.is(0, "grant")) return { kind: "grant" };
|
|
29651
|
-
if (head.is(0, "revoke")) return { kind: "revoke" };
|
|
29652
|
-
return OTHER;
|
|
29653
|
-
}
|
|
30149
|
+
// ../../packages/data-core/src/realtime-publication.ts
|
|
30150
|
+
var REALTIME_TABLES = "_naro_realtime_tables";
|
|
30151
|
+
var REALTIME_TABLES_SQL = `CREATE TABLE IF NOT EXISTS ${REALTIME_TABLES} (table_name TEXT NOT NULL PRIMARY KEY COLLATE NOCASE, created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')))`;
|
|
30152
|
+
var MAX_PUBLISHED_TABLES = 100;
|
|
30153
|
+
var PUBLISHED_TABLES_SQL = `SELECT table_name FROM ${REALTIME_TABLES} ORDER BY rowid LIMIT ${String(MAX_PUBLISHED_TABLES)}`;
|
|
29654
30154
|
|
|
29655
30155
|
// ../../packages/data-core/src/system-sql.ts
|
|
29656
30156
|
async function convertLegacyPolicies(db, found) {
|
|
@@ -29685,6 +30185,7 @@ var MIGRATIONS_TABLE = "CREATE TABLE IF NOT EXISTS _naro_migrations (version INT
|
|
|
29685
30185
|
var STORAGE_SUBQUERIES_VERSION = 7;
|
|
29686
30186
|
var STORAGE_SUBQUERIES_NAME = "storage_subquery_policies";
|
|
29687
30187
|
var STORAGE_SUBQUERIES_SQL = `SELECT version FROM _naro_migrations WHERE version = ${String(STORAGE_SUBQUERIES_VERSION)} AND name = '${STORAGE_SUBQUERIES_NAME}'`;
|
|
30188
|
+
var REALTIME_TABLES_VERSION = 8;
|
|
29688
30189
|
var SYSTEM_MIGRATIONS = [
|
|
29689
30190
|
{
|
|
29690
30191
|
version: 1,
|
|
@@ -29773,6 +30274,14 @@ var SYSTEM_MIGRATIONS = [
|
|
|
29773
30274
|
version: STORAGE_SUBQUERIES_VERSION,
|
|
29774
30275
|
name: STORAGE_SUBQUERIES_NAME,
|
|
29775
30276
|
statements: []
|
|
30277
|
+
},
|
|
30278
|
+
{
|
|
30279
|
+
// Realtime 3-2b (original spec §9.1, design §7.1): the tables whose
|
|
30280
|
+
// Data API writes reach the hub. Empty until the publish API (3-2c)
|
|
30281
|
+
// writes it. A worker from before it never reads it.
|
|
30282
|
+
version: REALTIME_TABLES_VERSION,
|
|
30283
|
+
name: "realtime",
|
|
30284
|
+
statements: [REALTIME_TABLES_SQL]
|
|
29776
30285
|
}
|
|
29777
30286
|
];
|
|
29778
30287
|
|
|
@@ -29972,6 +30481,10 @@ var ENTERPRISE_REALTIME_LIMITS = Object.freeze({
|
|
|
29972
30481
|
restRequestsPerSecond: 100
|
|
29973
30482
|
});
|
|
29974
30483
|
|
|
30484
|
+
// ../../packages/data-core/src/realtime-changes.ts
|
|
30485
|
+
var CHANGE_TYPES = Object.freeze({ insert: "INSERT", update: "UPDATE", delete: "DELETE" });
|
|
30486
|
+
var CHANGE_EVENT_CODES = Object.freeze({ "*": 0, INSERT: 1, UPDATE: 2, DELETE: 3 });
|
|
30487
|
+
|
|
29975
30488
|
// ../../packages/data-core/src/redirect-origins.ts
|
|
29976
30489
|
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
|
|
29977
30490
|
"localhost",
|
|
@@ -31847,11 +32360,11 @@ export {
|
|
|
31847
32360
|
summarizeStatement,
|
|
31848
32361
|
parseDotenvDetailed,
|
|
31849
32362
|
serializeDotenv,
|
|
32363
|
+
systemTablePredicate,
|
|
31850
32364
|
MAX_SINGLE_UPLOAD_BYTES,
|
|
31851
32365
|
checkObjectName,
|
|
31852
32366
|
parseCacheControl,
|
|
31853
32367
|
STORAGE_OBJECTS_TABLE,
|
|
31854
|
-
systemTablePredicate,
|
|
31855
32368
|
dataError,
|
|
31856
32369
|
SCHEMA_SQL,
|
|
31857
32370
|
tableNames,
|