Last active
May 2, 2025 15:19
-
-
Save Grubba27/e128fe81fe2eb255919c826db57cdf18 to your computer and use it in GitHub Desktop.
Meteor methods with decorators
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// .babelrc needs this config at least: | |
// { | |
// "plugins": [ | |
// ["@babel/plugin-transform-class-static-block"], | |
// ["@babel/plugin-proposal-decorators", { "version": "2023-11" }] | |
// ] | |
// } | |
import { Meteor } from 'meteor/meteor'; | |
const makeMethodName = (namespace, methodName) => { | |
if (namespace) { | |
return `${namespace.toLowerCase()}.${methodName}`; | |
} | |
return methodName; | |
} | |
const safeAddMethod = (methodName, method) => { | |
if (Meteor.isServer && !Meteor.server.method_handlers[methodName]) { | |
Meteor.methods({[methodName]: method}); | |
} | |
} | |
function expose(target, context) { | |
if (context.kind === "class") { | |
const className = context.name; | |
const methods = Object.getOwnPropertyNames(target.prototype).filter( | |
(name) => name !== "constructor" && !name.startsWith("_") | |
); | |
methods.forEach((methodName) => { | |
const method = target.prototype[methodName] | |
const functionName = makeMethodName(className, methodName); | |
safeAddMethod(functionName, method); | |
}); | |
} | |
} | |
function rpc(target, context, ) { | |
if (context.kind === "method") { | |
const functionName = context.name; | |
context.metadata.isRpc = true; | |
return function (...args) { | |
const methodName = makeMethodName(this.constructor.name, functionName); | |
safeAddMethod(methodName, target) | |
return target.apply(this, args); | |
}; | |
} | |
} | |
function params(...types) { | |
return (target, context) => { | |
if (context.kind === "method") { | |
context.metadata.params = types; | |
return function (...args) { | |
for (let i = 0; i < types.length; i++) { | |
const type = types[i]; | |
const arg = args[i]; | |
try { | |
const isOk = new type(arg); | |
if (isNaN(isOk)) { | |
throw new Meteor.Error(`Return value should be of type ${type}`) | |
} | |
} catch (e) { | |
throw new Meteor.Error(`Argument ${i} should be of type ${type}`); | |
} | |
} | |
return target.apply(this, args); | |
}; | |
} | |
} | |
} | |
function returns(type) { | |
return (target, context) => { | |
if (context.kind === "method") { | |
context.metadata.returns = type; | |
return async function (...args) { | |
const r = await target.apply(this, args); | |
try { | |
const isOk = new type(r); | |
if (isNaN(isOk)) { | |
throw new Meteor.Error(`Return value should be of type ${type}`) | |
} | |
} catch (e) { | |
throw new Meteor.Error(`Return value should be of type ${type}`); | |
} | |
return r; | |
}; | |
} | |
} | |
} | |
@expose | |
class Counter { | |
@params(Number) | |
@returns(Number) | |
async add(count) { | |
return count + 1 | |
} | |
@params(String, String) | |
@returns(String) | |
concat(a,b) { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment