@twinfinity/twin 0.0.0-feature.31596
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/README.md +277 -0
- package/dist/BuildInfo.d.ts +25 -0
- package/dist/BuildInfo.d.ts.map +1 -0
- package/dist/BuildInfo.js +15 -0
- package/dist/BuildInfo.js.map +1 -0
- package/dist/TwinClient.d.ts +823 -0
- package/dist/TwinClient.d.ts.map +1 -0
- package/dist/TwinClient.js +1487 -0
- package/dist/TwinClient.js.map +1 -0
- package/dist/errors.d.ts +289 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +357 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/Twin.d.ts +7 -0
- package/dist/types/Twin.d.ts.map +1 -0
- package/dist/types/Twin.js +6 -0
- package/dist/types/Twin.js.map +1 -0
- package/dist/types/TwinGeometryInfo.d.ts +7 -0
- package/dist/types/TwinGeometryInfo.d.ts.map +1 -0
- package/dist/types/TwinGeometryInfo.js +2 -0
- package/dist/types/TwinGeometryInfo.js.map +1 -0
- package/dist/types/asset-api.d.ts +66 -0
- package/dist/types/asset-api.d.ts.map +1 -0
- package/dist/types/asset-api.js +2 -0
- package/dist/types/asset-api.js.map +1 -0
- package/dist/types/asset-attachment-api.d.ts +51 -0
- package/dist/types/asset-attachment-api.d.ts.map +1 -0
- package/dist/types/asset-attachment-api.js +8 -0
- package/dist/types/asset-attachment-api.js.map +1 -0
- package/dist/types/asset-batch-api.d.ts +73 -0
- package/dist/types/asset-batch-api.d.ts.map +1 -0
- package/dist/types/asset-batch-api.js +2 -0
- package/dist/types/asset-batch-api.js.map +1 -0
- package/dist/types/asset-types-api.d.ts +76 -0
- package/dist/types/asset-types-api.d.ts.map +1 -0
- package/dist/types/asset-types-api.js +5 -0
- package/dist/types/asset-types-api.js.map +1 -0
- package/dist/types/common.d.ts +10 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +2 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/generated.d.ts +458 -0
- package/dist/types/generated.d.ts.map +1 -0
- package/dist/types/generated.js +2 -0
- package/dist/types/generated.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/twin-api.d.ts +141 -0
- package/dist/types/twin-api.d.ts.map +1 -0
- package/dist/types/twin-api.js +2 -0
- package/dist/types/twin-api.js.map +1 -0
- package/dist/types/twin-file-api.d.ts +61 -0
- package/dist/types/twin-file-api.d.ts.map +1 -0
- package/dist/types/twin-file-api.js +2 -0
- package/dist/types/twin-file-api.js.map +1 -0
- package/dist/types/twin-permissions-api.d.ts +240 -0
- package/dist/types/twin-permissions-api.d.ts.map +1 -0
- package/dist/types/twin-permissions-api.js +2 -0
- package/dist/types/twin-permissions-api.js.map +1 -0
- package/docs/.nojekyll +1 -0
- package/docs/assets/hierarchy.js +1 -0
- package/docs/assets/highlight.css +99 -0
- package/docs/assets/icons.js +18 -0
- package/docs/assets/icons.svg +1 -0
- package/docs/assets/main.js +60 -0
- package/docs/assets/navigation.js +1 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +1633 -0
- package/docs/classes/AssetAttachmentConflictError.html +3 -0
- package/docs/classes/AssetAttachmentNotFoundError.html +2 -0
- package/docs/classes/AssetBatchError.html +3 -0
- package/docs/classes/AssetCatalogTooLargeError.html +16 -0
- package/docs/classes/AssetCategoryConflictError.html +3 -0
- package/docs/classes/AssetCategoryForbiddenError.html +2 -0
- package/docs/classes/AssetCategoryNotFoundError.html +2 -0
- package/docs/classes/AssetCategoryValidationError.html +3 -0
- package/docs/classes/AssetConflictError.html +3 -0
- package/docs/classes/AssetForbiddenError.html +2 -0
- package/docs/classes/AssetNotFoundError.html +2 -0
- package/docs/classes/AssetPermissionsConflictError.html +16 -0
- package/docs/classes/AssetTypeConflictError.html +3 -0
- package/docs/classes/AssetTypeForbiddenError.html +2 -0
- package/docs/classes/AssetTypeNotFoundError.html +2 -0
- package/docs/classes/AssetTypeValidationError.html +3 -0
- package/docs/classes/AssetValidationError.html +3 -0
- package/docs/classes/ProcessorNotFoundError.html +2 -0
- package/docs/classes/TwinClient.html +409 -0
- package/docs/classes/TwinConflictError.html +3 -0
- package/docs/classes/TwinFileConflictError.html +3 -0
- package/docs/classes/TwinFileNotFoundError.html +2 -0
- package/docs/classes/TwinFileValidationError.html +3 -0
- package/docs/classes/TwinNotFoundError.html +4 -0
- package/docs/classes/TwinPermissionsConflictError.html +19 -0
- package/docs/classes/TwinPermissionsForbiddenError.html +12 -0
- package/docs/classes/TwinPrincipalNotFoundError.html +5 -0
- package/docs/classes/TwinTemporarilyUnavailableError.html +10 -0
- package/docs/classes/TwinUnauthenticatedError.html +6 -0
- package/docs/classes/TwinValidationError.html +3 -0
- package/docs/functions/isAssetCatalogTooLargeErrorBody.html +6 -0
- package/docs/functions/readErrorBody.html +10 -0
- package/docs/hierarchy.html +1 -0
- package/docs/index.html +168 -0
- package/docs/interfaces/ApiCreateUploadSessionResponse.html +7 -0
- package/docs/interfaces/AssetAttachmentPut.html +6 -0
- package/docs/interfaces/AssetBatchDeleteOperation.html +4 -0
- package/docs/interfaces/AssetBatchGetRequest.html +2 -0
- package/docs/interfaces/AssetBatchGetResponse.html +3 -0
- package/docs/interfaces/AssetBatchRequest.html +2 -0
- package/docs/interfaces/AssetBatchResponse.html +3 -0
- package/docs/interfaces/AssetBatchRestoreOperation.html +4 -0
- package/docs/interfaces/AssetBatchUpsertItem.html +12 -0
- package/docs/interfaces/AssetBatchUpsertOperation.html +4 -0
- package/docs/interfaces/AssetCatalogCategory.html +7 -0
- package/docs/interfaces/AssetCatalogResponse.html +6 -0
- package/docs/interfaces/AssetCatalogTooLargeErrorBody.html +15 -0
- package/docs/interfaces/AssetCategoryDelete.html +2 -0
- package/docs/interfaces/AssetCategoryGet.html +14 -0
- package/docs/interfaces/AssetCategoryPut.html +7 -0
- package/docs/interfaces/AssetGet.html +18 -0
- package/docs/interfaces/AssetGroupGet.html +9 -0
- package/docs/interfaces/AssetGroupsGet.html +3 -0
- package/docs/interfaces/AssetListItem.html +14 -0
- package/docs/interfaces/AssetPermissionsConflictErrorBody.html +12 -0
- package/docs/interfaces/AssetPermissionsPut.html +9 -0
- package/docs/interfaces/AssetPosition.html +4 -0
- package/docs/interfaces/AssetPost.html +12 -0
- package/docs/interfaces/AssetPrincipalPermissionsGet.html +23 -0
- package/docs/interfaces/AssetPut.html +12 -0
- package/docs/interfaces/AssetTypeDelete.html +2 -0
- package/docs/interfaces/AssetTypeGet.html +16 -0
- package/docs/interfaces/AssetTypePut.html +9 -0
- package/docs/interfaces/AttachmentGet.html +20 -0
- package/docs/interfaces/AttachmentPost.html +4 -0
- package/docs/interfaces/BatchItemError.html +4 -0
- package/docs/interfaces/BatchItemResult.html +6 -0
- package/docs/interfaces/BatchSummary.html +4 -0
- package/docs/interfaces/Coordinates.html +6 -0
- package/docs/interfaces/Diagnostics.html +4 -0
- package/docs/interfaces/DiagnosticsSummary.html +4 -0
- package/docs/interfaces/ElementQuantities.html +3 -0
- package/docs/interfaces/EntityCollection.html +15 -0
- package/docs/interfaces/EntityRepresentation.html +12 -0
- package/docs/interfaces/Facility.html +22 -0
- package/docs/interfaces/FacilityPart.html +18 -0
- package/docs/interfaces/FilePatch.html +7 -0
- package/docs/interfaces/FilePatchSet.html +5 -0
- package/docs/interfaces/GenericDiagnosticEntry.html +4 -0
- package/docs/interfaces/ITwinClient.html +404 -0
- package/docs/interfaces/IfcDiagnosticEntry.html +5 -0
- package/docs/interfaces/IfcDiagnosticNode.html +6 -0
- package/docs/interfaces/IfcDiagnosticNodeData.html +6 -0
- package/docs/interfaces/InheritedPermissions.html +8 -0
- package/docs/interfaces/ListTwinItem.html +30 -0
- package/docs/interfaces/Location.html +13 -0
- package/docs/interfaces/MyPermissions.html +7 -0
- package/docs/interfaces/MyTwinPermissions.html +5 -0
- package/docs/interfaces/PaginatedResponse.html +3 -0
- package/docs/interfaces/Pagination.html +4 -0
- package/docs/interfaces/Property.html +4 -0
- package/docs/interfaces/PropertySet.html +6 -0
- package/docs/interfaces/SimpleQuantity.html +6 -0
- package/docs/interfaces/SinglePropertyValue.html +5 -0
- package/docs/interfaces/Site.html +27 -0
- package/docs/interfaces/Space.html +16 -0
- package/docs/interfaces/TwinComputedPropertySetsResponse.html +4 -0
- package/docs/interfaces/TwinContentResponse.html +6 -0
- package/docs/interfaces/TwinDelete.html +2 -0
- package/docs/interfaces/TwinDiagnosticEntry.html +5 -0
- package/docs/interfaces/TwinDiagnosticNode.html +4 -0
- package/docs/interfaces/TwinDiagnosticNodeData.html +9 -0
- package/docs/interfaces/TwinDiagnosticsResponse.html +5 -0
- package/docs/interfaces/TwinErrorBody.html +4 -0
- package/docs/interfaces/TwinFileDelete.html +2 -0
- package/docs/interfaces/TwinFileGet.html +15 -0
- package/docs/interfaces/TwinFileListOptions.html +6 -0
- package/docs/interfaces/TwinFilePut.html +8 -0
- package/docs/interfaces/TwinFileReference.html +4 -0
- package/docs/interfaces/TwinFileRestore.html +2 -0
- package/docs/interfaces/TwinFileSource.html +4 -0
- package/docs/interfaces/TwinFileTransform.html +11 -0
- package/docs/interfaces/TwinFileVersionListOptions.html +4 -0
- package/docs/interfaces/TwinGet.html +48 -0
- package/docs/interfaces/TwinGroupGet.html +10 -0
- package/docs/interfaces/TwinGroupsGet.html +3 -0
- package/docs/interfaces/TwinPermissionsConflictErrorBody.html +8 -0
- package/docs/interfaces/TwinPermissionsPut.html +11 -0
- package/docs/interfaces/TwinPrincipalPermissionsGet.html +34 -0
- package/docs/interfaces/TwinProcessorEvent.html +7 -0
- package/docs/interfaces/TwinProcessorResponse.html +5 -0
- package/docs/interfaces/TwinPut.html +21 -0
- package/docs/interfaces/TwinReference.html +4 -0
- package/docs/interfaces/TwinSpecification.html +18 -0
- package/docs/interfaces/TwinVersionContentResponse.html +7 -0
- package/docs/interfaces/UploadStatusGet.html +3 -0
- package/docs/media/twin-management.md +399 -0
- package/docs/modules.html +1 -0
- package/docs/types/AssetBatchGetStatus.html +1 -0
- package/docs/types/AssetBatchOperation.html +1 -0
- package/docs/types/AssetBatchOperationStatus.html +1 -0
- package/docs/types/DiagnosticCategory.html +2 -0
- package/docs/types/DiagnosticLevel.html +2 -0
- package/docs/types/EpsgType.html +1 -0
- package/docs/types/FacilityClass.html +3 -0
- package/docs/types/FacilityPartClass.html +3 -0
- package/docs/types/IfcDiagnosticCode.html +1 -0
- package/docs/types/Op.html +2 -0
- package/docs/types/SinglePropertyValueType.html +3 -0
- package/docs/types/SingleQuantityValueType.html +3 -0
- package/docs/types/SiteType.html +3 -0
- package/docs/types/SpaceType.html +2 -0
- package/docs/types/TwinBoundCapabilityName.html +8 -0
- package/docs/types/TwinCapability.html +12 -0
- package/docs/types/TwinCapabilityName.html +8 -0
- package/docs/types/TwinDiagnosticCode.html +1 -0
- package/docs/types/TwinErrorCause.html +8 -0
- package/docs/types/TwinErrorItemKind.html +4 -0
- package/docs/types/TwinPermissionsConflictCause.html +6 -0
- package/docs/types/TwinScopedCapability.html +9 -0
- package/docs/types/TwinScopedCapabilityName.html +8 -0
- package/docs/types/UploadStatus.html +1 -0
- package/package.json +52 -0
- package/src/BuildInfo.ts +41 -0
- package/src/TwinClient.ts +3113 -0
- package/src/errors.ts +567 -0
- package/src/index.ts +3 -0
- package/src/tsconfig.json +13 -0
- package/src/types/Twin.ts +7 -0
- package/src/types/TwinGeometryInfo.ts +7 -0
- package/src/types/asset-api.ts +69 -0
- package/src/types/asset-attachment-api.ts +56 -0
- package/src/types/asset-batch-api.ts +90 -0
- package/src/types/asset-types-api.ts +86 -0
- package/src/types/common.ts +10 -0
- package/src/types/generated.ts +655 -0
- package/src/types/index.ts +9 -0
- package/src/types/twin-api.ts +153 -0
- package/src/types/twin-file-api.ts +67 -0
- package/src/types/twin-permissions-api.ts +257 -0
package/README.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# @twinfinity/twin
|
|
2
|
+
|
|
3
|
+
TypeScript client for the Twinfinity Twin Service API. Provides typed access to twins, assets, and twin files with optimistic concurrency control and structured error handling.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @twinfinity/twin
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Peer Dependencies
|
|
12
|
+
|
|
13
|
+
- `@twinfinity/authentication` - provides `TwinfinityHttpClient` for authenticated HTTP requests
|
|
14
|
+
- `@twinfinity/t8-client-model` - provides T8 client model types used by `loadTwin` / `loadGeometryInfo`
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
### Creating a Client
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { TwinClient } from '@twinfinity/twin';
|
|
22
|
+
|
|
23
|
+
const client = new TwinClient(baseUrl, httpClient);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The `baseUrl` is the API root (e.g. `https://api.twinfinity.com`). The client appends `/_ps/twins` internally.
|
|
27
|
+
|
|
28
|
+
### Twin Operations
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// List twins (paginated)
|
|
32
|
+
const page = await client.listTwins();
|
|
33
|
+
|
|
34
|
+
// List all twins (auto-paginates)
|
|
35
|
+
const allTwins = await client.listAllTwins();
|
|
36
|
+
|
|
37
|
+
// Get a specific twin
|
|
38
|
+
const twin = await client.getTwin('twin-id');
|
|
39
|
+
|
|
40
|
+
// Get a specific version
|
|
41
|
+
const twinV2 = await client.getTwin({ id: 'twin-id', version: 2 });
|
|
42
|
+
|
|
43
|
+
// Create or update
|
|
44
|
+
const updated = await client.createOrUpdateTwin('twin-id', {
|
|
45
|
+
relatedContainerIds: ['container-1'],
|
|
46
|
+
rootEntity: '0Site00000000000000000',
|
|
47
|
+
entities: {
|
|
48
|
+
sites: {
|
|
49
|
+
'0Site00000000000000000': { id: '0Site00000000000000000', name: 'My site' }
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
etag: twin.etag // required for updates
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Soft-delete and restore
|
|
56
|
+
const deleted = await client.deleteTwin('twin-id', twin.etag);
|
|
57
|
+
const restored = await client.restoreTwin('twin-id', deleted.etag);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### Nesting twins
|
|
61
|
+
|
|
62
|
+
A twin can nest other twins as children. Declare each child in `entities.twinReferences`
|
|
63
|
+
and place it under a site via that site's `aggregatedTwinReferences`:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
await client.createOrUpdateTwin('parent-id', {
|
|
67
|
+
relatedContainerIds: ['container-1'],
|
|
68
|
+
rootEntity: '0Site00000000000000000',
|
|
69
|
+
entities: {
|
|
70
|
+
sites: {
|
|
71
|
+
'0Site00000000000000000': {
|
|
72
|
+
id: '0Site00000000000000000',
|
|
73
|
+
name: 'Campus site',
|
|
74
|
+
aggregatedTwinReferences: ['ref-a']
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
twinReferences: {
|
|
78
|
+
'ref-a': { twin: 'child-id' } // id of the nested twin
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Omit `etag` when creating; supply the current twin's etag only when updating.
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// The parent/child edge is computed and read back on the twin:
|
|
85
|
+
const parent = await client.getTwin('parent-id');
|
|
86
|
+
parent.aggregatedTwins; // ['child-id'] — twins this twin parents
|
|
87
|
+
const child = await client.getTwin('child-id');
|
|
88
|
+
child.parentTwin; // 'parent-id' — the twin that references this one
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`aggregatedTwins` and `parentTwin` are computed by the service, not authored — sending
|
|
92
|
+
them in a write has no effect. A twin may have at most one parent, may not reference
|
|
93
|
+
itself, and references may not form a cycle. Adding a reference requires `View` on the
|
|
94
|
+
referenced twin (in addition to `Edit` on the twin being written); a referenced twin you
|
|
95
|
+
cannot read is reported as not found. See
|
|
96
|
+
[Twin Management → Nested Twins](../../docs/specs/backend/services/twin/twin-management.md#nested-twins-twin-references)
|
|
97
|
+
for the full rules.
|
|
98
|
+
|
|
99
|
+
### Loading Twin Models
|
|
100
|
+
|
|
101
|
+
The client can download and deserialize processed twin content (T8CM/T8GI formats):
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// Load client model with default types
|
|
105
|
+
const { id, version, model } = await client.loadTwin('twin-id');
|
|
106
|
+
|
|
107
|
+
// Load with custom factory functions for domain-specific types
|
|
108
|
+
const custom = await client.loadTwinWithFactories(
|
|
109
|
+
'twin-id',
|
|
110
|
+
myProjectFactory,
|
|
111
|
+
myProductFactory,
|
|
112
|
+
myEntityTypeFactory,
|
|
113
|
+
myUnitFactory,
|
|
114
|
+
myConnectProject,
|
|
115
|
+
myConnectProduct
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// Load geometry info
|
|
119
|
+
const geometry = await client.loadGeometryInfo('twin-id');
|
|
120
|
+
|
|
121
|
+
// Load client model with geometry combined
|
|
122
|
+
const withGeometry = await client.loadTwinWithGeometry('twin-id');
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
When no version is specified, the client searches versions (newest first) for one that has the requested content format.
|
|
126
|
+
|
|
127
|
+
### Asset Operations
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// List assets in a twin
|
|
131
|
+
const assets = await client.listAssets('twin-id');
|
|
132
|
+
|
|
133
|
+
// Include soft-deleted assets
|
|
134
|
+
const allAssets = await client.listAssets('twin-id', 0, 100, { includeDeleted: true });
|
|
135
|
+
|
|
136
|
+
// Create assets
|
|
137
|
+
const created = await client.createAssets('twin-id', [{ name: 'Pump A', category: 'HVAC', type: 'Pump' }]);
|
|
138
|
+
|
|
139
|
+
// Update with optimistic concurrency
|
|
140
|
+
const updated = await client.updateAsset('twin-id', 'asset-id', {
|
|
141
|
+
etag: asset.etag,
|
|
142
|
+
name: 'Pump A (Updated)'
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Batch operations (atomic - all succeed or all roll back)
|
|
146
|
+
const result = await client.batchAssets('twin-id', [
|
|
147
|
+
{ operation: 'upsert', id: 'asset-1', item: { name: 'New Asset' } },
|
|
148
|
+
{ operation: 'delete', id: 'asset-2', item: { etag: 'etag-2' } },
|
|
149
|
+
{ operation: 'restore', id: 'asset-3', item: { etag: 'etag-3' } }
|
|
150
|
+
]);
|
|
151
|
+
|
|
152
|
+
// Batch get multiple assets by ID
|
|
153
|
+
const fetched = await client.batchGetAssets('twin-id', ['id-1', 'id-2']);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Twin File Operations
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// List files (with filtering)
|
|
160
|
+
const files = await client.listTwinFiles('twin-id', { checkedIn: true });
|
|
161
|
+
|
|
162
|
+
// Create or update a file
|
|
163
|
+
const file = await client.createOrUpdateTwinFile('twin-id', 'file-id', {
|
|
164
|
+
source: { changeId: 'doc-id', changeVersion: 1, sourceType: 'DocumentChange' },
|
|
165
|
+
name: 'model.ifc',
|
|
166
|
+
quality: 100
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Download file content
|
|
170
|
+
const blob = await client.getTwinFileContent('twin-id', 'file-id');
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Error Handling
|
|
174
|
+
|
|
175
|
+
All methods throw typed errors for specific HTTP failure codes. Unexpected status codes throw a generic `Error`.
|
|
176
|
+
|
|
177
|
+
### Error Classes
|
|
178
|
+
|
|
179
|
+
| Error | HTTP Status | Context Attached |
|
|
180
|
+
| ------------------------- | ----------- | ------------------------------ |
|
|
181
|
+
| `TwinValidationError` | 400 | `errorBody?: TwinErrorBody` |
|
|
182
|
+
| `TwinNotFoundError` | 404 | `errorBody?: TwinErrorBody` |
|
|
183
|
+
| `TwinConflictError` | 409 | `currentTwin: TwinGet` |
|
|
184
|
+
| `AssetValidationError` | 400 | `errorBody?: TwinErrorBody` |
|
|
185
|
+
| `AssetForbiddenError` | 403 | - |
|
|
186
|
+
| `AssetNotFoundError` | 404 | - |
|
|
187
|
+
| `AssetConflictError` | 409 | `currentAsset: AssetGet` |
|
|
188
|
+
| `AssetBatchError` | 404, 409 | `response: AssetBatchResponse` |
|
|
189
|
+
| `TwinFileValidationError` | 400 | `errorBody?: TwinErrorBody` |
|
|
190
|
+
| `TwinFileNotFoundError` | 404 | - |
|
|
191
|
+
| `TwinFileConflictError` | 409 | `currentTwinFile: TwinFileGet` |
|
|
192
|
+
| `ProcessorNotFoundError` | 404 | - |
|
|
193
|
+
|
|
194
|
+
Twin-scoped permissions (`/twins/{twinId}/permissions`, `/twins/{twinId}/groups`):
|
|
195
|
+
|
|
196
|
+
| Error | HTTP Status | Context Attached |
|
|
197
|
+
| --------------------------------------- | ----------- | --------------------------------------------------------- |
|
|
198
|
+
| `TwinPermissionsForbiddenError` | 403 | `errorBody?: TwinErrorBody` |
|
|
199
|
+
| `TwinPrincipalNotFoundError` | 404 | `errorBody?: TwinErrorBody` |
|
|
200
|
+
| `TwinPermissionsConflictError` | 409 | `conflictCause`, `currentState?`, `errorBody` |
|
|
201
|
+
| `TwinTemporarilyUnavailableError` | 503 | `errorBody?: TwinErrorBody`, `retryAfterSeconds?: number` |
|
|
202
|
+
|
|
203
|
+
`TwinPermissionsConflictError` names the conflict on `conflictCause` rather than on `cause`, leaving
|
|
204
|
+
the standard `Error.cause` free: `EtagMismatch` is retried by re-reading, `EtagRequired` by reading
|
|
205
|
+
at all, and `ScopesNotProvisioned` is not retryable. `currentState` carries the entry as the server
|
|
206
|
+
holds it, including the etag to retry with.
|
|
207
|
+
|
|
208
|
+
Asset-domain permissions (`/twins/permissions`, `/twins/groups`) reuse the errors above, except that
|
|
209
|
+
a 409 arrives as `AssetPermissionsConflictError` — the same shape, but its `currentState` is an
|
|
210
|
+
`AssetPrincipalPermissionsGet` rather than a twin's entry, and `ScopesNotProvisioned` never occurs
|
|
211
|
+
because the domain's scope is seeded once per customer rather than provisioned per resource.
|
|
212
|
+
|
|
213
|
+
### Conflict Handling
|
|
214
|
+
|
|
215
|
+
Conflict errors (409) carry the current server-side state, enabling retry logic:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
import { TwinConflictError } from '@twinfinity/twin';
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
await client.createOrUpdateTwin('twin-id', twinData);
|
|
222
|
+
} catch (e) {
|
|
223
|
+
if (e instanceof TwinConflictError) {
|
|
224
|
+
// e.currentTwin contains the server's current version
|
|
225
|
+
// Use it to merge changes and retry
|
|
226
|
+
const merged = mergeChanges(twinData, e.currentTwin);
|
|
227
|
+
await client.createOrUpdateTwin('twin-id', {
|
|
228
|
+
...merged,
|
|
229
|
+
etag: e.currentTwin.etag
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Validation Error Body
|
|
236
|
+
|
|
237
|
+
`TwinValidationError`, `TwinFileValidationError`, and `AssetValidationError` may include a structured error body:
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
interface TwinErrorBody {
|
|
241
|
+
detail: string;
|
|
242
|
+
cause: string;
|
|
243
|
+
item?: {
|
|
244
|
+
kind: string;
|
|
245
|
+
id: string;
|
|
246
|
+
version?: number;
|
|
247
|
+
field?: string;
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Batch Error Handling
|
|
253
|
+
|
|
254
|
+
`AssetBatchError` carries the full batch response with per-item results, including which operations were reverted:
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { AssetBatchError } from '@twinfinity/twin';
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
await client.batchAssets('twin-id', operations);
|
|
261
|
+
} catch (e) {
|
|
262
|
+
if (e instanceof AssetBatchError) {
|
|
263
|
+
for (const result of e.response.results) {
|
|
264
|
+
if (result.status === 'conflicted') {
|
|
265
|
+
console.log(`Item ${result.index} conflicted: ${result.error?.detail}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Exports
|
|
273
|
+
|
|
274
|
+
The package has two export paths:
|
|
275
|
+
|
|
276
|
+
- `@twinfinity/twin` - Public API: `TwinClient`, `ITwinClient`, all types, all error classes
|
|
277
|
+
- `@twinfinity/twin/internal/*` - Internal modules (no stability guarantees)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents either production or development build type
|
|
3
|
+
*/
|
|
4
|
+
export type BuildType = 'Dev' | 'Prod';
|
|
5
|
+
/**
|
|
6
|
+
* Contains property metadata for the Twinfinity build
|
|
7
|
+
*/
|
|
8
|
+
export interface BuildInfo {
|
|
9
|
+
/** Major version number */
|
|
10
|
+
readonly major: number;
|
|
11
|
+
/** Minor version number */
|
|
12
|
+
readonly minor: number;
|
|
13
|
+
/** Patch version number */
|
|
14
|
+
readonly patch: number;
|
|
15
|
+
/** Unique build id */
|
|
16
|
+
readonly id: number;
|
|
17
|
+
/** The commit checksum */
|
|
18
|
+
readonly commit: string;
|
|
19
|
+
/** String that uniquely identifies the current version */
|
|
20
|
+
readonly version: string;
|
|
21
|
+
/** The build type */
|
|
22
|
+
readonly buildType: BuildType;
|
|
23
|
+
}
|
|
24
|
+
export declare const BUILD_INFO: Readonly<BuildInfo>;
|
|
25
|
+
//# sourceMappingURL=BuildInfo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BuildInfo.d.ts","sourceRoot":"","sources":["../src/BuildInfo.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;AAEvC;;GAEG;AACH,MAAM,WAAW,SAAS;IACtB,2BAA2B;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2BAA2B;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2BAA2B;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,qBAAqB;IACrB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;CACjC;AAiBD,eAAO,MAAM,UAAU,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const gBi = {
|
|
2
|
+
major: 0,
|
|
3
|
+
minor: 0,
|
|
4
|
+
patch: 0,
|
|
5
|
+
id: 31596,
|
|
6
|
+
commit: 'b8846e12b',
|
|
7
|
+
version: '',
|
|
8
|
+
buildType: 'Prod'
|
|
9
|
+
};
|
|
10
|
+
gBi.version = `${gBi.major}.${gBi.minor}.${gBi.patch}.${gBi.id}-[${gBi.commit}]`;
|
|
11
|
+
if (gBi.commit === 'unknownCommit') {
|
|
12
|
+
gBi.buildType = 'Dev';
|
|
13
|
+
}
|
|
14
|
+
export const BUILD_INFO = Object.freeze(gBi);
|
|
15
|
+
//# sourceMappingURL=BuildInfo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BuildInfo.js","sourceRoot":"","sources":["../src/BuildInfo.ts"],"names":[],"mappings":"AAyBA,MAAM,GAAG,GAAc;IACnB,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,MAAM;IACb,EAAE,EAAE,MAAM;IACV,MAAM,EAAE,eAAe;IACvB,OAAO,EAAE,EAAE;IACX,SAAS,EAAE,MAAM;CACpB,CAAC;AAED,GAAG,CAAC,OAAkB,GAAG,GAAG,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC;AAC7F,IAAI,GAAG,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;IAChC,GAAG,CAAC,SAAuB,GAAG,KAAK,CAAC;AACzC,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC"}
|