Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
43 changes: 43 additions & 0 deletions packages/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,45 @@ export type SendSmsParams = {
readonly message: string,
}

export type JobStatus = 'completed' | 'failed' | 'queued' | 'active' | 'cancelled'

export type Job<TType extends keyof Zemble.QueueRegistry> = {
readonly jobId: string
readonly status: JobStatus
readonly type: TType
}

export type Cron = {
readonly recurrencePattern: string
readonly worker: () => Promise<void>
readonly errorHandler?: (error: unknown) => void
}

export type Queue = {
readonly worker: () => Promise<void>
readonly errorHandler?: (error: unknown) => void
}

export interface StartJobParams<TType extends keyof Zemble.QueueRegistry> {
readonly jobId?: string
readonly type: TType
readonly data: Zemble.QueueRegistry[TType]
readonly delayMs?: number
readonly priority?: number
}

type StartCronParams = {
readonly type: string
readonly data: Record<string, JSON>
readonly recurrencePattern: string
}

export type IStandardCronService = (options: StartCronParams) => Promise<Cron>

export type IStandardRemoveFromQueueService = (jobId: string) => Promise<Job<keyof Zemble.QueueRegistry>> | Job<keyof Zemble.QueueRegistry>

export type IStandardAddToQueueService = (options: StartJobParams<keyof Zemble.QueueRegistry>) => Promise<Job<keyof Zemble.QueueRegistry>> | Job<keyof Zemble.QueueRegistry>

export type IStandardSendSmsService = (options: SendSmsParams) => Promise<boolean>

export abstract class IStandardKeyValueService<T = unknown> {
Expand Down Expand Up @@ -257,6 +296,10 @@ declare global {
// readonly UnknownToken: Record<string, unknown>
}

interface QueueRegistry {

}

interface PushTokenRegistry {

}
Expand Down
13 changes: 13 additions & 0 deletions packages/cron-in-memory/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# cron-in-memory

## Develop

```bash
bun dev
```

## Test

```bash
bun test
```
9 changes: 9 additions & 0 deletions packages/cron-in-memory/codegen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import defaultConfig from '@zemble/graphql/codegen'

import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
...defaultConfig,
}

export default config
23 changes: 23 additions & 0 deletions packages/cron-in-memory/graphql/Mutation/randomNumber.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createTestApp } from '@zemble/core/test-utils'
import {
it, expect,
} from 'bun:test'

import plugin from '../../plugin'
import { graphql } from '../client.generated'

const randomNumberMutation = graphql(`
mutation RandomNumber {
randomNumber
}
`)

it('Should return a number', async () => {
const app = await createTestApp(plugin)

const response = await app.gqlRequest(randomNumberMutation, {})
expect(response.data).toEqual({

randomNumber: expect.any(Number),
})
})
11 changes: 11 additions & 0 deletions packages/cron-in-memory/graphql/Mutation/randomNumber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { MutationResolvers } from '../schema.generated'

const randomNumber: MutationResolvers['randomNumber'] = (_, __, { pubsub }) => {
const randomNumber = Math.floor(Math.random() * 1000)

pubsub.publish('randomNumber', randomNumber)

return randomNumber
}

export default randomNumber
21 changes: 21 additions & 0 deletions packages/cron-in-memory/graphql/Query/hello.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createTestApp } from '@zemble/core/test-utils'
import { it, expect } from 'bun:test'

import plugin from '../../plugin'
import { graphql } from '../client.generated'

const HelloWorldQuery = graphql(`
query Hello {
hello
}
`)

it('Should return world!', async () => {
const app = await createTestApp(plugin)

const response = await app.gqlRequest(HelloWorldQuery, {})

expect(response.data).toEqual({
hello: 'world!',
})
})
5 changes: 5 additions & 0 deletions packages/cron-in-memory/graphql/Query/hello.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { QueryResolvers } from '../schema.generated'

const hello: QueryResolvers['hello'] = () => 'world!'

export default hello
20 changes: 20 additions & 0 deletions packages/cron-in-memory/graphql/Subscription/countdown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { SubscriptionResolvers } from '../schema.generated'

const countdown: SubscriptionResolvers['countdown'] = {
// This will return the value on every 1 sec until it reaches 0
// eslint-disable-next-line object-shorthand
subscribe: async function* (_, { from }, { logger }) {
// eslint-disable-next-line no-plusplus
for (let i = from; i >= 0; i--) {
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve) => {
logger.info('countdown', { countdown: i })
setTimeout(resolve, 1000)
})
yield { countdown: i }
}
},
resolve: (payload: unknown) => (payload as { readonly countdown: number}).countdown,
}

export default countdown
15 changes: 15 additions & 0 deletions packages/cron-in-memory/graphql/Subscription/randomNumber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { SubscriptionResolvers } from '../schema.generated'

const randomNumber: SubscriptionResolvers['randomNumber'] = {
// subscribe to the randomNumber event
subscribe: (_, __, { pubsub }) => {
console.log('subscribing to randomNumber')
return pubsub.subscribe('randomNumber')
},
resolve: (payload: number) => {
console.log('resolving randomNumber', payload)
return payload
},
}

export default randomNumber
22 changes: 22 additions & 0 deletions packages/cron-in-memory/graphql/Subscription/tick.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { SubscriptionResolvers } from '../schema.generated'

let initialized = false
const initializeOnce = (pubsub: Zemble.PubSubType) => {
if (initialized) return
initialized = true
setInterval(() => {
pubsub.publish('tick', Date.now())
}, 1000)
}

const tick: SubscriptionResolvers['tick'] = {
// subscribe to the tick event
subscribe: (_, __, { pubsub }) => {
initializeOnce(pubsub)
console.log('subscribing to tick')
return pubsub.subscribe('tick')
},
resolve: (payload: number) => payload,
}

export default tick
154 changes: 154 additions & 0 deletions packages/cron-in-memory/graphql/schema.generated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// @ts-nocheck
import '@zemble/core'
import type { GraphQLResolveInfo } from 'graphql';
export type Maybe<T> = T | null | undefined;
export type InputMaybe<T> = T | null | undefined;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
export type MakeEmpty<T extends { [key: string]: unknown }, K extends keyof T> = { [_ in K]?: never };
export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };
export type RequireFields<T, K extends keyof T> = Omit<T, K> & { [P in K]-?: NonNullable<T[P]> };
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: { input: string; output: string; }
String: { input: string; output: string; }
Boolean: { input: boolean; output: boolean; }
Int: { input: number; output: number; }
Float: { input: number; output: number; }
};

export type Mutation = {
readonly __typename?: 'Mutation';
readonly randomNumber: Scalars['Int']['output'];
};

export type Query = {
readonly __typename?: 'Query';
readonly hello: Scalars['String']['output'];
};

export type Subscription = {
readonly __typename?: 'Subscription';
readonly countdown: Scalars['Int']['output'];
readonly randomNumber: Scalars['Int']['output'];
readonly tick: Scalars['Float']['output'];
};


export type SubscriptionCountdownArgs = {
from: Scalars['Int']['input'];
};

export type WithIndex<TObject> = TObject & Record<string, any>;
export type ResolversObject<TObject> = WithIndex<TObject>;

export type ResolverTypeWrapper<T> = Promise<T> | T;


export type ResolverWithResolve<TResult, TParent, TContext, TArgs> = {
resolve: ResolverFn<TResult, TParent, TContext, TArgs>;
};
export type Resolver<TResult, TParent = {}, TContext = {}, TArgs = {}> = ResolverFn<TResult, TParent, TContext, TArgs> | ResolverWithResolve<TResult, TParent, TContext, TArgs>;

export type ResolverFn<TResult, TParent, TContext, TArgs> = (
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => Promise<TResult> | TResult;

export type SubscriptionSubscribeFn<TResult, TParent, TContext, TArgs> = (
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => AsyncIterable<TResult> | Promise<AsyncIterable<TResult>>;

export type SubscriptionResolveFn<TResult, TParent, TContext, TArgs> = (
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => TResult | Promise<TResult>;

export interface SubscriptionSubscriberObject<TResult, TKey extends string, TParent, TContext, TArgs> {
subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>;
resolve?: SubscriptionResolveFn<TResult, { [key in TKey]: TResult }, TContext, TArgs>;
}

export interface SubscriptionResolverObject<TResult, TParent, TContext, TArgs> {
subscribe: SubscriptionSubscribeFn<any, TParent, TContext, TArgs>;
resolve: SubscriptionResolveFn<TResult, any, TContext, TArgs>;
}

export type SubscriptionObject<TResult, TKey extends string, TParent, TContext, TArgs> =
| SubscriptionSubscriberObject<TResult, TKey, TParent, TContext, TArgs>
| SubscriptionResolverObject<TResult, TParent, TContext, TArgs>;

export type SubscriptionResolver<TResult, TKey extends string, TParent = {}, TContext = {}, TArgs = {}> =
| ((...args: any[]) => SubscriptionObject<TResult, TKey, TParent, TContext, TArgs>)
| SubscriptionObject<TResult, TKey, TParent, TContext, TArgs>;

export type TypeResolveFn<TTypes, TParent = {}, TContext = {}> = (
parent: TParent,
context: TContext,
info: GraphQLResolveInfo
) => Maybe<TTypes> | Promise<Maybe<TTypes>>;

export type IsTypeOfResolverFn<T = {}, TContext = {}> = (obj: T, context: TContext, info: GraphQLResolveInfo) => boolean | Promise<boolean>;

export type NextResolverFn<T> = () => Promise<T>;

export type DirectiveResolverFn<TResult = {}, TParent = {}, TContext = {}, TArgs = {}> = (
next: NextResolverFn<TResult>,
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => TResult | Promise<TResult>;



/** Mapping between all available schema types and the resolvers types */
export type ResolversTypes = ResolversObject<{
Boolean: ResolverTypeWrapper<Scalars['Boolean']['output']>;
Float: ResolverTypeWrapper<Scalars['Float']['output']>;
Int: ResolverTypeWrapper<Scalars['Int']['output']>;
Mutation: ResolverTypeWrapper<{}>;
Query: ResolverTypeWrapper<{}>;
String: ResolverTypeWrapper<Scalars['String']['output']>;
Subscription: ResolverTypeWrapper<{}>;
}>;

/** Mapping between all available schema types and the resolvers parents */
export type ResolversParentTypes = ResolversObject<{
Boolean: Scalars['Boolean']['output'];
Float: Scalars['Float']['output'];
Int: Scalars['Int']['output'];
Mutation: {};
Query: {};
String: Scalars['String']['output'];
Subscription: {};
}>;

export type MutationResolvers<ContextType = Zemble.GraphQLContext, ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation']> = ResolversObject<{
randomNumber?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
}>;

export type QueryResolvers<ContextType = Zemble.GraphQLContext, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']> = ResolversObject<{
hello?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
}>;

export type SubscriptionResolvers<ContextType = Zemble.GraphQLContext, ParentType extends ResolversParentTypes['Subscription'] = ResolversParentTypes['Subscription']> = ResolversObject<{
countdown?: SubscriptionResolver<ResolversTypes['Int'], "countdown", ParentType, ContextType, RequireFields<SubscriptionCountdownArgs, 'from'>>;
randomNumber?: SubscriptionResolver<ResolversTypes['Int'], "randomNumber", ParentType, ContextType>;
tick?: SubscriptionResolver<ResolversTypes['Float'], "tick", ParentType, ContextType>;
}>;

export type Resolvers<ContextType = Zemble.GraphQLContext> = ResolversObject<{
Mutation?: MutationResolvers<ContextType>;
Query?: QueryResolvers<ContextType>;
Subscription?: SubscriptionResolvers<ContextType>;
}>;

13 changes: 13 additions & 0 deletions packages/cron-in-memory/graphql/schema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
type Query {
hello: String!
}

type Mutation {
randomNumber: Int!
}

type Subscription {
countdown(from: Int!): Int!
tick: Float!
randomNumber: Int!
}
Loading