@kubun/connector 0.9.0 → 0.11.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/lib/cluster-utils.d.ts +9 -0
- package/lib/cluster-utils.js +32 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.js +3 -1
- package/lib/models/cluster.js +11 -1
- package/lib/models/external-entity.js +53 -1
- package/lib/types.d.ts +11 -0
- package/lib/types.js +1 -1
- package/package.json +4 -4
package/lib/cluster-utils.d.ts
CHANGED
|
@@ -4,3 +4,12 @@ import type { ClustersRecord } from '@kubun/protocol';
|
|
|
4
4
|
* Use this in providers to tag EntityBatch.modelID at module level.
|
|
5
5
|
*/
|
|
6
6
|
export declare function resolveModelID(clusters: ClustersRecord, modelName: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Resolve the deduped `urn:kubun:model:<modelID>` for every model a set of
|
|
9
|
+
* clusters writes. A cluster's `record` holds exactly the concrete models it
|
|
10
|
+
* imports (interface models such as ExternalEntity are referenced but are not
|
|
11
|
+
* record members), so its keys are the content-addressed model IDs to scope a
|
|
12
|
+
* write capability to. Shared by both the client that mints a viewer→server
|
|
13
|
+
* grant and the server that revokes it, so the two derive the identical set.
|
|
14
|
+
*/
|
|
15
|
+
export declare function clusterModelURNs(clusters: ClustersRecord): Array<string>;
|
package/lib/cluster-utils.js
CHANGED
|
@@ -1 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a model name to its content-addressed model ID across clusters.
|
|
3
|
+
* Use this in providers to tag EntityBatch.modelID at module level.
|
|
4
|
+
*/ export function resolveModelID(clusters, modelName) {
|
|
5
|
+
for (const cluster of Object.values(clusters)){
|
|
6
|
+
const modelIndex = cluster.models.findIndex((m)=>m.name === modelName);
|
|
7
|
+
if (modelIndex === -1) continue;
|
|
8
|
+
for (const [id, index] of Object.entries(cluster.record)){
|
|
9
|
+
if (index === modelIndex) return id;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
throw new Error(`Model "${modelName}" not found in any cluster`);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the deduped `urn:kubun:model:<modelID>` for every model a set of
|
|
16
|
+
* clusters writes. A cluster's `record` holds exactly the concrete models it
|
|
17
|
+
* imports (interface models such as ExternalEntity are referenced but are not
|
|
18
|
+
* record members), so its keys are the content-addressed model IDs to scope a
|
|
19
|
+
* write capability to. Shared by both the client that mints a viewer→server
|
|
20
|
+
* grant and the server that revokes it, so the two derive the identical set.
|
|
21
|
+
*/ export function clusterModelURNs(clusters) {
|
|
22
|
+
const urns = [];
|
|
23
|
+
for (const cluster of Object.values(clusters)){
|
|
24
|
+
for (const modelID of Object.keys(cluster.record)){
|
|
25
|
+
const urn = `urn:kubun:model:${modelID}`;
|
|
26
|
+
if (!urns.includes(urn)) {
|
|
27
|
+
urns.push(urn);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return urns;
|
|
32
|
+
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { resolveModelID } from './cluster-utils.js';
|
|
1
|
+
export { clusterModelURNs, resolveModelID } from './cluster-utils.js';
|
|
2
2
|
export { connectorClusters, connectorModelIDs } from './models/cluster.js';
|
|
3
3
|
export { externalEntityDefinition } from './models/external-entity.js';
|
|
4
|
-
export type { ActionDefinition, ActionHandler, ActionHandlerFactory, ActionResult, ClientDataProvider, ClientProviderFactory, ConnectorAuth, ConnectorDefinition, ConnectorSyncEventPayload, Credential, CredentialProvider, DataProvider, DeviceConnectorAuth, DevicePermission, EntityBatch, EntityRecord, FetchChangesParams, FetchParams, OAuthConnectorAuth, OAuthProviderDefinition, OAuthState, ServerDataProvider, ServerProviderFactory, SyncBoundary, SyncCompleteEvent, SyncErrorEvent, SyncEvent, SyncProgressEvent, SyncState, SyncStateEntry, SyncStateStore, SyncStatus, TokenResponse, UserSyncPreferences, WebhookParams, WebhookRegistration, } from './types.js';
|
|
4
|
+
export type { ActionDefinition, ActionHandler, ActionHandlerFactory, ActionResult, ClientDataProvider, ClientProviderFactory, ConnectorAuth, ConnectorDefinition, ConnectorSyncEventPayload, Credential, CredentialProvider, DataProvider, DeviceConnectorAuth, DevicePermission, EntityBatch, EntityRecord, FetchChangesParams, FetchParams, OAuthConnectorAuth, OAuthProviderDefinition, OAuthState, ServerDataProvider, ServerProviderFactory, SyncBoundary, SyncCompleteEvent, SyncErrorEvent, SyncEvent, SyncFailureSample, SyncProgressEvent, SyncState, SyncStateEntry, SyncStateStore, SyncStatus, TokenResponse, UserSyncPreferences, WebhookParams, WebhookRegistration, } from './types.js';
|
package/lib/index.js
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
-
export{resolveModelID}from
|
|
1
|
+
export { clusterModelURNs, resolveModelID } from './cluster-utils.js';
|
|
2
|
+
export { connectorClusters, connectorModelIDs } from './models/cluster.js';
|
|
3
|
+
export { externalEntityDefinition } from './models/external-entity.js';
|
package/lib/models/cluster.js
CHANGED
|
@@ -1 +1,11 @@
|
|
|
1
|
-
import{GraphBuilder
|
|
1
|
+
import { GraphBuilder, GraphModel } from '@kubun/protocol';
|
|
2
|
+
import { externalEntityDefinition } from './external-entity.js';
|
|
3
|
+
const builder = new GraphBuilder();
|
|
4
|
+
builder.add(externalEntityDefinition);
|
|
5
|
+
export const connectorClusters = builder.build();
|
|
6
|
+
const graph = GraphModel.fromClusters({
|
|
7
|
+
clusters: connectorClusters
|
|
8
|
+
});
|
|
9
|
+
export const connectorModelIDs = {
|
|
10
|
+
ExternalEntity: graph.aliases.ExternalEntity
|
|
11
|
+
};
|
|
@@ -1 +1,53 @@
|
|
|
1
|
-
import{dateTimeSchema
|
|
1
|
+
import { dateTimeSchema, urlSchema } from '@kubun/scalars';
|
|
2
|
+
/**
|
|
3
|
+
* ExternalEntity is the base interface for documents synced from external services.
|
|
4
|
+
*
|
|
5
|
+
* Fields:
|
|
6
|
+
* - sourceService: External service identifier (e.g., "jira", "slack", "ios-contacts")
|
|
7
|
+
* - sourceID: External entity native ID
|
|
8
|
+
* - sourceURL: Optional URL back to the entity in the source service
|
|
9
|
+
* - lastSyncedAt: Timestamp of when this entity was last synced
|
|
10
|
+
*/ export const externalEntityDefinition = {
|
|
11
|
+
name: 'ExternalEntity',
|
|
12
|
+
behavior: 'interface',
|
|
13
|
+
schema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
sourceService: {
|
|
17
|
+
$ref: '#/definitions/SourceService'
|
|
18
|
+
},
|
|
19
|
+
sourceID: {
|
|
20
|
+
$ref: '#/definitions/SourceID'
|
|
21
|
+
},
|
|
22
|
+
sourceURL: {
|
|
23
|
+
$ref: '#/definitions/SourceURL'
|
|
24
|
+
},
|
|
25
|
+
lastSyncedAt: {
|
|
26
|
+
$ref: '#/definitions/DateTime'
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
required: [
|
|
30
|
+
'sourceService',
|
|
31
|
+
'sourceID',
|
|
32
|
+
'lastSyncedAt'
|
|
33
|
+
],
|
|
34
|
+
additionalProperties: true,
|
|
35
|
+
definitions: {
|
|
36
|
+
SourceService: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
title: 'SourceService',
|
|
39
|
+
minLength: 1,
|
|
40
|
+
maxLength: 50
|
|
41
|
+
},
|
|
42
|
+
SourceID: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
title: 'SourceID',
|
|
45
|
+
minLength: 1,
|
|
46
|
+
maxLength: 500
|
|
47
|
+
},
|
|
48
|
+
SourceURL: urlSchema,
|
|
49
|
+
DateTime: dateTimeSchema
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
fieldsMeta: {}
|
|
53
|
+
};
|
package/lib/types.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ export type SyncState = {
|
|
|
42
42
|
entityCount: number;
|
|
43
43
|
status: SyncStatus;
|
|
44
44
|
error?: string;
|
|
45
|
+
leaseExpiresAt?: number | null;
|
|
45
46
|
};
|
|
46
47
|
export type SyncStateEntry = SyncState & {
|
|
47
48
|
connectorName: string;
|
|
@@ -52,6 +53,8 @@ export type SyncStateStore = {
|
|
|
52
53
|
set(connectorName: string, ownerDID: string, state: SyncState): Promise<void>;
|
|
53
54
|
delete(connectorName: string, ownerDID: string): Promise<void>;
|
|
54
55
|
listForConnector(connectorName: string): Promise<Array<SyncStateEntry>>;
|
|
56
|
+
claimSync(connectorName: string, ownerDID: string, leaseMs: number): Promise<boolean>;
|
|
57
|
+
renewSync(connectorName: string, ownerDID: string, leaseMs: number): Promise<void>;
|
|
55
58
|
};
|
|
56
59
|
export type SyncBoundary = {
|
|
57
60
|
maxAge?: string;
|
|
@@ -162,6 +165,11 @@ export type ConnectorDefinition = {
|
|
|
162
165
|
};
|
|
163
166
|
auth: ConnectorAuth;
|
|
164
167
|
};
|
|
168
|
+
export type SyncFailureSample = {
|
|
169
|
+
sourceService: string;
|
|
170
|
+
sourceID: string;
|
|
171
|
+
message: string;
|
|
172
|
+
};
|
|
165
173
|
export type SyncProgressEvent = {
|
|
166
174
|
type: 'sync:progress';
|
|
167
175
|
connectorName: string;
|
|
@@ -177,11 +185,13 @@ export type SyncCompleteEvent = {
|
|
|
177
185
|
totalProcessed: number;
|
|
178
186
|
totalFailed: number;
|
|
179
187
|
duration: number;
|
|
188
|
+
failedSample?: Array<SyncFailureSample>;
|
|
180
189
|
};
|
|
181
190
|
export type SyncErrorEvent = {
|
|
182
191
|
type: 'sync:error';
|
|
183
192
|
connectorName: string;
|
|
184
193
|
error: string;
|
|
194
|
+
failedSample?: Array<SyncFailureSample>;
|
|
185
195
|
};
|
|
186
196
|
export type SyncEvent = SyncProgressEvent | SyncCompleteEvent | SyncErrorEvent;
|
|
187
197
|
export type ConnectorSyncEventPayload = {
|
|
@@ -193,4 +203,5 @@ export type ConnectorSyncEventPayload = {
|
|
|
193
203
|
totalFailed?: number;
|
|
194
204
|
duration?: number;
|
|
195
205
|
error?: string;
|
|
206
|
+
failedSample?: Array<SyncFailureSample>;
|
|
196
207
|
};
|
package/lib/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{};
|
|
1
|
+
export { };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubun/connector",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"license": "see LICENSE.md",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"type": "module",
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
"sideEffects": false,
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"json-schema-typed": "^8.0.2",
|
|
19
|
-
"@kubun/protocol": "^0.
|
|
20
|
-
"@kubun/scalars": "^0.
|
|
19
|
+
"@kubun/protocol": "^0.11.0",
|
|
20
|
+
"@kubun/scalars": "^0.11.0"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build:clean": "del lib",
|
|
24
|
-
"build:js": "swc src -d ./lib --config-file ../../swc.json --strip-leading-paths",
|
|
24
|
+
"build:js": "swc src -d ./lib --config-file ../../node_modules/@kigu/dev/swc.json --strip-leading-paths",
|
|
25
25
|
"build:types": "tsc --emitDeclarationOnly --skipLibCheck",
|
|
26
26
|
"build:types:ci": "tsc --emitDeclarationOnly --declarationMap false",
|
|
27
27
|
"build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
|