@syncular/server 0.15.33 → 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 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 { RowColumn } from '@syncular/core';
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
- validateIdentifier('table', table.name);
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
- validateIdentifier(`table ${table.name}: column`, column.name);
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
- validateIdentifier(`table ${table.name}: index`, index.name);
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.33",
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.33"
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 type { RowColumn } from '@syncular/core';
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
- validateIdentifier('table', table.name);
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
- validateIdentifier(`table ${table.name}: column`, column.name);
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
- validateIdentifier(`table ${table.name}: index`, index.name);
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)}`,