@dxos/echo-protocol 0.8.4-main.fd6878d → 0.8.4-staging.60fe92afc8
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/LICENSE +102 -5
- package/README.md +1 -1
- package/dist/lib/neutral/index.mjs +721 -0
- package/dist/lib/neutral/index.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/types/src/document-structure.d.ts +85 -30
- package/dist/types/src/document-structure.d.ts.map +1 -1
- package/dist/types/src/echo-feed-codec.d.ts +17 -0
- package/dist/types/src/echo-feed-codec.d.ts.map +1 -0
- package/dist/types/src/edge-peer.d.ts +11 -0
- package/dist/types/src/edge-peer.d.ts.map +1 -0
- package/dist/types/src/foreign-key.d.ts +1 -1
- package/dist/types/src/foreign-key.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +5 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/query/ast.d.ts +290 -28
- package/dist/types/src/query/ast.d.ts.map +1 -1
- package/dist/types/src/reference.d.ts +11 -64
- package/dist/types/src/reference.d.ts.map +1 -1
- package/dist/types/src/space-id.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -15
- package/src/document-structure.ts +106 -33
- package/src/echo-feed-codec.ts +67 -0
- package/src/edge-peer.ts +27 -0
- package/src/foreign-key.ts +4 -3
- package/src/index.ts +5 -3
- package/src/query/ast.ts +353 -38
- package/src/reference.ts +13 -158
- package/dist/lib/browser/index.mjs +0 -526
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/node-esm/index.mjs +0 -527
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
package/package.json
CHANGED
|
@@ -1,37 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/echo-protocol",
|
|
3
|
-
"version": "0.8.4-
|
|
3
|
+
"version": "0.8.4-staging.60fe92afc8",
|
|
4
4
|
"description": "Core ECHO APIs.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
-
"repository":
|
|
8
|
-
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dxos/dxos"
|
|
10
|
+
},
|
|
11
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
9
12
|
"author": "DXOS.org",
|
|
10
|
-
"sideEffects":
|
|
13
|
+
"sideEffects": false,
|
|
11
14
|
"type": "module",
|
|
12
15
|
"exports": {
|
|
13
16
|
".": {
|
|
14
17
|
"source": "./src/index.ts",
|
|
15
18
|
"types": "./dist/types/src/index.d.ts",
|
|
16
|
-
"
|
|
17
|
-
"node": "./dist/lib/node-esm/index.mjs"
|
|
19
|
+
"default": "./dist/lib/neutral/index.mjs"
|
|
18
20
|
}
|
|
19
21
|
},
|
|
20
22
|
"types": "dist/types/src/index.d.ts",
|
|
21
|
-
"typesVersions": {
|
|
22
|
-
"*": {}
|
|
23
|
-
},
|
|
24
23
|
"files": [
|
|
25
24
|
"dist",
|
|
26
25
|
"src"
|
|
27
26
|
],
|
|
28
27
|
"dependencies": {
|
|
29
|
-
"effect": "3.
|
|
30
|
-
"@dxos/crypto": "0.8.4-
|
|
31
|
-
"@dxos/
|
|
32
|
-
"@dxos/
|
|
33
|
-
"@dxos/
|
|
34
|
-
"@dxos/
|
|
28
|
+
"effect": "3.21.3",
|
|
29
|
+
"@dxos/crypto": "0.8.4-staging.60fe92afc8",
|
|
30
|
+
"@dxos/invariant": "0.8.4-staging.60fe92afc8",
|
|
31
|
+
"@dxos/keys": "0.8.4-staging.60fe92afc8",
|
|
32
|
+
"@dxos/protocols": "0.8.4-staging.60fe92afc8",
|
|
33
|
+
"@dxos/util": "0.8.4-staging.60fe92afc8"
|
|
35
34
|
},
|
|
36
35
|
"publishConfig": {
|
|
37
36
|
"access": "public"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { invariant } from '@dxos/invariant';
|
|
6
|
-
import type {
|
|
6
|
+
import type { EntityId, URI } from '@dxos/keys';
|
|
7
7
|
import { visitValues } from '@dxos/util';
|
|
8
8
|
|
|
9
9
|
import { type RawString } from './automerge';
|
|
@@ -19,8 +19,8 @@ export type SpaceState = {
|
|
|
19
19
|
/**
|
|
20
20
|
* Array indexes get converted to strings.
|
|
21
21
|
*/
|
|
22
|
-
export type
|
|
23
|
-
export type
|
|
22
|
+
export type EntityProp = string;
|
|
23
|
+
export type EntityPropPath = EntityProp[];
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Link to all documents that hold objects in the space.
|
|
@@ -35,13 +35,13 @@ export interface DatabaseDirectory {
|
|
|
35
35
|
* Objects inlined in the current document.
|
|
36
36
|
*/
|
|
37
37
|
objects?: {
|
|
38
|
-
[id: string]:
|
|
38
|
+
[id: string]: EntityStructure;
|
|
39
39
|
};
|
|
40
40
|
/**
|
|
41
41
|
* Object id points to an automerge doc url where the object is embedded.
|
|
42
42
|
*/
|
|
43
43
|
links?: {
|
|
44
|
-
[
|
|
44
|
+
[echoUri: string]: string | RawString;
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -67,11 +67,11 @@ export const DatabaseDirectory = Object.freeze({
|
|
|
67
67
|
return rawKey;
|
|
68
68
|
},
|
|
69
69
|
|
|
70
|
-
getInlineObject: (doc: DatabaseDirectory, id:
|
|
70
|
+
getInlineObject: (doc: DatabaseDirectory, id: EntityId): EntityStructure | undefined => {
|
|
71
71
|
return doc.objects?.[id];
|
|
72
72
|
},
|
|
73
73
|
|
|
74
|
-
getLink: (doc: DatabaseDirectory, id:
|
|
74
|
+
getLink: (doc: DatabaseDirectory, id: EntityId): string | undefined => {
|
|
75
75
|
return doc.links?.[id]?.toString();
|
|
76
76
|
},
|
|
77
77
|
|
|
@@ -81,7 +81,7 @@ export const DatabaseDirectory = Object.freeze({
|
|
|
81
81
|
links,
|
|
82
82
|
}: {
|
|
83
83
|
spaceKey: string;
|
|
84
|
-
objects?: Record<string,
|
|
84
|
+
objects?: Record<string, EntityStructure>;
|
|
85
85
|
links?: Record<string, RawString>;
|
|
86
86
|
}): DatabaseDirectory => ({
|
|
87
87
|
access: {
|
|
@@ -95,11 +95,11 @@ export const DatabaseDirectory = Object.freeze({
|
|
|
95
95
|
/**
|
|
96
96
|
* Representation of an ECHO object in an AM document.
|
|
97
97
|
*/
|
|
98
|
-
export type
|
|
98
|
+
export type EntityStructure = {
|
|
99
99
|
// TODO(dmaretskyi): Missing in some cases.
|
|
100
|
-
system?:
|
|
100
|
+
system?: EntitySystem;
|
|
101
101
|
|
|
102
|
-
meta:
|
|
102
|
+
meta: EntityMeta;
|
|
103
103
|
/**
|
|
104
104
|
* User-defined data.
|
|
105
105
|
* Adheres to schema in `system.type`
|
|
@@ -107,42 +107,46 @@ export type ObjectStructure = {
|
|
|
107
107
|
data: Record<string, any>;
|
|
108
108
|
};
|
|
109
109
|
|
|
110
|
-
// Helper methods to interact with the {@link
|
|
111
|
-
export const
|
|
110
|
+
// Helper methods to interact with the {@link EntityStructure}.
|
|
111
|
+
export const EntityStructure = Object.freeze({
|
|
112
112
|
/**
|
|
113
113
|
* @throws On invalid object structure.
|
|
114
114
|
*/
|
|
115
|
-
getTypeReference: (object:
|
|
115
|
+
getTypeReference: (object: EntityStructure): EncodedReference | undefined => {
|
|
116
116
|
return object.system?.type;
|
|
117
117
|
},
|
|
118
118
|
|
|
119
119
|
/**
|
|
120
120
|
* @throws On invalid object structure.
|
|
121
121
|
*/
|
|
122
|
-
getEntityKind: (object:
|
|
122
|
+
getEntityKind: (object: EntityStructure): 'object' | 'relation' | 'type' => {
|
|
123
123
|
const kind = object.system?.kind ?? 'object';
|
|
124
|
-
invariant(kind === 'object' || kind === 'relation', 'Invalid kind');
|
|
124
|
+
invariant(kind === 'object' || kind === 'relation' || kind === 'type', 'Invalid kind');
|
|
125
125
|
return kind;
|
|
126
126
|
},
|
|
127
127
|
|
|
128
|
-
isDeleted: (object:
|
|
128
|
+
isDeleted: (object: EntityStructure): boolean => {
|
|
129
129
|
return object.system?.deleted ?? false;
|
|
130
130
|
},
|
|
131
131
|
|
|
132
|
-
getRelationSource: (object:
|
|
132
|
+
getRelationSource: (object: EntityStructure): EncodedReference | undefined => {
|
|
133
133
|
return object.system?.source;
|
|
134
134
|
},
|
|
135
135
|
|
|
136
|
-
getRelationTarget: (object:
|
|
136
|
+
getRelationTarget: (object: EntityStructure): EncodedReference | undefined => {
|
|
137
137
|
return object.system?.target;
|
|
138
138
|
},
|
|
139
139
|
|
|
140
|
+
getParent: (object: EntityStructure): EncodedReference | undefined => {
|
|
141
|
+
return object.system?.parent;
|
|
142
|
+
},
|
|
143
|
+
|
|
140
144
|
/**
|
|
141
145
|
* @returns All references in the data section of the object.
|
|
142
146
|
*/
|
|
143
|
-
getAllOutgoingReferences: (object:
|
|
144
|
-
const references: { path:
|
|
145
|
-
const visit = (path:
|
|
147
|
+
getAllOutgoingReferences: (object: EntityStructure): { path: EntityPropPath; reference: EncodedReference }[] => {
|
|
148
|
+
const references: { path: EntityPropPath; reference: EncodedReference }[] = [];
|
|
149
|
+
const visit = (path: EntityPropPath, value: unknown) => {
|
|
146
150
|
if (isEncodedReference(value)) {
|
|
147
151
|
references.push({ path, reference: value });
|
|
148
152
|
} else {
|
|
@@ -153,16 +157,20 @@ export const ObjectStructure = Object.freeze({
|
|
|
153
157
|
return references;
|
|
154
158
|
},
|
|
155
159
|
|
|
160
|
+
getTags: (object: EntityStructure): (EncodedReference | string)[] => {
|
|
161
|
+
return object.meta.tags ?? [];
|
|
162
|
+
},
|
|
163
|
+
|
|
156
164
|
makeObject: ({
|
|
157
165
|
type,
|
|
158
166
|
data,
|
|
159
167
|
keys,
|
|
160
168
|
}: {
|
|
161
|
-
type:
|
|
169
|
+
type: URI.URI;
|
|
162
170
|
deleted?: boolean;
|
|
163
171
|
keys?: ForeignKey[];
|
|
164
172
|
data?: unknown;
|
|
165
|
-
}):
|
|
173
|
+
}): EntityStructure => {
|
|
166
174
|
return {
|
|
167
175
|
system: {
|
|
168
176
|
kind: 'object',
|
|
@@ -183,13 +191,13 @@ export const ObjectStructure = Object.freeze({
|
|
|
183
191
|
keys,
|
|
184
192
|
data,
|
|
185
193
|
}: {
|
|
186
|
-
type:
|
|
194
|
+
type: URI.URI;
|
|
187
195
|
source: EncodedReference;
|
|
188
196
|
target: EncodedReference;
|
|
189
197
|
deleted?: boolean;
|
|
190
198
|
keys?: ForeignKey[];
|
|
191
199
|
data?: unknown;
|
|
192
|
-
}):
|
|
200
|
+
}): EntityStructure => {
|
|
193
201
|
return {
|
|
194
202
|
system: {
|
|
195
203
|
kind: 'relation',
|
|
@@ -204,30 +212,82 @@ export const ObjectStructure = Object.freeze({
|
|
|
204
212
|
data: data ?? {},
|
|
205
213
|
};
|
|
206
214
|
},
|
|
215
|
+
|
|
216
|
+
makeType: ({ type, keys, data }: { type: URI.URI; keys?: ForeignKey[]; data?: unknown }): EntityStructure => {
|
|
217
|
+
return {
|
|
218
|
+
system: {
|
|
219
|
+
kind: 'type',
|
|
220
|
+
type: { '/': type },
|
|
221
|
+
},
|
|
222
|
+
meta: {
|
|
223
|
+
keys: keys ?? [],
|
|
224
|
+
},
|
|
225
|
+
data: data ?? {},
|
|
226
|
+
};
|
|
227
|
+
},
|
|
207
228
|
});
|
|
208
229
|
|
|
209
230
|
/**
|
|
210
231
|
* Echo object metadata.
|
|
211
232
|
*/
|
|
212
|
-
export type
|
|
233
|
+
export type EntityMeta = {
|
|
213
234
|
/**
|
|
214
235
|
* Foreign keys.
|
|
215
236
|
*/
|
|
216
237
|
keys: ForeignKey[];
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Tags.
|
|
241
|
+
* Encoded references to Tag objects within the space.
|
|
242
|
+
*
|
|
243
|
+
* NOTE: Optional for backwards compatibility; legacy data may store bare DXN strings, which are
|
|
244
|
+
* upgraded to encoded references on read (see `object-core.ts`).
|
|
245
|
+
*/
|
|
246
|
+
tags?: (EncodedReference | string)[];
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Fully-qualified registry key for the object (FQN format, e.g. `org.example.type.foo`).
|
|
250
|
+
* Identifies the canonical registry entry the object instance was created from.
|
|
251
|
+
*/
|
|
252
|
+
key?: string;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Semantic version of the registry entry the object was created from.
|
|
256
|
+
* Must be a valid semver string (e.g. `1.2.3`).
|
|
257
|
+
*/
|
|
258
|
+
version?: string;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Dictionary of annotations to this entity.
|
|
262
|
+
*
|
|
263
|
+
* NOTE: Optional for backwards compatibility. Values are arbitrary decoded automerge primitives;
|
|
264
|
+
* typed as `any` so `EntityStructure` stays assignable to `DecodedAutomergePrimaryValue`.
|
|
265
|
+
*/
|
|
266
|
+
annotations?: { readonly [key: string]: any };
|
|
217
267
|
};
|
|
218
268
|
|
|
219
269
|
/**
|
|
220
270
|
* Automerge object system properties.
|
|
221
271
|
* (Is automerge specific.)
|
|
222
272
|
*/
|
|
223
|
-
export type
|
|
273
|
+
export type EntitySystem = {
|
|
224
274
|
/**
|
|
225
|
-
* Entity kind.
|
|
275
|
+
* Entity kind. `'type'` covers persisted ECHO type definitions (instances of
|
|
276
|
+
* the `Type.Type` meta-schema); `'object'` / `'relation'` cover regular ECHO
|
|
277
|
+
* instances.
|
|
226
278
|
*/
|
|
227
|
-
kind?: 'object' | 'relation';
|
|
279
|
+
kind?: 'object' | 'relation' | 'type';
|
|
228
280
|
|
|
229
281
|
/**
|
|
230
|
-
* Object reference ('protobuf' protocol) type
|
|
282
|
+
* Object reference ('protobuf' protocol) type — DXN of the schema this
|
|
283
|
+
* entity instantiates.
|
|
284
|
+
*
|
|
285
|
+
* - For `kind === 'object'` / `'relation'` instances, this is the URI of the
|
|
286
|
+
* user-defined schema the entity was created from (e.g. `dxn:org.example.Person:1.0.0`).
|
|
287
|
+
* - For `kind === 'type'` entities (persisted Type.Type meta-instances) this
|
|
288
|
+
* is always the URI of the `TypeSchema` meta-schema itself
|
|
289
|
+
* (`dxn:org.dxos.type.schema:0.1.0`). The kind that the meta-instance
|
|
290
|
+
* _describes_ (object/relation/type) lives in `data.jsonSchema.entityKind`.
|
|
231
291
|
*/
|
|
232
292
|
type?: EncodedReference;
|
|
233
293
|
|
|
@@ -236,15 +296,28 @@ export type ObjectSystem = {
|
|
|
236
296
|
*/
|
|
237
297
|
deleted?: boolean;
|
|
238
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Object parent.
|
|
301
|
+
* Objects with no parent are at the top level of the object hierarchy in the space.
|
|
302
|
+
*/
|
|
303
|
+
parent?: EncodedReference;
|
|
304
|
+
|
|
239
305
|
/**
|
|
240
306
|
* Only for relations.
|
|
241
307
|
*/
|
|
242
308
|
source?: EncodedReference;
|
|
243
309
|
|
|
244
310
|
/**
|
|
245
|
-
* Only for relations.
|
|
311
|
+
* Only for relations.
|
|
246
312
|
*/
|
|
247
313
|
target?: EncodedReference;
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Unix ms timestamp recorded at object creation time.
|
|
317
|
+
* Set once when the ObjectStructure is first written; never modified after that.
|
|
318
|
+
* Survives compaction / migrations (unlike automerge change timestamps).
|
|
319
|
+
*/
|
|
320
|
+
createdAt?: number;
|
|
248
321
|
};
|
|
249
322
|
|
|
250
323
|
/**
|
|
@@ -254,6 +327,6 @@ export const PROPERTY_ID = 'id';
|
|
|
254
327
|
|
|
255
328
|
/**
|
|
256
329
|
* Data namespace.
|
|
257
|
-
* The key on {@link
|
|
330
|
+
* The key on {@link EntityStructure} that contains the user-defined data.
|
|
258
331
|
*/
|
|
259
332
|
export const DATA_NAMESPACE = 'data';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { FeedProtocol } from '@dxos/protocols';
|
|
6
|
+
|
|
7
|
+
import type { ForeignKey } from './foreign-key';
|
|
8
|
+
|
|
9
|
+
/** Property name for meta when object is serialized to JSON. Matches @dxos/echo/internal ATTR_META. */
|
|
10
|
+
const ATTR_META = '@meta';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Codec for ECHO objects in feed block payload: JSON object ↔ UTF-8 bytes.
|
|
14
|
+
* Encodes with queue position stripped; decodes with optional position injection.
|
|
15
|
+
*/
|
|
16
|
+
export class EchoFeedCodec {
|
|
17
|
+
static readonly #encoder = new TextEncoder();
|
|
18
|
+
static readonly #decoder = new TextDecoder();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Prepares a value for feed storage (strips queue position from metadata) and encodes to bytes.
|
|
22
|
+
*/
|
|
23
|
+
static encode(value: Record<string, unknown>): Uint8Array {
|
|
24
|
+
const prepared = EchoFeedCodec.#stripQueuePosition(value);
|
|
25
|
+
return EchoFeedCodec.#encoder.encode(JSON.stringify(prepared));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Decodes feed block bytes to a JSON value.
|
|
30
|
+
* If position is provided, injects queue position into the decoded object's metadata.
|
|
31
|
+
*/
|
|
32
|
+
static decode(data: Uint8Array, position?: number): Record<string, unknown> {
|
|
33
|
+
const decoded = JSON.parse(EchoFeedCodec.#decoder.decode(data));
|
|
34
|
+
if (position !== undefined && typeof decoded === 'object' && decoded !== null) {
|
|
35
|
+
EchoFeedCodec.#setQueuePosition(decoded, position);
|
|
36
|
+
}
|
|
37
|
+
return decoded;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static #stripQueuePosition(value: Record<string, unknown>): Record<string, unknown> {
|
|
41
|
+
if (typeof value !== 'object' || value === null) {
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
const obj = structuredClone(value);
|
|
45
|
+
const meta = obj[ATTR_META] as { keys?: ForeignKey[] } | undefined;
|
|
46
|
+
if (meta?.keys?.some((key: ForeignKey) => key.source === FeedProtocol.KEY_QUEUE_POSITION)) {
|
|
47
|
+
meta.keys = meta.keys.filter((key: ForeignKey) => key.source !== FeedProtocol.KEY_QUEUE_POSITION);
|
|
48
|
+
}
|
|
49
|
+
return obj;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static #setQueuePosition(obj: Record<string, any>, position: number): void {
|
|
53
|
+
obj[ATTR_META] ??= { keys: [] };
|
|
54
|
+
obj[ATTR_META]!.keys ??= [];
|
|
55
|
+
const keys = obj[ATTR_META]!.keys!;
|
|
56
|
+
for (let i = 0; i < keys.length; i++) {
|
|
57
|
+
if (keys[i].source === FeedProtocol.KEY_QUEUE_POSITION) {
|
|
58
|
+
keys.splice(i, 1);
|
|
59
|
+
i--;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
keys.push({
|
|
63
|
+
source: FeedProtocol.KEY_QUEUE_POSITION,
|
|
64
|
+
id: position.toString(),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
package/src/edge-peer.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type SpaceId } from '@dxos/keys';
|
|
6
|
+
import { EdgeService } from '@dxos/protocols';
|
|
7
|
+
import { compositeKey } from '@dxos/util';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns true if the given peerId belongs to an EDGE replicator (Automerge or Subduction).
|
|
11
|
+
*
|
|
12
|
+
* When `spaceId` is provided, the match is scoped to that space (peerId must start with
|
|
13
|
+
* `<service>:<spaceId>`). When omitted, only the leading service segment is checked
|
|
14
|
+
* (peerId must start with `<service>:`), which is useful when the caller doesn't have a
|
|
15
|
+
* spaceId on hand or wants to match any edge replicator regardless of space.
|
|
16
|
+
*/
|
|
17
|
+
export const isEdgePeerId = (peerId: string, spaceId?: SpaceId): boolean => {
|
|
18
|
+
const automergePrefix =
|
|
19
|
+
spaceId !== undefined
|
|
20
|
+
? compositeKey(EdgeService.AUTOMERGE_REPLICATOR, spaceId)
|
|
21
|
+
: `${EdgeService.AUTOMERGE_REPLICATOR}:`;
|
|
22
|
+
const subductionPrefix =
|
|
23
|
+
spaceId !== undefined
|
|
24
|
+
? compositeKey(EdgeService.SUBDUCTION_REPLICATOR, spaceId)
|
|
25
|
+
: `${EdgeService.SUBDUCTION_REPLICATOR}:`;
|
|
26
|
+
return peerId.startsWith(automergePrefix) || peerId.startsWith(subductionPrefix);
|
|
27
|
+
};
|
package/src/foreign-key.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Schema from 'effect/Schema';
|
|
6
|
+
import * as SchemaAST from 'effect/SchemaAST';
|
|
6
7
|
|
|
7
8
|
const ForeignKey_ = Schema.Struct({
|
|
8
9
|
/**
|
|
@@ -15,8 +16,8 @@ const ForeignKey_ = Schema.Struct({
|
|
|
15
16
|
* Id within the foreign database.
|
|
16
17
|
*/
|
|
17
18
|
// TODO(wittjosiah): This annotation is currently used to ensure id field shows up in forms.
|
|
18
|
-
// TODO(dmaretskyi): `false` is not a valid value for the annotation.
|
|
19
|
-
id: Schema.String.annotations({ [SchemaAST.IdentifierAnnotationId]: false }),
|
|
19
|
+
// TODO(dmaretskyi): `false` is not a valid value for the annotation. Use a different annotation.
|
|
20
|
+
id: Schema.String.annotations({ [SchemaAST.IdentifierAnnotationId]: 'false' }),
|
|
20
21
|
});
|
|
21
22
|
|
|
22
23
|
export type ForeignKey = Schema.Schema.Type<typeof ForeignKey_>;
|
package/src/index.ts
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
export type * from './collection-sync';
|
|
5
6
|
export * from './document-structure';
|
|
7
|
+
export * from './edge-peer';
|
|
8
|
+
export * from './echo-feed-codec';
|
|
9
|
+
export * from './foreign-key';
|
|
10
|
+
export * from './query';
|
|
6
11
|
export * from './reference';
|
|
7
12
|
export * from './space-doc-version';
|
|
8
|
-
export type * from './collection-sync';
|
|
9
13
|
export * from './space-id';
|
|
10
|
-
export * from './foreign-key';
|
|
11
|
-
export * from './query';
|