@stream44.studio/encapsulate 0.4.0-rc.5
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/.dco-signatures +9 -0
- package/.github/workflows/dco.yaml +12 -0
- package/.github/workflows/test.yml +26 -0
- package/.o/GordianOpenIntegrity-CurrentLifehash.svg +1026 -0
- package/.o/GordianOpenIntegrity-InceptionLifehash.svg +1026 -0
- package/.o/GordianOpenIntegrity.yaml +25 -0
- package/.o/assets/Hero-Explosion-v0.jpeg +0 -0
- package/DCO.md +34 -0
- package/LICENSE.md +8 -0
- package/README.md +46 -0
- package/package.json +33 -0
- package/src/capsule-projectors/CapsuleModuleProjector.v0.ts +1725 -0
- package/src/encapsulate.ts +881 -0
- package/src/spine-contracts/CapsuleSpineContract.v0/Membrane.v0.ts +705 -0
- package/src/spine-contracts/CapsuleSpineContract.v0/README.md +28 -0
- package/src/spine-contracts/CapsuleSpineContract.v0/Static.v0.ts +395 -0
- package/src/spine-factories/CapsuleSpineFactory.v0.ts +582 -0
- package/src/spine-factories/TimingObserver.ts +26 -0
- package/src/static-analyzer.v0.ts +1898 -0
- package/structs/Capsule.ts +22 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
Capsule Spine Contract v0
|
|
3
|
+
===
|
|
4
|
+
|
|
5
|
+
The default spine contract used to incubate spine functionality.
|
|
6
|
+
|
|
7
|
+
A spine contract is a standard and implementation that governs:
|
|
8
|
+
|
|
9
|
+
- how capsule properties are mapped to the encapsulated api and
|
|
10
|
+
- which features are available to bind additional logic controlled by definitions declared in the capsule source
|
|
11
|
+
|
|
12
|
+
Spine contracts define ecosystems as source code is written against these standards. They define the fundamental logic of how components and their internal APIs are bound.
|
|
13
|
+
|
|
14
|
+
In practice there should only ever be very few spine contracts but there can be a plethora of different partial or full implementations of the same standard.
|
|
15
|
+
|
|
16
|
+
This spine contract aims to realize a concrete implementation of the [PrivateData.Space](https://privatedata.space/) model for the purpose of building full-stack distributed JavaScript applications & systems.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
Example Capsule Source
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
Reference
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import { CapsulePropertyTypes, join } from "../../encapsulate"
|
|
2
|
+
|
|
3
|
+
// Type for capsule instance registry - scoped per spine contract instance
|
|
4
|
+
export type CapsuleInstanceRegistry = Map<string, any>
|
|
5
|
+
|
|
6
|
+
export class ContractCapsuleInstanceFactory {
|
|
7
|
+
|
|
8
|
+
protected spineContractUri: string
|
|
9
|
+
protected capsule: any
|
|
10
|
+
protected self: any
|
|
11
|
+
protected encapsulatedApi: Record<string, any>
|
|
12
|
+
protected resolve?: (uri: string, parentFilepath: string) => Promise<string>
|
|
13
|
+
protected importCapsule?: (filepath: string) => Promise<any>
|
|
14
|
+
protected spineFilesystemRoot?: string
|
|
15
|
+
protected freezeCapsule?: (capsule: any) => Promise<any>
|
|
16
|
+
protected instanceRegistry?: CapsuleInstanceRegistry
|
|
17
|
+
protected extendedCapsuleInstance?: any
|
|
18
|
+
protected ownSelf?: any
|
|
19
|
+
protected runtimeSpineContracts?: Record<string, any>
|
|
20
|
+
public structInitFunctions: Array<() => any> = []
|
|
21
|
+
public mappedCapsuleInstances: Array<any> = []
|
|
22
|
+
|
|
23
|
+
constructor({ spineContractUri, capsule, self, ownSelf, encapsulatedApi, resolve, importCapsule, spineFilesystemRoot, freezeCapsule, instanceRegistry, extendedCapsuleInstance, runtimeSpineContracts }: { spineContractUri: string, capsule: any, self: any, ownSelf?: any, encapsulatedApi: Record<string, any>, resolve?: (uri: string, parentFilepath: string) => Promise<string>, importCapsule?: (filepath: string) => Promise<any>, spineFilesystemRoot?: string, freezeCapsule?: (capsule: any) => Promise<any>, instanceRegistry?: CapsuleInstanceRegistry, extendedCapsuleInstance?: any, runtimeSpineContracts?: Record<string, any> }) {
|
|
24
|
+
this.spineContractUri = spineContractUri
|
|
25
|
+
this.capsule = capsule
|
|
26
|
+
this.self = self
|
|
27
|
+
this.ownSelf = ownSelf
|
|
28
|
+
this.encapsulatedApi = encapsulatedApi
|
|
29
|
+
this.resolve = resolve
|
|
30
|
+
this.importCapsule = importCapsule
|
|
31
|
+
this.spineFilesystemRoot = spineFilesystemRoot
|
|
32
|
+
this.freezeCapsule = freezeCapsule
|
|
33
|
+
this.instanceRegistry = instanceRegistry
|
|
34
|
+
this.extendedCapsuleInstance = extendedCapsuleInstance
|
|
35
|
+
this.runtimeSpineContracts = runtimeSpineContracts
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async mapProperty({ overrides, options, property }: { overrides: any, options: any, property: any }) {
|
|
39
|
+
if (property.definition.type === CapsulePropertyTypes.Mapping) {
|
|
40
|
+
await this.mapMappingProperty({ overrides, options, property })
|
|
41
|
+
} else if (
|
|
42
|
+
property.definition.type === CapsulePropertyTypes.String ||
|
|
43
|
+
property.definition.type === CapsulePropertyTypes.Literal
|
|
44
|
+
) {
|
|
45
|
+
this.mapLiteralProperty({ property })
|
|
46
|
+
} else if (property.definition.type === CapsulePropertyTypes.Function) {
|
|
47
|
+
this.mapFunctionProperty({ property })
|
|
48
|
+
} else if (property.definition.type === CapsulePropertyTypes.GetterFunction) {
|
|
49
|
+
this.mapGetterFunctionProperty({ property })
|
|
50
|
+
} else if (property.definition.type === CapsulePropertyTypes.StructInit) {
|
|
51
|
+
this.mapStructInitProperty({ property })
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
protected getApiTarget({ property }: { property: any }) {
|
|
56
|
+
// Properties under '#' go directly on the API
|
|
57
|
+
// Properties under '#<uri>' go under api['#<uri>']
|
|
58
|
+
if (!property.propertyContractUri || property.propertyContractUri === '#') {
|
|
59
|
+
return this.encapsulatedApi
|
|
60
|
+
} else {
|
|
61
|
+
// Namespace under the property contract key
|
|
62
|
+
if (!this.encapsulatedApi[property.propertyContractUri]) {
|
|
63
|
+
this.encapsulatedApi[property.propertyContractUri] = {}
|
|
64
|
+
}
|
|
65
|
+
return this.encapsulatedApi[property.propertyContractUri]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
protected async resolveMappedCapsule({ property }: { property: any }) {
|
|
70
|
+
let mappedCapsule
|
|
71
|
+
|
|
72
|
+
if (typeof property.definition.value === 'string') {
|
|
73
|
+
if (!this.resolve) throw new Error(`'resolve' not set!`)
|
|
74
|
+
if (!this.spineFilesystemRoot) throw new Error(`'spineFilesystemRoot' not set!`)
|
|
75
|
+
if (!this.importCapsule) throw new Error(`'importCapsule' not set!`)
|
|
76
|
+
|
|
77
|
+
// Use encapsulateOptions.moduleFilepath (always available) instead of cst.source.moduleFilepath
|
|
78
|
+
const moduleFilepath = this.capsule.encapsulateOptions?.moduleFilepath || this.capsule.cst?.source?.moduleFilepath
|
|
79
|
+
if (!moduleFilepath) throw new Error(`'moduleFilepath' not available on capsule!`)
|
|
80
|
+
|
|
81
|
+
const parentPath = join(this.spineFilesystemRoot, moduleFilepath)
|
|
82
|
+
const filepath = await this.resolve(property.definition.value, parentPath)
|
|
83
|
+
mappedCapsule = await this.importCapsule(filepath)
|
|
84
|
+
} else if (
|
|
85
|
+
typeof property.definition.value === 'object' &&
|
|
86
|
+
typeof property.definition.value.capsuleSourceLineRef === 'string'
|
|
87
|
+
) {
|
|
88
|
+
mappedCapsule = property.definition.value
|
|
89
|
+
} else {
|
|
90
|
+
throw new Error(`Unknown mapping value for property '${property.name}'!`)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return mappedCapsule
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
protected async extractConstants({ mappedCapsule }: { mappedCapsule: any }) {
|
|
97
|
+
const constants: Record<string, any> = {}
|
|
98
|
+
|
|
99
|
+
const spineContractDef = mappedCapsule.definition[this.spineContractUri]
|
|
100
|
+
|
|
101
|
+
if (!spineContractDef) {
|
|
102
|
+
throw new Error(`Spine contract definition not found for URI: ${this.spineContractUri}. Available keys: ${Object.keys(mappedCapsule.definition).join(', ')}`)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Iterate through all keys in the spine contract definition
|
|
106
|
+
for (const [key, value] of Object.entries(spineContractDef)) {
|
|
107
|
+
if (key.startsWith('#')) {
|
|
108
|
+
// This is a property contract - iterate through its properties
|
|
109
|
+
for (const [prop, propDef] of Object.entries(value as Record<string, any>)) {
|
|
110
|
+
const { type, value: propValue } = propDef as any
|
|
111
|
+
|
|
112
|
+
if (typeof propValue === 'undefined') continue
|
|
113
|
+
|
|
114
|
+
if (
|
|
115
|
+
type === CapsulePropertyTypes.String ||
|
|
116
|
+
type === CapsulePropertyTypes.Literal
|
|
117
|
+
) {
|
|
118
|
+
constants[prop] = propValue
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
// Regular property (backwards compatibility)
|
|
123
|
+
const { type, value: propValue } = value as any
|
|
124
|
+
|
|
125
|
+
if (typeof propValue === 'undefined') continue
|
|
126
|
+
|
|
127
|
+
if (
|
|
128
|
+
type === CapsulePropertyTypes.String ||
|
|
129
|
+
type === CapsulePropertyTypes.Literal
|
|
130
|
+
) {
|
|
131
|
+
constants[key] = propValue
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return constants
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
protected async mapMappingProperty({ overrides, options, property }: { overrides: any, options: any, property: any }) {
|
|
140
|
+
const mappedCapsule = await this.resolveMappedCapsule({ property })
|
|
141
|
+
const constants = await this.extractConstants({ mappedCapsule })
|
|
142
|
+
|
|
143
|
+
// delegateOptions is set by encapsulate.ts for property contract delegates
|
|
144
|
+
// options can be a function or an object for regular mappings
|
|
145
|
+
const mappingOptions = property.definition.delegateOptions
|
|
146
|
+
|| (typeof property.definition.options === 'function'
|
|
147
|
+
? await property.definition.options({ constants })
|
|
148
|
+
: property.definition.options)
|
|
149
|
+
|
|
150
|
+
// Check for existing instance in registry - reuse if available when no options
|
|
151
|
+
// Pre-registration with null allows parent capsules to "claim" a slot before child capsules process
|
|
152
|
+
const capsuleName = mappedCapsule.encapsulateOptions?.capsuleName
|
|
153
|
+
|
|
154
|
+
if (capsuleName && this.instanceRegistry) {
|
|
155
|
+
if (this.instanceRegistry.has(capsuleName)) {
|
|
156
|
+
const existingEntry = this.instanceRegistry.get(capsuleName)
|
|
157
|
+
|
|
158
|
+
// Only reuse if current mapping has no options
|
|
159
|
+
if (!mappingOptions) {
|
|
160
|
+
// Use deferred proxy that resolves from registry when accessed
|
|
161
|
+
// Works for both null (pre-registered) and actual instances
|
|
162
|
+
const apiTarget = this.getApiTarget({ property })
|
|
163
|
+
const registry = this.instanceRegistry
|
|
164
|
+
apiTarget[property.name] = new Proxy({} as any, {
|
|
165
|
+
get: (_target: any, apiProp: string | symbol) => {
|
|
166
|
+
if (typeof apiProp === 'symbol') return undefined
|
|
167
|
+
const resolvedInstance = registry.get(capsuleName)
|
|
168
|
+
if (!resolvedInstance) {
|
|
169
|
+
throw new Error(`Capsule instance not yet resolved: ${capsuleName}`)
|
|
170
|
+
}
|
|
171
|
+
// Access through .api if it exists (for capsule instances with getters)
|
|
172
|
+
if (resolvedInstance.api && apiProp in resolvedInstance.api) {
|
|
173
|
+
return resolvedInstance.api[apiProp]
|
|
174
|
+
}
|
|
175
|
+
return resolvedInstance[apiProp]
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
this.self[property.name] = new Proxy({} as any, {
|
|
179
|
+
get: (_target, prop) => {
|
|
180
|
+
if (typeof prop === 'symbol') return undefined
|
|
181
|
+
const resolvedInstance = registry.get(capsuleName)
|
|
182
|
+
if (!resolvedInstance) {
|
|
183
|
+
throw new Error(`Capsule instance not yet resolved: ${capsuleName}`)
|
|
184
|
+
}
|
|
185
|
+
const value = resolvedInstance.api?.[prop] ?? resolvedInstance[prop]
|
|
186
|
+
if (value && typeof value === 'object' && value.api) {
|
|
187
|
+
return value.api
|
|
188
|
+
}
|
|
189
|
+
return value
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
return
|
|
193
|
+
}
|
|
194
|
+
// If current mapping has options, fall through to create new instance
|
|
195
|
+
} else {
|
|
196
|
+
// Pre-register as null to claim the slot for this capsule
|
|
197
|
+
this.instanceRegistry.set(capsuleName, null)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Transform overrides if this mapping has a propertyContractDelegate
|
|
202
|
+
let mappedOverrides = overrides
|
|
203
|
+
if (property.definition.propertyContractDelegate) {
|
|
204
|
+
// Extract overrides for the delegate property contract and map them to '#'
|
|
205
|
+
// Try both capsuleSourceLineRef and capsuleName
|
|
206
|
+
const delegateOverrides =
|
|
207
|
+
overrides?.[this.capsule.encapsulateOptions.capsuleSourceLineRef]?.[property.definition.propertyContractDelegate] ||
|
|
208
|
+
(this.capsule.encapsulateOptions.capsuleName && overrides?.[this.capsule.encapsulateOptions.capsuleName]?.[property.definition.propertyContractDelegate])
|
|
209
|
+
|
|
210
|
+
if (delegateOverrides) {
|
|
211
|
+
mappedOverrides = {
|
|
212
|
+
...overrides,
|
|
213
|
+
[mappedCapsule.capsuleSourceLineRef]: {
|
|
214
|
+
'#': delegateOverrides
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (mappedCapsule.encapsulateOptions.capsuleName) {
|
|
218
|
+
mappedOverrides[mappedCapsule.encapsulateOptions.capsuleName] = {
|
|
219
|
+
'#': delegateOverrides
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const apiTarget = this.getApiTarget({ property })
|
|
226
|
+
const mappedInstance = await mappedCapsule.makeInstance({
|
|
227
|
+
overrides: mappedOverrides,
|
|
228
|
+
options: mappingOptions,
|
|
229
|
+
runtimeSpineContracts: this.runtimeSpineContracts
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
// Register the instance (replaces null pre-registration marker)
|
|
233
|
+
// Always register to make instance available for child capsules with deferred proxies
|
|
234
|
+
if (capsuleName && this.instanceRegistry) {
|
|
235
|
+
this.instanceRegistry.set(capsuleName, mappedInstance)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
apiTarget[property.name] = mappedInstance
|
|
239
|
+
this.mappedCapsuleInstances.push(mappedInstance)
|
|
240
|
+
// Use proxy to unwrap .api for this.self so internal references work
|
|
241
|
+
this.self[property.name] = mappedInstance.api ? new Proxy(mappedInstance.api, {
|
|
242
|
+
get: (target, prop) => {
|
|
243
|
+
const value = target[prop]
|
|
244
|
+
// Recursively unwrap nested .api objects
|
|
245
|
+
if (value && typeof value === 'object' && value.api) {
|
|
246
|
+
return value.api
|
|
247
|
+
}
|
|
248
|
+
return value
|
|
249
|
+
}
|
|
250
|
+
}) : mappedInstance
|
|
251
|
+
|
|
252
|
+
// If this mapping has a propertyContractDelegate, also mount the mapped capsule's API
|
|
253
|
+
// to the property contract namespace for direct access
|
|
254
|
+
if (property.definition.propertyContractDelegate) {
|
|
255
|
+
// Create the property contract namespace if it doesn't exist
|
|
256
|
+
if (!this.encapsulatedApi[property.definition.propertyContractDelegate]) {
|
|
257
|
+
this.encapsulatedApi[property.definition.propertyContractDelegate] = {}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Mount all properties from the mapped capsule's API to the property contract namespace
|
|
261
|
+
const delegateTarget = this.encapsulatedApi[property.definition.propertyContractDelegate]
|
|
262
|
+
for (const [key, value] of Object.entries(mappedInstance.api)) {
|
|
263
|
+
delegateTarget[key] = value
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
protected mapLiteralProperty({ property }: { property: any }) {
|
|
269
|
+
const apiTarget = this.getApiTarget({ property })
|
|
270
|
+
// Use existing value from self if defined, otherwise use property definition
|
|
271
|
+
// This preserves values set by child capsules in the extends chain
|
|
272
|
+
const existingValue = this.self[property.name]
|
|
273
|
+
const value = existingValue !== undefined
|
|
274
|
+
? existingValue
|
|
275
|
+
: property.definition.value
|
|
276
|
+
|
|
277
|
+
// Assign to both apiTarget and self so getter functions can access via this
|
|
278
|
+
apiTarget[property.name] = value
|
|
279
|
+
// Only update self if it wasn't already set (preserve child values)
|
|
280
|
+
if (existingValue === undefined) {
|
|
281
|
+
this.self[property.name] = value
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
protected createSelfProxy() {
|
|
286
|
+
const extendedApi = this.extendedCapsuleInstance?.api
|
|
287
|
+
const ownSelf = this.ownSelf
|
|
288
|
+
return new Proxy(this.self, {
|
|
289
|
+
get: (target: any, prop: string | symbol) => {
|
|
290
|
+
if (typeof prop === 'symbol') return target[prop]
|
|
291
|
+
|
|
292
|
+
// 'self' property returns ownSelf (only this capsule's own properties)
|
|
293
|
+
if (prop === 'self' && ownSelf) {
|
|
294
|
+
return ownSelf
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// First check if the property exists in target (this.self)
|
|
298
|
+
if (prop in target) {
|
|
299
|
+
return target[prop]
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Fall back to encapsulatedApi
|
|
303
|
+
if (prop in this.encapsulatedApi) {
|
|
304
|
+
return this.encapsulatedApi[prop]
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Fall back to extended capsule's API
|
|
308
|
+
if (extendedApi && prop in extendedApi) {
|
|
309
|
+
return extendedApi[prop]
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return undefined
|
|
313
|
+
}
|
|
314
|
+
})
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
protected mapFunctionProperty({ property }: { property: any }) {
|
|
318
|
+
const apiTarget = this.getApiTarget({ property })
|
|
319
|
+
const selfProxy = this.createSelfProxy()
|
|
320
|
+
apiTarget[property.name] = property.definition.value.bind(selfProxy)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
protected mapGetterFunctionProperty({ property }: { property: any }) {
|
|
324
|
+
const apiTarget = this.getApiTarget({ property })
|
|
325
|
+
const getterFn = property.definition.value
|
|
326
|
+
const selfProxy = this.createSelfProxy()
|
|
327
|
+
|
|
328
|
+
// Define a lazy getter that calls the function only when accessed with proper this context
|
|
329
|
+
Object.defineProperty(apiTarget, property.name, {
|
|
330
|
+
get: () => {
|
|
331
|
+
return getterFn.call(selfProxy)
|
|
332
|
+
},
|
|
333
|
+
enumerable: true,
|
|
334
|
+
configurable: true
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
// Also define the getter on ownSelf so this.self.propertyName works for getter functions
|
|
338
|
+
// This ensures this.self accesses the getter, not a raw value
|
|
339
|
+
if (this.ownSelf) {
|
|
340
|
+
Object.defineProperty(this.ownSelf, property.name, {
|
|
341
|
+
get: () => {
|
|
342
|
+
return getterFn.call(selfProxy)
|
|
343
|
+
},
|
|
344
|
+
enumerable: true,
|
|
345
|
+
configurable: true
|
|
346
|
+
})
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
protected mapStructInitProperty({ property }: { property: any }) {
|
|
351
|
+
const selfProxy = this.createSelfProxy()
|
|
352
|
+
const boundFunction = property.definition.value.bind(selfProxy)
|
|
353
|
+
this.structInitFunctions.push(boundFunction)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async freeze(options: any): Promise<any> {
|
|
357
|
+
return this.freezeCapsule?.(options) || {}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
export function CapsuleSpineContract({ freezeCapsule, resolve, importCapsule, spineFilesystemRoot }: { freezeCapsule?: (capsule: any) => Promise<any>, resolve?: (uri: string, parentFilepath: string) => Promise<string>, importCapsule?: (filepath: string) => Promise<any>, spineFilesystemRoot?: string } = {}) {
|
|
366
|
+
|
|
367
|
+
const instanceRegistry: CapsuleInstanceRegistry = new Map()
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
'#': CapsuleSpineContract['#'],
|
|
371
|
+
instanceRegistry,
|
|
372
|
+
makeContractCapsuleInstance: ({ spineContractUri, capsule, self, ownSelf, encapsulatedApi, extendedCapsuleInstance, runtimeSpineContracts }: { spineContractUri: string, capsule: any, self: any, ownSelf?: any, encapsulatedApi: Record<string, any>, extendedCapsuleInstance?: any, runtimeSpineContracts?: Record<string, any> }) => {
|
|
373
|
+
return new ContractCapsuleInstanceFactory({
|
|
374
|
+
spineContractUri,
|
|
375
|
+
capsule,
|
|
376
|
+
self,
|
|
377
|
+
ownSelf,
|
|
378
|
+
encapsulatedApi,
|
|
379
|
+
resolve,
|
|
380
|
+
importCapsule,
|
|
381
|
+
spineFilesystemRoot,
|
|
382
|
+
freezeCapsule,
|
|
383
|
+
instanceRegistry,
|
|
384
|
+
extendedCapsuleInstance,
|
|
385
|
+
runtimeSpineContracts
|
|
386
|
+
})
|
|
387
|
+
},
|
|
388
|
+
hydrate: ({ capsuleSnapshot }: { capsuleSnapshot: any }): any => {
|
|
389
|
+
|
|
390
|
+
return capsuleSnapshot
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
CapsuleSpineContract['#'] = '@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0'
|