Skip to content

Commit

Permalink
feat(platform): use unique identifier for capability and intention ID
Browse files Browse the repository at this point in the history
closes #162, closes #171

BREAKING CHANGE: Using unique identifier for capability and intention ID introduced a breaking change.

Previously, the IDs used for capabilities and intentions were stable but not unique, which caused problems when deregistering capabilities and intentions. If your application requires stable capability identifiers, you can register a capability interceptor, as follows:

```ts
import {Capability, CapabilityInterceptor} from '@scion/microfrontend-platform';
import {Crypto} from '@scion/toolkit/crypto';
import {Beans} from '@scion/toolkit/bean-manager';

Beans.register(CapabilityInterceptor, {
  useValue: new class implements CapabilityInterceptor {
    public async intercept(capability: Capability): Promise<Capability> {
      const stableId = await Crypto.digest(JSON.stringify({
        type: capability.type,
        qualifier: capability.qualifier,
        application: capability.metadata!.appSymbolicName,
      }));
      return {
        ...capability,
        metadata: {...capability.metadata!, id: stableId},
      };
    }
  },
  multi: true
})
```

Note that the communication protocol between host and client has NOT changed. You can independently upgrade host and clients to the new version.
  • Loading branch information
Marcarrian authored and danielwiehl committed Nov 8, 2022
1 parent 1098f8f commit e2957ba
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 23 deletions.
11 changes: 0 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@
"@scion/components": "14.0.2",
"@scion/components.internal": "14.0.1",
"@scion/toolkit": "1.2.1",
"js-sha256": "0.9.0",
"rxjs": "7.5.7",
"tslib": "2.4.0",
"zone.js": "0.11.8"
Expand Down
3 changes: 1 addition & 2 deletions projects/scion/microfrontend-platform/ng-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"entryFile": "src/public-api.ts"
},
"allowedNonPeerDependencies": [
"@scion",
"js-sha256"
"@scion"
]
}
1 change: 0 additions & 1 deletion projects/scion/microfrontend-platform/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"name": "SCION contributors"
},
"dependencies": {
"js-sha256": "^0.9.0",
"tslib": "^2.3.0"
},
"peerDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -686,4 +686,26 @@ describe('ManifestRegistry', () => {
const actual = (await firstValueFrom(Beans.get(ManifestService).lookupCapabilities$({type: 'testee'})))[0];
expect(actual.metadata.id).toEqual('1');
});

it('should use a unique identifier for capability ID', async () => {
await MicrofrontendPlatform.startHost({
host: {symbolicName: 'host-app'},
applications: [],
});

const id1 = await Beans.get(ManifestRegistry).registerCapability({type: 'testee'}, 'host-app');
const id2 = await Beans.get(ManifestRegistry).registerCapability({type: 'testee'}, 'host-app');
expect(id1).not.toEqual(id2);
});

it('should use a unique identifier for intention ID', async () => {
await MicrofrontendPlatform.startHost({
host: {symbolicName: 'host-app'},
applications: [],
});

const id1 = Beans.get(ManifestRegistry).registerIntention({type: 'testee'}, 'host-app');
const id2 = Beans.get(ManifestRegistry).registerIntention({type: 'testee'}, 'host-app');
expect(id1).not.toEqual(id2);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
*/

import {Capability, Intention, ParamDefinition} from '../../platform.model';
import {sha256} from 'js-sha256';
import {ManifestObjectStore} from './manifest-object-store';
import {concatWith, defer, EMPTY, filter, merge, of, Subject} from 'rxjs';
import {distinctUntilChanged, expand, mergeMap, take, takeUntil} from 'rxjs/operators';
Expand All @@ -26,6 +25,7 @@ import {Logger, LoggingContext} from '../../logger';
import {ManifestObjectFilter} from './manifest-object.model';
import {ClientRegistry} from '../client-registry/client.registry';
import {CapabilityInterceptor} from './capability-interceptors';
import {UUID} from '@scion/toolkit/uuid';

export class ɵManifestRegistry implements ManifestRegistry, PreDestroy {

Expand Down Expand Up @@ -113,8 +113,7 @@ export class ɵManifestRegistry implements ManifestRegistry, PreDestroy {
optionalParams: undefined,
private: capability.private ?? true,
metadata: {
// use the first 7 digits of the capability hash as capability id
id: sha256(JSON.stringify({application: appSymbolicName, type: capability.type, ...capability.qualifier})).substring(0, 7),
id: UUID.randomUUID(),
appSymbolicName: appSymbolicName,
},
});
Expand All @@ -133,19 +132,17 @@ export class ɵManifestRegistry implements ManifestRegistry, PreDestroy {
throw Error(`[IntentionRegisterError] Missing required intention.`);
}

// use the first 7 digits of the intention hash as intention id
const intentionId = sha256(JSON.stringify({application: appSymbolicName, type: intention.type, ...intention.qualifier})).substring(0, 7);
const intentionToRegister: Intention = {
...intention,
metadata: {
id: intentionId,
id: UUID.randomUUID(),
appSymbolicName: appSymbolicName,
},
};

// Register the intention.
this._intentionStore.add(intentionToRegister);
return intentionId;
return intentionToRegister.metadata!.id;
}

private unregisterIntention(appSymbolicName: string, filter: ManifestObjectFilter): void {
Expand Down Expand Up @@ -302,7 +299,6 @@ export namespace ManifestRegistryTopics {
export const UnregisterCapabilities = 'ɵUNREGISTER_CAPABILITIES';
export const RegisterIntention = 'ɵREGISTER_INTENTION';
export const UnregisterIntentions = 'ɵUNREGISTER_INTENTIONS';
export const LookupPlatformVersion = 'ɵLOOKUP_PLATFORM_VERSION';

export function platformVersion(appSymbolicName: string): string {
return `ɵapplication/${appSymbolicName}/platform/version`;
Expand Down

0 comments on commit e2957ba

Please sign in to comment.