@stream44.studio/encapsulate 0.4.0-rc.11 → 0.4.0-rc.13

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.
@@ -17,10 +17,11 @@ export class ContractCapsuleInstanceFactory {
17
17
  protected extendedCapsuleInstance?: any
18
18
  protected ownSelf?: any
19
19
  protected runtimeSpineContracts?: Record<string, any>
20
+ protected capsuleInstance?: any
20
21
  public structInitFunctions: Array<() => any> = []
21
22
  public mappedCapsuleInstances: Array<any> = []
22
23
 
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
+ constructor({ spineContractUri, capsule, self, ownSelf, encapsulatedApi, resolve, importCapsule, spineFilesystemRoot, freezeCapsule, instanceRegistry, extendedCapsuleInstance, runtimeSpineContracts, capsuleInstance }: { 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>, capsuleInstance?: any }) {
24
25
  this.spineContractUri = spineContractUri
25
26
  this.capsule = capsule
26
27
  this.self = self
@@ -33,6 +34,7 @@ export class ContractCapsuleInstanceFactory {
33
34
  this.instanceRegistry = instanceRegistry
34
35
  this.extendedCapsuleInstance = extendedCapsuleInstance
35
36
  this.runtimeSpineContracts = runtimeSpineContracts
37
+ this.capsuleInstance = capsuleInstance
36
38
  }
37
39
 
38
40
  async mapProperty({ overrides, options, property }: { overrides: any, options: any, property: any }) {
@@ -40,7 +42,8 @@ export class ContractCapsuleInstanceFactory {
40
42
  await this.mapMappingProperty({ overrides, options, property })
41
43
  } else if (
42
44
  property.definition.type === CapsulePropertyTypes.String ||
43
- property.definition.type === CapsulePropertyTypes.Literal
45
+ property.definition.type === CapsulePropertyTypes.Literal ||
46
+ property.definition.type === CapsulePropertyTypes.Constant
44
47
  ) {
45
48
  this.mapLiteralProperty({ property })
46
49
  } else if (property.definition.type === CapsulePropertyTypes.Function) {
@@ -226,7 +229,8 @@ export class ContractCapsuleInstanceFactory {
226
229
  const mappedInstance = await mappedCapsule.makeInstance({
227
230
  overrides: mappedOverrides,
228
231
  options: mappingOptions,
229
- runtimeSpineContracts: this.runtimeSpineContracts
232
+ runtimeSpineContracts: this.runtimeSpineContracts,
233
+ rootCapsule: this.capsuleInstance?.rootCapsule
230
234
  })
231
235
 
232
236
  // Register the instance (replaces null pre-registration marker)
@@ -369,7 +373,7 @@ export function CapsuleSpineContract({ freezeCapsule, resolve, importCapsule, sp
369
373
  return {
370
374
  '#': CapsuleSpineContract['#'],
371
375
  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> }) => {
376
+ makeContractCapsuleInstance: ({ spineContractUri, capsule, self, ownSelf, encapsulatedApi, extendedCapsuleInstance, runtimeSpineContracts, capsuleInstance }: { spineContractUri: string, capsule: any, self: any, ownSelf?: any, encapsulatedApi: Record<string, any>, extendedCapsuleInstance?: any, runtimeSpineContracts?: Record<string, any>, capsuleInstance?: any }) => {
373
377
  return new ContractCapsuleInstanceFactory({
374
378
  spineContractUri,
375
379
  capsule,
@@ -382,7 +386,8 @@ export function CapsuleSpineContract({ freezeCapsule, resolve, importCapsule, sp
382
386
  freezeCapsule,
383
387
  instanceRegistry,
384
388
  extendedCapsuleInstance,
385
- runtimeSpineContracts
389
+ runtimeSpineContracts,
390
+ capsuleInstance
386
391
  })
387
392
  },
388
393
  hydrate: ({ capsuleSnapshot }: { capsuleSnapshot: any }): any => {
@@ -212,9 +212,42 @@ async function resolve(uri: string, fromPath: string, spineRoot?: string): Promi
212
212
 
213
213
  // Non-scoped bare specifier — try node_modules resolution from fromPath
214
214
  if (!uri.startsWith('.') && !uri.startsWith('/')) {
215
- // Walk up from fromPath looking for node_modules
215
+ // Parse package name and subpath (e.g., "t44/caps/WorkspaceCli" -> pkg="t44", subpath="caps/WorkspaceCli")
216
+ const slashIdx = uri.indexOf('/')
217
+ const pkg = slashIdx === -1 ? uri : uri.slice(0, slashIdx)
218
+ const subpath = slashIdx === -1 ? undefined : uri.slice(slashIdx + 1)
219
+
220
+ // Walk up from fromPath looking for self-package or node_modules
216
221
  let dir = dirname(fromPath)
217
222
  while (true) {
223
+ // Check if this directory's package.json matches the requested package (self-package resolution)
224
+ try {
225
+ const pjPath = join(dir, 'package.json')
226
+ const pj = JSON.parse(await readFile(pjPath, 'utf-8'))
227
+ if (pj.name === pkg) {
228
+ if (subpath) {
229
+ if (pj.exports) {
230
+ const exportKey = './' + subpath
231
+ const exportValue = pj.exports[exportKey]
232
+ if (typeof exportValue === 'string') {
233
+ return pathResolve(dir, exportValue)
234
+ }
235
+ }
236
+ const fsPath = join(dir, subpath + '.ts')
237
+ try { await stat(fsPath); return fsPath } catch { }
238
+ try { await stat(join(dir, subpath)); return join(dir, subpath) } catch { }
239
+ } else if (pj.exports?.['.']) {
240
+ const mainExport = pj.exports['.']
241
+ if (typeof mainExport === 'string') {
242
+ return pathResolve(dir, mainExport)
243
+ }
244
+ } else if (pj.main) {
245
+ return pathResolve(dir, pj.main)
246
+ }
247
+ }
248
+ } catch { }
249
+
250
+ // Check node_modules
218
251
  const candidate = join(dir, 'node_modules', uri)
219
252
  try {
220
253
  const s = await stat(candidate)
@@ -499,7 +532,7 @@ export async function CapsuleSpineFactory({
499
532
 
500
533
  timing?.recordMajor('CAPSULE SPINE FACTORY: READY')
501
534
 
502
- const loadCapsule = async ({ capsuleSnapshot }: { capsuleSourceLineRef: string, capsuleSnapshot: any }) => {
535
+ const loadCapsule = async ({ capsuleSnapshot, cacheBustVersion }: { capsuleSourceLineRef: string, capsuleSnapshot: any, cacheBustVersion?: number }) => {
503
536
 
504
537
  if (!capsuleModuleProjectionRoot) {
505
538
  throw new Error('capsuleModuleProjectionRoot must be provided to enable dynamic loading of capsules')
@@ -509,6 +542,11 @@ export async function CapsuleSpineFactory({
509
542
 
510
543
  if (!filepath) throw new Error(`Cannot load capsule. No 'filepath' found at 'spineContracts["#@stream44.studio/encapsulate/spine-contracts/CapsuleSpineContract.v0"]["#@stream44.studio/encapsulate/structs/Capsule"].projectedCapsuleFilepath'!`)
511
544
 
545
+ // Check cache bust version - if it doesn't match, return null to trigger regeneration
546
+ if (cacheBustVersion !== undefined && capsuleSnapshot.cst?.cacheBustVersion !== cacheBustVersion) {
547
+ return null
548
+ }
549
+
512
550
  const { capsule } = await import(join(capsuleModuleProjectionRoot, filepath))
513
551
 
514
552
  return capsule
@@ -529,6 +567,7 @@ export async function CapsuleSpineFactory({
529
567
 
530
568
  const result = await SpineRuntime({
531
569
  snapshot,
570
+ spineFilesystemRoot,
532
571
  spineContracts: spineContractInstances.runtime,
533
572
  loadCapsule
534
573
  })
@@ -235,10 +235,18 @@ export function StaticAnalyzer({
235
235
  ])
236
236
 
237
237
  if (cstsContent && crtsContent) {
238
- timing?.record(`StaticAnalyzer: Cache HIT for ${encapsulateOptions.moduleFilepath}`)
239
- return {
240
- csts: JSON.parse(cstsContent),
241
- crts: JSON.parse(crtsContent)
238
+ const cachedCsts = JSON.parse(cstsContent)
239
+
240
+ // Check cache bust version - if mismatch, regenerate
241
+ const cachedVersion = cachedCsts?.[capsuleSourceLineRef]?.cacheBustVersion
242
+ if (encapsulateOptions.cacheBustVersion !== undefined && cachedVersion !== encapsulateOptions.cacheBustVersion) {
243
+ timing?.record(timing?.chalk?.red?.(`StaticAnalyzer: Cache BUST (version mismatch: ${cachedVersion} !== ${encapsulateOptions.cacheBustVersion}) for ${encapsulateOptions.moduleFilepath}`))
244
+ } else {
245
+ timing?.record(`StaticAnalyzer: Cache HIT for ${encapsulateOptions.moduleFilepath}`)
246
+ return {
247
+ csts: cachedCsts,
248
+ crts: JSON.parse(crtsContent)
249
+ }
242
250
  }
243
251
  }
244
252
  }
@@ -340,6 +348,7 @@ export function StaticAnalyzer({
340
348
  )
341
349
 
342
350
  const cst: any = {
351
+ cacheBustVersion: encapsulateOptions.cacheBustVersion || 1,
343
352
  capsuleSourceLineRef,
344
353
  capsuleSourceNameRef,
345
354
  capsuleSourceNameRefHash,