@syncular/server 0.15.32 → 0.15.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +11 -15
- package/package.json +2 -2
- package/src/schema.ts +13 -21
package/dist/schema.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* §2.4 column types, scope patterns per §3.1, and a schema version. Codegen
|
|
6
6
|
* (B5) will emit this shape later; tests hand-write it.
|
|
7
7
|
*/
|
|
8
|
-
import type
|
|
8
|
+
import { type RowColumn } from '@syncular/core';
|
|
9
9
|
/** `'prefix:{variable}'` shorthand (column name = variable) or explicit. */
|
|
10
10
|
export type ScopePatternSpec = string | {
|
|
11
11
|
pattern: string;
|
package/dist/schema.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server schema IR (SPEC.md §2.4, §3.1).
|
|
3
|
+
*
|
|
4
|
+
* The server is configured with a schema IR: tables, columns with the six
|
|
5
|
+
* §2.4 column types, scope patterns per §3.1, and a schema version. Codegen
|
|
6
|
+
* (B5) will emit this shape later; tests hand-write it.
|
|
7
|
+
*/
|
|
8
|
+
import { validatePortableRelationalIdentifier, } from '@syncular/core';
|
|
1
9
|
const PATTERN_RE = /^([^{}]+):\{([^{}:]+)\}$/;
|
|
2
10
|
/**
|
|
3
11
|
* Identifier rules for relational server storage (DESIGN "current-row
|
|
@@ -6,18 +14,6 @@ const PATTERN_RE = /^([^{}]+):\{([^{}:]+)\}$/;
|
|
|
6
14
|
* both prefixes are reserved; identifiers over 63 bytes would be silently
|
|
7
15
|
* truncated by Postgres.
|
|
8
16
|
*/
|
|
9
|
-
function validateIdentifier(kind, name) {
|
|
10
|
-
if (name.length === 0) {
|
|
11
|
-
throw new Error(`${kind} name must not be empty`);
|
|
12
|
-
}
|
|
13
|
-
const lower = name.toLowerCase();
|
|
14
|
-
if (lower.startsWith('sync_') || lower.startsWith('_sync')) {
|
|
15
|
-
throw new Error(`${kind} name ${JSON.stringify(name)} uses a reserved prefix (sync_/_sync are the server storage namespace)`);
|
|
16
|
-
}
|
|
17
|
-
if (new TextEncoder().encode(name).length > 63) {
|
|
18
|
-
throw new Error(`${kind} name ${JSON.stringify(name)} exceeds 63 bytes (Postgres identifier limit)`);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
17
|
function compilePattern(table, spec, columnIndex) {
|
|
22
18
|
const pattern = typeof spec === 'string' ? spec : spec.pattern;
|
|
23
19
|
const match = PATTERN_RE.exec(pattern);
|
|
@@ -44,19 +40,19 @@ export function compileSchema(schema) {
|
|
|
44
40
|
if (tables.has(table.name)) {
|
|
45
41
|
throw new Error(`duplicate table ${JSON.stringify(table.name)}`);
|
|
46
42
|
}
|
|
47
|
-
|
|
43
|
+
validatePortableRelationalIdentifier('table', table.name);
|
|
48
44
|
const columnIndex = new Map();
|
|
49
45
|
table.columns.forEach((column, index) => {
|
|
50
46
|
if (columnIndex.has(column.name)) {
|
|
51
47
|
throw new Error(`table ${table.name}: duplicate column ${JSON.stringify(column.name)}`);
|
|
52
48
|
}
|
|
53
|
-
|
|
49
|
+
validatePortableRelationalIdentifier(`table ${table.name}: column`, column.name);
|
|
54
50
|
columnIndex.set(column.name, index);
|
|
55
51
|
});
|
|
56
52
|
const indexes = table.indexes ?? [];
|
|
57
53
|
const indexNames = new Set();
|
|
58
54
|
for (const index of indexes) {
|
|
59
|
-
|
|
55
|
+
validatePortableRelationalIdentifier(`table ${table.name}: index`, index.name);
|
|
60
56
|
if (indexNames.has(index.name)) {
|
|
61
57
|
throw new Error(`table ${table.name}: duplicate index ${JSON.stringify(index.name)}`);
|
|
62
58
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/server",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.34",
|
|
4
4
|
"description": "Syncular server: handleSyncRequest + storage/auth interfaces for the sync protocol",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"!dist/**/*.test.d.ts"
|
|
54
54
|
],
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@syncular/core": "0.15.
|
|
56
|
+
"@syncular/core": "0.15.34"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@electric-sql/pglite": "^0.5.4"
|
package/src/schema.ts
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* §2.4 column types, scope patterns per §3.1, and a schema version. Codegen
|
|
6
6
|
* (B5) will emit this shape later; tests hand-write it.
|
|
7
7
|
*/
|
|
8
|
-
import
|
|
8
|
+
import {
|
|
9
|
+
type RowColumn,
|
|
10
|
+
validatePortableRelationalIdentifier,
|
|
11
|
+
} from '@syncular/core';
|
|
9
12
|
|
|
10
13
|
/** `'prefix:{variable}'` shorthand (column name = variable) or explicit. */
|
|
11
14
|
export type ScopePatternSpec = string | { pattern: string; column: string };
|
|
@@ -107,23 +110,6 @@ const PATTERN_RE = /^([^{}]+):\{([^{}:]+)\}$/;
|
|
|
107
110
|
* both prefixes are reserved; identifiers over 63 bytes would be silently
|
|
108
111
|
* truncated by Postgres.
|
|
109
112
|
*/
|
|
110
|
-
function validateIdentifier(kind: string, name: string): void {
|
|
111
|
-
if (name.length === 0) {
|
|
112
|
-
throw new Error(`${kind} name must not be empty`);
|
|
113
|
-
}
|
|
114
|
-
const lower = name.toLowerCase();
|
|
115
|
-
if (lower.startsWith('sync_') || lower.startsWith('_sync')) {
|
|
116
|
-
throw new Error(
|
|
117
|
-
`${kind} name ${JSON.stringify(name)} uses a reserved prefix (sync_/_sync are the server storage namespace)`,
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
if (new TextEncoder().encode(name).length > 63) {
|
|
121
|
-
throw new Error(
|
|
122
|
-
`${kind} name ${JSON.stringify(name)} exceeds 63 bytes (Postgres identifier limit)`,
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
113
|
function compilePattern(
|
|
128
114
|
table: TableSchema,
|
|
129
115
|
spec: ScopePatternSpec,
|
|
@@ -159,7 +145,7 @@ export function compileSchema(schema: ServerSchema): CompiledSchema {
|
|
|
159
145
|
if (tables.has(table.name)) {
|
|
160
146
|
throw new Error(`duplicate table ${JSON.stringify(table.name)}`);
|
|
161
147
|
}
|
|
162
|
-
|
|
148
|
+
validatePortableRelationalIdentifier('table', table.name);
|
|
163
149
|
const columnIndex = new Map<string, number>();
|
|
164
150
|
table.columns.forEach((column, index) => {
|
|
165
151
|
if (columnIndex.has(column.name)) {
|
|
@@ -167,13 +153,19 @@ export function compileSchema(schema: ServerSchema): CompiledSchema {
|
|
|
167
153
|
`table ${table.name}: duplicate column ${JSON.stringify(column.name)}`,
|
|
168
154
|
);
|
|
169
155
|
}
|
|
170
|
-
|
|
156
|
+
validatePortableRelationalIdentifier(
|
|
157
|
+
`table ${table.name}: column`,
|
|
158
|
+
column.name,
|
|
159
|
+
);
|
|
171
160
|
columnIndex.set(column.name, index);
|
|
172
161
|
});
|
|
173
162
|
const indexes = table.indexes ?? [];
|
|
174
163
|
const indexNames = new Set<string>();
|
|
175
164
|
for (const index of indexes) {
|
|
176
|
-
|
|
165
|
+
validatePortableRelationalIdentifier(
|
|
166
|
+
`table ${table.name}: index`,
|
|
167
|
+
index.name,
|
|
168
|
+
);
|
|
177
169
|
if (indexNames.has(index.name)) {
|
|
178
170
|
throw new Error(
|
|
179
171
|
`table ${table.name}: duplicate index ${JSON.stringify(index.name)}`,
|