Skip to content

Commit

Permalink
Handle time event in model handler
Browse files Browse the repository at this point in the history
  • Loading branch information
PaulLeCam committed Jun 18, 2024
1 parent 1534d3b commit fddbf71
Show file tree
Hide file tree
Showing 14 changed files with 396 additions and 190 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
"@biomejs/biome": "1.8.1",
"@jest/globals": "^29.7.0",
"@swc/cli": "^0.3.12",
"@swc/core": "^1.5.29",
"@swc/core": "^1.6.1",
"@swc/jest": "^0.2.36",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.2",
"@types/node": "^20.14.5",
"del-cli": "^5.1.0",
"jest": "^29.7.0",
"tsx": "^4.15.4",
"turbo": "^2.0.3",
"tsx": "^4.15.6",
"turbo": "^2.0.4",
"typescript": "^5.4.5"
},
"pnpm": {
Expand Down
2 changes: 1 addition & 1 deletion packages/ethereum-did/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"caip": "^1.1.1",
"did-session": "^3.1.0",
"dids": "^5.0.2",
"viem": "^2.14.0"
"viem": "^2.15.1"
},
"jest": {
"extensionsToTreatAsEsm": [".ts"],
Expand Down
19 changes: 19 additions & 0 deletions packages/events/src/codecs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
decode,
optional,
sparse,
strict,
string,
tuple,
unknown,
Expand Down Expand Up @@ -78,3 +79,21 @@ export function assertSignedEvent(
): asserts input is SignedEvent {
decodeSignedEvent(input)
}

export const TimeEvent = strict(
{
id: cid,
prev: cid,
proof: cid,
path: string,
},
'TimeEvent',
)
export type TimeEvent = TypeOf<typeof TimeEvent>

export function decodeTimeEvent(input: unknown): TimeEvent {
return decode(TimeEvent, input)
}
export function assertTimeEvent(input: unknown): asserts input is TimeEvent {
decodeTimeEvent(input)
}
3 changes: 3 additions & 0 deletions packages/events/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ export {
GenericEventHeader,
InitEventHeader,
SignedEvent,
TimeEvent,
assertSignedEvent,
assertTimeEvent,
decodeSignedEvent,
decodeTimeEvent,
} from './codecs.js'
export {
type EventContainer,
Expand Down
4 changes: 3 additions & 1 deletion packages/model-handler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@
},
"devDependencies": {
"@ceramic-sdk/ethereum-did": "workspace:^",
"@ceramic-sdk/identifiers": "workspace:^",
"@ceramic-sdk/key-did": "workspace:^",
"@didtools/codecs": "^3.0.0",
"@types/lodash.ismatch": "^4.4.9",
"json-schema-typed": "^8.0.1"
"json-schema-typed": "^8.0.1",
"multiformats": "^13.1.1"
},
"jest": {
"extensionsToTreatAsEsm": [".ts"],
Expand Down
57 changes: 48 additions & 9 deletions packages/model-handler/src/handler.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
import {
type SignedEvent,
SignedEvent,
type SignedEventContainer,
TimeEvent,
signedEventToContainer,
} from '@ceramic-sdk/events'
import {
type ModelEvent,
ModelInitEventPayload,
ModelMetadata,
type ModelState,
assertValidModelContent,
getModelStreamID,
validateController,
} from '@ceramic-sdk/model-protocol'
import type { DID } from 'dids'
import type { CID } from 'multiformats/cid'

import {
validateImplementedInterfaces,
validateInterface,
} from './interfaces-validation.js'
import type { Context } from './types.js'
import type { Context, InitContext, TimeContext } from './types.js'

export async function getInitEventContainer(
verifier: DID,
Expand All @@ -27,8 +29,9 @@ export async function getInitEventContainer(
}

export async function handleInitEvent(
cid: CID,
event: SignedEvent,
context: Context,
context: InitContext,
): Promise<ModelState> {
const { payload } = await getInitEventContainer(context.verifier, event)

Expand All @@ -47,10 +50,46 @@ export async function handleInitEvent(
await validateImplementedInterfaces(content, context)
}

const streamID = getModelStreamID({
data: payload.data,
header: payload.header,
})
return {
cid,
content,
metadata,
log: [event],
}
}

return { id: streamID.toString(), content, metadata, log: [event] }
export async function handleTimeEvent(
cid: CID,
event: TimeEvent,
context: TimeContext,
): Promise<ModelState> {
const state = await context.getModelState(event.id)
if (!state.cid.equals(event.id)) {
throw new Error(
`Invalid state with model ${state.cid} provided for time event ${cid}: expected model ${event.id}`,
)
}

const init = state.log[0]
if (init == null) {
throw new Error(
`Invalid state for model ${state.cid} provided for time event ${cid}: no events in log`,
)
}

return { ...state, log: [...state.log, event] }
}

export async function handleEvent(
cid: CID,
event: ModelEvent,
context: Context,
): Promise<ModelState> {
if (SignedEvent.is(event)) {
return await handleInitEvent(cid, event, context)
}
if (TimeEvent.is(event)) {
return await handleTimeEvent(cid, event, context)
}
throw new Error(`Unsupported event: ${cid}`)
}
6 changes: 3 additions & 3 deletions packages/model-handler/src/interfaces-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { JsonReference } from 'json-ptr'
import type { JSONSchema } from 'json-schema-typed/draft-2020-12'
import isMatch from 'lodash.ismatch'

import type { Context } from './types.js'
import type { InitContext } from './types.js'

export type Schema = Exclude<JSONSchema, boolean>

Expand Down Expand Up @@ -740,15 +740,15 @@ export function validateInterfaceImplementation(

export async function validateImplementedInterfaces(
model: ModelDefinition,
context: Context,
context: InitContext,
): Promise<void> {
const errors: Array<Error> = []

const toValidate = ((model as ModelDefinitionV2).implements ?? []).map(
async (interfaceID) => {
try {
const interfaceDefinition =
await context.loadModelDefinition(interfaceID)
await context.getModelDefinition(interfaceID)
validateInterfaceImplementation(interfaceID, interfaceDefinition, model)
} catch (error) {
errors.push(error as Error)
Expand Down
13 changes: 10 additions & 3 deletions packages/model-handler/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import type { ModelDefinition } from '@ceramic-sdk/model-protocol'
import type { ModelDefinition, ModelState } from '@ceramic-sdk/model-protocol'
import type { DID } from 'dids'
import type { CID } from 'multiformats/cid'

export type Context = {
loadModelDefinition: (id: string) => Promise<ModelDefinition>
export type InitContext = {
getModelDefinition: (id: string) => Promise<ModelDefinition>
verifier: DID
}

export type TimeContext = {
getModelState: (cid: CID) => Promise<ModelState>
}

export type Context = InitContext & TimeContext
Loading

0 comments on commit fddbf71

Please sign in to comment.