Skip to content

Commit

Permalink
Decode the rest of the notification
Browse files Browse the repository at this point in the history
  • Loading branch information
thewilkybarkid committed Dec 4, 2023
1 parent 588927a commit 0509358
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 0 deletions.
16 changes: 16 additions & 0 deletions package-lock.json

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

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
"@effect/platform-node": "^0.33.5",
"@effect/schema": "^0.51.3",
"@js-temporal/polyfill": "^0.4.4",
"doi-regex": "^0.1.13",
"effect": "^2.0.0-next.58",
"ioredis": "^5.3.2"
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@tsconfig/node20": "^20.1.2",
"@types/doi-regex": "^0.1.3",
"@types/node": "^20.10.3",
"@typescript-eslint/eslint-plugin": "^6.13.1",
"@typescript-eslint/parser": "^6.13.1",
Expand Down
22 changes: 22 additions & 0 deletions src/CoarNotify.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
import { Schema } from '@effect/schema'
import * as Doi from './Doi.js'
import * as Url from './Url.js'

export const ReviewActionSchema = Schema.struct({
'@context': Schema.tuple(
Schema.literal('https://www.w3.org/ns/activitystreams'),
Schema.literal('https://purl.org/coar/notify'),
),
id: Schema.string,
type: Schema.tuple(Schema.literal('Offer'), Schema.literal('coar-notify:ReviewAction')),
origin: Schema.struct({
id: Url.UrlFromStringSchema(Schema.string),
inbox: Url.UrlFromStringSchema(Schema.string),
type: Schema.literal('Organization', 'Service'),
}),
target: Schema.struct({
id: Url.UrlFromStringSchema(Schema.string),
inbox: Url.UrlFromStringSchema(Schema.string),
type: Schema.literal('Organization', 'Service'),
}),
object: Schema.struct({
id: Schema.string,
'ietf:cite-as': Doi.DoiUrlSchema,
}),
actor: Schema.struct({
id: Url.UrlFromStringSchema(Schema.string),
type: Schema.literal('Application', 'Group', 'Organization', 'Person', 'Service'),
name: Schema.string,
}),
})
32 changes: 32 additions & 0 deletions src/Doi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ParseResult, Schema } from '@effect/schema'
import doiRegex from 'doi-regex'
import { Brand, Either, type Option, type Predicate, String, flow } from 'effect'

export type Doi = Brand.Branded<string, 'Doi'>

const isDoi: Predicate.Refinement<unknown, Doi> = (u): u is Doi =>
typeof u === 'string' && doiRegex({ exact: true }).test(u) && !u.endsWith('/.') && !u.endsWith('/..')

export const Doi = Brand.refined<Doi>(isDoi, s => Brand.error(`Expected ${s} to be a DOI`))

const toUrl: (doi: Doi) => URL = doi => {
const url = new URL('https://doi.org')
url.pathname = doi.replace(/\/(\.{1,2})\//g, '/$1%2F').replace(/\\/g, '%5C')

return url
}

const parse: (s: string) => Option.Option<Doi> = flow(
String.trim,
String.replace(/^(?:https?:\/\/(?:dx\.)?doi\.org\/|doi:)?/i, ''),
s => Doi.option(s),
)

export const DoiSchema = Schema.string.pipe(Schema.fromBrand(Doi))

export const DoiUrlSchema: Schema.Schema<string, Doi> = Schema.transformOrFail(
Schema.string,
Schema.to(DoiSchema),
s => Either.fromOption(parse(s), () => ParseResult.parseError([ParseResult.type(DoiSchema.ast, s)])),
doi => ParseResult.succeed(toUrl(doi).href),
)
16 changes: 16 additions & 0 deletions src/Url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ParseResult, Schema } from '@effect/schema'

export const UrlSchema: Schema.Schema<URL> = Schema.instanceOf(URL)

export const UrlFromStringSchema = <I, A extends string>(self: Schema.Schema<I, A>): Schema.Schema<I, URL> =>
Schema.transformOrFail(
self,
UrlSchema,
(s, _, ast) =>
ParseResult.try({
try: () => new URL(s),
catch: () => ParseResult.parseError([ParseResult.type(ast, s)]),
}),
url => ParseResult.succeed(url.href),
{ strict: false },
)

0 comments on commit 0509358

Please sign in to comment.