@kubun/connector 0.10.0 → 0.12.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.
@@ -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>;
@@ -1 +1,32 @@
1
- export function resolveModelID(e,o){for(let r of Object.values(e)){let e=r.models.findIndex(e=>e.name===o);if(-1!==e){for(let[o,t]of Object.entries(r.record))if(t===e)return o}}throw Error(`Model "${o}" not found in any cluster`)}
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"./cluster-utils.js";export{connectorClusters,connectorModelIDs}from"./models/cluster.js";export{externalEntityDefinition}from"./models/external-entity.js";
1
+ export { clusterModelURNs, resolveModelID } from './cluster-utils.js';
2
+ export { connectorClusters, connectorModelIDs } from './models/cluster.js';
3
+ export { externalEntityDefinition } from './models/external-entity.js';
@@ -1 +1,11 @@
1
- import{GraphBuilder as t,GraphModel as e}from"@kubun/protocol";import{externalEntityDefinition as o}from"./external-entity.js";let r=new t;r.add(o);export const connectorClusters=r.build();let n=e.fromClusters({clusters:connectorClusters});export const connectorModelIDs={ExternalEntity:n.aliases.ExternalEntity};
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 as e,urlSchema as i}from"@kubun/scalars";export const externalEntityDefinition={name:"ExternalEntity",behavior:"interface",schema:{type:"object",properties:{sourceService:{$ref:"#/definitions/SourceService"},sourceID:{$ref:"#/definitions/SourceID"},sourceURL:{$ref:"#/definitions/SourceURL"},lastSyncedAt:{$ref:"#/definitions/DateTime"}},required:["sourceService","sourceID","lastSyncedAt"],additionalProperties:!0,definitions:{SourceService:{type:"string",title:"SourceService",minLength:1,maxLength:50},SourceID:{type:"string",title:"SourceID",minLength:1,maxLength:500},SourceURL:i,DateTime:e}},fieldsMeta:{}};
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,32 +1,32 @@
1
1
  {
2
2
  "name": "@kubun/connector",
3
- "version": "0.10.0",
4
- "license": "see LICENSE.md",
3
+ "version": "0.12.0",
5
4
  "keywords": [],
5
+ "license": "see LICENSE.md",
6
+ "sideEffects": false,
6
7
  "type": "module",
7
- "main": "lib/index.js",
8
- "types": "lib/index.d.ts",
9
8
  "exports": {
10
9
  ".": "./lib/index.js"
11
10
  },
11
+ "main": "lib/index.js",
12
+ "types": "lib/index.d.ts",
12
13
  "files": [
13
14
  "lib/*",
14
15
  "LICENSE.md"
15
16
  ],
16
- "sideEffects": false,
17
17
  "dependencies": {
18
18
  "json-schema-typed": "^8.0.2",
19
- "@kubun/protocol": "^0.10.0",
20
- "@kubun/scalars": "^0.10.0"
19
+ "@kubun/protocol": "^0.12.0",
20
+ "@kubun/scalars": "^0.12.0"
21
21
  },
22
22
  "scripts": {
23
+ "build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
23
24
  "build:clean": "del lib",
24
- "build:js": "swc src -d ./lib --config-file ../../swc.json --strip-leading-paths",
25
+ "build:js": "swc src -d ./lib --config-file ../../node_modules/@kigu/dev/swc.json --strip-leading-paths",
25
26
  "build:types": "tsc --emitDeclarationOnly --skipLibCheck",
26
27
  "build:types:ci": "tsc --emitDeclarationOnly --declarationMap false",
27
- "build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
28
+ "test": "pnpm run test:types && pnpm run test:unit",
28
29
  "test:types": "tsc --noEmit -p tsconfig.test.json",
29
- "test:unit": "vitest run",
30
- "test": "pnpm run test:types && pnpm run test:unit"
30
+ "test:unit": "vitest run"
31
31
  }
32
32
  }