chore(server): node16 & export maps support for server (#4698)

* chore(server): node16 & export maps support for server

* moar cleanup

* lint fixc
This commit is contained in:
Kristaps Fabians Geikins
2025-05-12 14:27:34 +03:00
committed by GitHub
parent 06446decb9
commit b406d0e32d
68 changed files with 227 additions and 146 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
import '@/bootstrap.js' // This has side-effects and has to be imported first
import Environment from '@speckle/shared/dist/commonjs/environment/index.js'
import * as Environment from '@speckle/shared/environment'
const { FF_NEXT_GEN_FILE_IMPORTER_ENABLED } = Environment.getFeatureFlags()
import { main as oldMain } from '@/controller/daemon.js'
@@ -3,7 +3,7 @@ import crs from 'crypto-random-string'
import bcrypt from 'bcrypt'
import { chunk } from 'lodash-es'
import { logger as parentLogger } from '@/observability/logging.js'
import Observability from '@speckle/shared/dist/commonjs/observability/index.js'
import * as Observability from '@speckle/shared/observability'
import type { Knex } from 'knex'
import type { Logger } from 'pino'
@@ -1,4 +1,4 @@
import { ensureError } from '@speckle/shared/dist/esm/index.js'
import { ensureError } from '@speckle/shared'
import fs from 'fs'
import path from 'node:path'
import { pipeline } from 'node:stream/promises'
@@ -1,5 +1,5 @@
import fs from 'fs'
import Observability from '@speckle/shared/dist/commonjs/observability/index.js'
import * as Observability from '@speckle/shared/observability'
import { logger as parentLogger } from '@/observability/logging.js'
import { getDbClients } from '@/knex.js'
import { parseAndCreateCommitFactory } from '@/ifc/index.js'
+1 -1
View File
@@ -1,6 +1,6 @@
import { performance } from 'perf_hooks'
import { fetch } from 'undici'
import Observability from '@speckle/shared/dist/commonjs/observability/index.js'
import * as Observability from '@speckle/shared/observability'
import { ServerAPI } from '@/controller/api.js'
import { logger as parentLogger } from '@/observability/logging.js'
import { IFCParser } from '@/ifc/parser.js'
@@ -1,6 +1,6 @@
import { performance } from 'perf_hooks'
import WebIFC from 'web-ifc/web-ifc-api-node.js'
import Observability from '@speckle/shared/dist/commonjs/observability/index.js'
import * as Observability from '@speckle/shared/observability'
import { logger as parentLogger } from '@/observability/logging.js'
import {
getHash,
+2 -2
View File
@@ -1,8 +1,8 @@
import Environment from '@speckle/shared/dist/commonjs/environment/index.js'
import * as Environment from '@speckle/shared/environment'
import {
loadMultiRegionsConfig,
configureKnexClient
} from '@speckle/shared/dist/commonjs/environment/multiRegionConfig.js'
} from '@speckle/shared/environment/multiRegionConfig'
import { logger } from '@/observability/logging.js'
import { Knex } from 'knex'
@@ -1,4 +1,4 @@
import Observability from '@speckle/shared/dist/commonjs/observability/index.js'
import * as Observability from '@speckle/shared/observability'
// loggers for specific components within normal operation
export const logger = Observability.extendLoggerComponent(
@@ -5,7 +5,7 @@ import {
} from '~/lib/common/helpers/mp'
import type Mixpanel from 'mixpanel'
import type { Nullable } from '@speckle/shared'
import * as ServerMixpanelUtils from '@speckle/shared/dist/esm/observability/mixpanel.js'
import * as ServerMixpanelUtils from '@speckle/shared/observability/mixpanel'
import { useApiOrigin } from '~/composables/env'
import { useActiveUser } from '~/composables/globals'
import { isFunction } from 'lodash-es'
@@ -1,4 +1,4 @@
import * as Observability from '@speckle/shared/dist/esm/observability/index.js'
import * as Observability from '@speckle/shared/observability'
import type { IncomingMessage } from 'node:http'
import { get } from 'lodash-es'
import type { Logger } from 'pino'
@@ -9,11 +9,11 @@ import {
isDevOrTestEnv,
isTest
} from '@/utils/env.js'
import Environment from '@speckle/shared/dist/commonjs/environment/index.js'
import * as Environment from '@speckle/shared/environment'
import {
loadMultiRegionsConfig,
configureKnexClient
} from '@speckle/shared/dist/commonjs/environment/multiRegionConfig.js'
} from '@speckle/shared/environment/multiRegionConfig'
import { Knex } from 'knex'
const { FF_WORKSPACES_MULTI_REGION_ENABLED } = Environment.getFeatureFlags()
@@ -1,9 +1,7 @@
import { getLogLevel, isLogPretty } from '@/utils/env.js'
import {
extendLoggerComponent as elc,
getLogger
} from '@speckle/shared/dist/commonjs/observability/index.js'
export const extendLoggerComponent = elc
import { extendLoggerComponent, getLogger } from '@speckle/shared/observability'
export { extendLoggerComponent }
export const logger = extendLoggerComponent(
getLogger(getLogLevel(), isLogPretty()),
@@ -1,7 +1,7 @@
import prometheusClient from 'prom-client'
import { join } from 'lodash-es'
import type { MetricInitializer } from '@/observability/types.js'
import Environment from '@speckle/shared/dist/commonjs/environment/index.js'
import * as Environment from '@speckle/shared/environment'
const { FF_WORKSPACES_MULTI_REGION_ENABLED } = Environment.getFeatureFlags()
@@ -1,7 +1,7 @@
import prometheusClient from 'prom-client'
import { join } from 'lodash-es'
import type { MetricInitializer } from '@/observability/types.js'
import Environment from '@speckle/shared/dist/commonjs/environment/index.js'
import * as Environment from '@speckle/shared/environment'
const { FF_WORKSPACES_MULTI_REGION_ENABLED } = Environment.getFeatureFlags()
@@ -1,7 +1,7 @@
import prometheusClient from 'prom-client'
import { join } from 'lodash-es'
import type { MetricInitializer } from '@/observability/types.js'
import Environment from '@speckle/shared/dist/commonjs/environment/index.js'
import * as Environment from '@speckle/shared/environment'
type QueryResponseSchema = {
rows: [{ subname: string; subenabled: boolean }]
+1 -1
View File
@@ -13,7 +13,7 @@
"default": "./dist/objectloader.esm.js"
},
"require": {
"types": "./types/index.d.ts",
"types": "./types/index.d.cts",
"default": "./dist/objectloader.cjs"
}
},
+57
View File
@@ -0,0 +1,57 @@
/**
* This is written manually & should be kept up to date when the API changes
*/
export interface SpeckleObject extends Record<string, unknown> {
totalChildrenCount?: number
}
type Logger = (...args: unknown[]) => void
export type ProgressStage = 'download' | 'construction'
/**
* ObjectLoader class
*/
class ObjectLoader {
constructor(params: {
serverUrl: string
streamId: string
objectId: string
token?: string
options?: Partial<{
/**
* Whether IndexedDB caching is enabled (disabled by default in node envs where IndexedDB is not available)
*/
enableCaching: boolean
fullyTraverseArrays: boolean
excludeProps: Array
/**
* Override fetch implementation (necessary in node environment)
*/
fetch: GlobalFetch['fetch']
/**
* Optionally provide alternative for console.log
*/
customLogger: Logger
/**
* Optionally provide alternative for console.warn
*/
customWarner: Logger
}>
})
static createFromObjects(objects: object[]): ObjectLoader
static createFromJSON(input: string): ObjectLoader
async getRootObject(): Promise<SpeckleObject>
async getTotalObjectCount(): Promise<number>
async getAndConstructObject(
onProgress: (e: { stage: ProgressStage; current: number; total: number }) => void
): SpeckleObject | SpeckleObject[]
async *getObjectIterator(): AsyncGenerator<SpeckleObject, SpeckleObject>
async getObject(id: string): Promise<Record<string, unknown>>
dispose(): void
}
export default ObjectLoader
+1 -4
View File
@@ -1,7 +1,4 @@
import {
extendLoggerComponent,
getLogger
} from '@speckle/shared/dist/commonjs/observability/index.js'
import { extendLoggerComponent, getLogger } from '@speckle/shared/observability'
import { LOG_LEVEL, LOG_PRETTY } from '@/config.js'
export const logger = extendLoggerComponent(
+1 -1
View File
@@ -4,7 +4,7 @@ dotenv.config({ path: `./.env.test` })
dotenv.config({ path: `./.env` })
// Resolve FF values for ignore patterns
const Environment = require('@speckle/shared/dist/commonjs/environment/index.js')
const Environment = require('@speckle/shared/environment')
const featureFlags = Environment.getFeatureFlags()
const ignore = [
...(!featureFlags.FF_AUTOMATE_MODULE_ENABLED ? ['modules/automate/**/*'] : []),
+3 -2
View File
@@ -51,7 +51,7 @@ import {
getMaximumRequestBodySizeMB,
isCompressionEnabled
} from '@/modules/shared/helpers/envHelper'
import * as ModulesSetup from '@/modules'
import * as ModulesSetup from '@/modules/index'
import { GraphQLContext, Optional } from '@/modules/shared/helpers/typeHelper'
import { createRateLimiterMiddleware } from '@/modules/core/services/ratelimiter'
@@ -401,7 +401,8 @@ const shouldUseFrontendProxy = () => isDevEnv()
async function createFrontendProxy() {
const frontendHost = process.env.FRONTEND_HOST || '127.0.0.1'
const frontendPort = process.env.FRONTEND_PORT || 8081
const { createProxyMiddleware } = await import('http-proxy-middleware')
const { createProxyMiddleware } =
require('http-proxy-middleware') as typeof import('http-proxy-middleware')
// even tho it has default values, it fixes http-proxy setting `Connection: close` on each request
// slowing everything down
+3
View File
@@ -67,6 +67,9 @@ const configs = [
}
],
// Until we fully move to ESM, we can't have this:
'@typescript-eslint/no-require-imports': 'off',
// TODO: Enable these
'@typescript-eslint/require-await': 'off', // can be turned on, but there's a lot of fixing to do
'@typescript-eslint/await-thenable': 'off', // can be turned on, but there's a lot of fixing to do
+1 -1
View File
@@ -20,7 +20,7 @@ The Speckle shared package exposes a `FeatureFlags` object, that contains all th
For any usecase that is not Nuxt based, the code below is the preferred way of using feature flags.
```typescript
import { Environment } from '@speckle/shared/dist/commonjs/environment/index' // or @speckle/shared/environment, if supported
import * as Environment from '@speckle/shared/environment'
if (Environment.getFeatureFlags().FF_AUTOMATE_MODULE_ENABLED)
console.log("Hurray I'm enabled")
+1 -1
View File
@@ -1,5 +1,5 @@
import type { CheckResponse, RedisCheck } from '@/healthchecks/types'
import { isRedisReady } from '@speckle/shared/dist/commonjs/redis/isRedisReady.js'
import { isRedisReady } from '@speckle/shared/redis'
export const isRedisAlive: RedisCheck = async (params): Promise<CheckResponse> => {
const { client } = params
+1 -1
View File
@@ -19,7 +19,7 @@ import {
configureKnexClient,
KnexConfigArgs,
RegionServerConfig
} from '@speckle/shared/dist/commonjs/environment/multiRegionConfig.js'
} from '@speckle/shared/environment/multiRegionConfig'
function walk(dir: string) {
let results: string[] = []
@@ -1,6 +1,6 @@
import { CommandModule } from 'yargs'
import { cliLogger as logger } from '@/observability/logging'
import * as ModulesSetup from '@/modules'
import * as ModulesSetup from '@/modules/index'
import { printSchema } from 'graphql/utilities'
import fs from 'node:fs/promises'
import path from 'node:path'
@@ -85,16 +85,16 @@ import { throwIfAuthNotOk } from '@/modules/shared/helpers/errorHelper'
import { getFeatureFlags } from '@/modules/shared/helpers/envHelper'
import { withOperationLogging } from '@/observability/domain/businessLogging'
import {
Authz,
getProjectLimitDate,
isNonNullable,
MaybeNullOrUndefined,
Roles
} from '@speckle/shared'
import { PersonalProjectsLimits } from '@speckle/shared/authz'
const { FF_FORCE_PERSONAL_PROJECTS_LIMITS_ENABLED } = getFeatureFlags()
const getPersonalProjectLimits = FF_FORCE_PERSONAL_PROJECTS_LIMITS_ENABLED
? () => Promise.resolve(Authz.PersonalProjectsLimits)
? () => Promise.resolve(PersonalProjectsLimits)
: () => Promise.resolve(null)
const getStreams = getStreamsFactory({ db })
+2 -1
View File
@@ -97,7 +97,8 @@ const coreModule: SpeckleModule<{
// Setup test subs
if (isTestEnv()) {
const { startEmittingTestSubs } = await import('@/test/graphqlHelper')
const { startEmittingTestSubs } =
require('@/test/graphqlHelper') as typeof import('@/test/graphqlHelper')
stopTestSubs = await startEmittingTestSubs()
}
+1 -1
View File
@@ -1,6 +1,6 @@
import DataLoader from 'dataloader'
import { AuthContext } from '@/modules/shared/authz'
import { graphDataloadersBuilders } from '@/modules'
import { graphDataloadersBuilders } from '@/modules/index'
import { ModularizedDataLoadersConstraint } from '@/modules/shared/helpers/graphqlHelper'
import { Knex } from 'knex'
import { isNonNullable, Optional } from '@speckle/shared'
@@ -1,5 +1,5 @@
import fetch from 'cross-fetch'
import { ApolloClient, NormalizedCacheObject, gql } from '@apollo/client/core'
import { ApolloClient, NormalizedCacheObject, gql } from '@apollo/client/core/core.cjs'
import { getFrontendOrigin } from '@/modules/shared/helpers/envHelper'
import { CreateCommentInput } from '@/test/graphql/generated/graphql'
import { Roles, TIME_MS, timeoutAt } from '@speckle/shared'
@@ -5,8 +5,8 @@ import {
HttpLink,
gql,
ApolloQueryResult
} from '@apollo/client/core'
import { setContext } from '@apollo/client/link/context'
} from '@apollo/client/core/core.cjs'
import { setContext } from '@apollo/client/link/context/context.cjs'
import { getServerVersion } from '@/modules/shared/helpers/envHelper'
import { CrossSyncClientTestQuery } from '@/modules/cross-server-sync/graph/generated/graphql'
import { EnvironmentResourceError } from '@/modules/shared/errors'
+2 -1
View File
@@ -3,6 +3,7 @@ import { moduleLogger } from '@/observability/logging'
import * as SendingService from '@/modules/emails/services/sending'
import { initializeTransporter } from '@/modules/emails/utils/transporter'
import { SpeckleModule } from '@/modules/shared/helpers/typeHelper'
import RestApi from '@/modules/emails/rest/index'
const emailsModule: SpeckleModule = {
init: async ({ app }) => {
@@ -12,7 +13,7 @@ const emailsModule: SpeckleModule = {
await initializeTransporter()
// init rest api
;(await import('./rest')).default(app)
RestApi(app)
}
}
@@ -4,7 +4,7 @@ import {
FileUploadRecordV2
} from '@/modules/fileuploads/helpers/types'
import { Optional } from '@speckle/shared'
import { FileImportResultPayload } from '@speckle/shared/dist/commonjs/workers/fileimport/job.js'
import { FileImportResultPayload } from '@speckle/shared/workers/fileimport'
export type GetFileInfo = (args: {
fileId: string
@@ -1,5 +1,5 @@
import { FileUploadConvertedStatus } from '@/modules/fileuploads/helpers/types'
import { FileImportResultPayload } from '@speckle/shared/dist/commonjs/workers/fileimport/job'
import { FileImportResultPayload } from '@speckle/shared/workers/fileimport'
import { FileImportInvalidJobResultPayload } from '@/modules/fileuploads/helpers/errors'
export const jobResultStatusToFileUploadStatus = (
@@ -5,7 +5,7 @@ import { publish } from '@/modules/shared/utils/subscriptions'
import { streamWritePermissionsPipelineFactory } from '@/modules/shared/authz'
import { getStreamFactory } from '@/modules/core/repositories/streams'
import { getProjectDbClient } from '@/modules/multiregion/utils/dbSelector'
import { fileImportResultPayload } from '@speckle/shared/dist/commonjs/workers/fileimport/job.js'
import { fileImportResultPayload } from '@speckle/shared/workers/fileimport'
import { onFileImportResultFactory } from '@/modules/fileuploads/services/resultHandler'
import {
saveUploadFileFactoryV2,
+42 -26
View File
@@ -11,7 +11,7 @@ import { makeExecutableSchema } from '@graphql-tools/schema'
import { moduleLogger } from '@/observability/logging'
import { addMocksToSchema } from '@graphql-tools/mock'
import { getFeatureFlags } from '@/modules/shared/helpers/envHelper'
import { isNonNullable, Optional, Authz, TIME_MS } from '@speckle/shared'
import { isNonNullable, Optional, TIME_MS } from '@speckle/shared'
import { SpeckleModule } from '@/modules/shared/helpers/typeHelper'
import type { Express } from 'express'
import { RequestDataLoadersBuilder } from '@/modules/shared/helpers/graphqlHelper'
@@ -36,6 +36,11 @@ import {
} from '@/modules/shared/utils/caching'
import TTLCache from '@isaacs/ttlcache'
import { buildRequestLoaders, RequestDataLoaders } from '@/modules/core/loaders'
import {
AllAuthCheckContextLoaders,
AuthCheckContextLoaderKeys,
AuthCheckContextLoaders
} from '@speckle/shared/authz'
/**
* Cached speckle module requires
@@ -60,7 +65,6 @@ function autoloadFromDirectory(dirPath: string) {
const ext = path.extname(file)
if (['.js', '.ts'].includes(ext)) {
const name = camelCase(path.basename(file, ext))
// eslint-disable-next-line @typescript-eslint/no-require-imports
results[name] = require(pathToFile)
}
}
@@ -112,8 +116,19 @@ async function getSpeckleModules() {
const moduleNames = getEnabledModuleNames()
for (const dir of moduleNames) {
const moduleIndex = await import(`./${dir}/index`)
const moduleDefinition = 'init' in moduleIndex ? moduleIndex : moduleIndex.default
const moduleIndex = require(`./${dir}/index`)
// CJS/ESM interop is weird
let moduleDefinition: SpeckleModule
if ('init' in moduleIndex) {
moduleDefinition = moduleIndex
} else {
// .default.default may be needed, I dunno why...
const moduleDefault = moduleIndex.default
moduleDefinition =
'default' in moduleDefault ? moduleDefault.default : moduleDefault
}
if (!('init' in moduleDefinition)) {
throw new LogicError(`Module ${dir} does not have an init function`)
}
@@ -332,7 +347,7 @@ export const moduleAuthLoaders = async (params: {
}) => {
const enabledModuleNames = getEnabledModuleNames()
let loaders: Partial<Authz.AuthCheckContextLoaders> = {}
let loaders: Partial<AuthCheckContextLoaders> = {}
const dataLoaders = params.dataLoaders || (await buildRequestLoaders({ auth: false }))
const ctx: ServerLoadersContext = {
dataLoaders
@@ -353,10 +368,10 @@ export const moduleAuthLoaders = async (params: {
// Load the actual loaders
const newLoaders = await moduleLoadersBuilderFn?.()
const newServerLoaders: Partial<Authz.AuthCheckContextLoaders> = Object.entries(
const newServerLoaders: Partial<AuthCheckContextLoaders> = Object.entries(
newLoaders || {}
).reduce((acc, entry) => {
const key = entry[0] as Authz.AuthCheckContextLoaderKeys
const key = entry[0] as AuthCheckContextLoaderKeys
const loader = entry[1] as Required<ServerLoaders>[typeof key]
// Feed in ctx to all loader functions
@@ -369,7 +384,7 @@ export const moduleAuthLoaders = async (params: {
set(acc, key, wrappedLoader)
return acc
}, {} as Partial<Authz.AuthCheckContextLoaders>)
}, {} as Partial<AuthCheckContextLoaders>)
loaders = {
...loaders,
@@ -379,7 +394,7 @@ export const moduleAuthLoaders = async (params: {
// validate that all were loaded
const notFoundKeys = difference(
Object.values(Authz.AuthCheckContextLoaderKeys),
Object.values(AuthCheckContextLoaderKeys),
Object.keys(loaders)
)
if (notFoundKeys.length) {
@@ -388,7 +403,7 @@ export const moduleAuthLoaders = async (params: {
)
}
const allLoaders = loaders as Authz.AuthCheckContextLoaders
const allLoaders = loaders as AuthCheckContextLoaders
/**
* Add inmemory caching to all loaders. Since the loaders & their caches are scoped to each request and these checks
@@ -397,24 +412,25 @@ export const moduleAuthLoaders = async (params: {
* In edge cases - the caches can be cleared
*/
const cache = new TTLCache<string, unknown>()
const loadersWithCache: Authz.AuthCheckContextLoaders = Object.entries(
allLoaders
).reduce((acc, entry) => {
const key = entry[0] as Authz.AuthCheckContextLoaderKeys
const loader = entry[1] as Authz.AllAuthCheckContextLoaders[typeof key]
const loadersWithCache: AuthCheckContextLoaders = Object.entries(allLoaders).reduce(
(acc, entry) => {
const key = entry[0] as AuthCheckContextLoaderKeys
const loader = entry[1] as AllAuthCheckContextLoaders[typeof key]
const newLoader = wrapWithCache<any, any>({
resolver: loader,
name: `authzLoader:${key}`,
// since its the inmemory cache, we dont have to worry about true-myth results being
// serialized and deserialized as they would be with redis
cacheProvider: inMemoryCacheProviderFactory({ cache }),
ttlMs: 1 * TIME_MS.hour // (longer than any req will be),
})
acc[key] = newLoader
const newLoader = wrapWithCache<any, any>({
resolver: loader,
name: `authzLoader:${key}`,
// since its the inmemory cache, we dont have to worry about true-myth results being
// serialized and deserialized as they would be with redis
cacheProvider: inMemoryCacheProviderFactory({ cache }),
ttlMs: 1 * TIME_MS.hour // (longer than any req will be),
})
acc[key] = newLoader
return acc
}, {} as Authz.AuthCheckContextLoaders)
return acc
},
{} as AuthCheckContextLoaders
)
return {
loaders: loadersWithCache,
+3 -2
View File
@@ -1,5 +1,6 @@
import { RequestDataLoaders } from '@/modules/core/loaders'
import { Authz, MaybeAsync } from '@speckle/shared'
import { MaybeAsync } from '@speckle/shared'
import { AuthCheckContextLoaders } from '@speckle/shared/authz'
export type ServerLoadersContext = {
dataLoaders: RequestDataLoaders
@@ -7,7 +8,7 @@ export type ServerLoadersContext = {
// Inject extra argument to all loaders, e.g. for GQL dataloaders
export type ServerLoaders = Partial<{
[K in keyof Authz.AuthCheckContextLoaders]: Authz.AuthCheckContextLoaders[K] extends (
[K in keyof AuthCheckContextLoaders]: AuthCheckContextLoaders[K] extends (
...args: infer A
) => infer R
? (...args: [...A, ctx: ServerLoadersContext]) => R
+2 -2
View File
@@ -7,7 +7,7 @@ import {
import { has, reduce } from 'lodash'
import { IMockStore, IMocks } from '@graphql-tools/mock'
import { moduleMockConfigs } from '@/modules'
import { moduleMockConfigs } from '@/modules/index'
import { isNonNullable, Roles, SourceAppNames } from '@speckle/shared'
import {
getRandomDbRecords,
@@ -21,7 +21,7 @@ import { Streams } from '@/modules/core/dbSchema'
*/
const buildBaseConfig = async (): Promise<SpeckleModuleMocksConfig> => {
// Async import so that we only import this when envs actually have mocks on
const faker = (await import('@faker-js/faker')).faker
const { faker } = require('@faker-js/faker') as typeof import('@faker-js/faker')
return {
resolvers: ({ helpers: { getFieldValue }, store }) => ({
@@ -3,7 +3,7 @@ import { Nullable } from '@speckle/shared'
import {
DataRegionsConfig,
RegionServerConfig
} from '@speckle/shared/dist/commonjs/environment/multiRegionConfig.js'
} from '@speckle/shared/environment/multiRegionConfig'
export { RegionServerConfig, DataRegionsConfig }
export type ServerRegion = RegionRecord
@@ -12,7 +12,7 @@ import {
MainRegionConfig,
MultiRegionConfig,
loadMultiRegionsConfig
} from '@speckle/shared/dist/commonjs/environment/multiRegionConfig.js'
} from '@speckle/shared/environment/multiRegionConfig'
let multiRegionConfig: Optional<MultiRegionConfig> = undefined
@@ -29,7 +29,7 @@ import {
} from '@/modules/multiregion/repositories/projectRegion'
import { updateProjectRegionKeyFactory } from '@/modules/multiregion/services/projectRegion'
import { getGenericRedis } from '@/modules/shared/redis/redis'
import { initializeQueue as setupQueue } from '@speckle/shared/dist/commonjs/queue/index.js'
import { initializeQueue as setupQueue } from '@speckle/shared/queue'
import { getEventBus } from '@/modules/shared/services/eventBus'
import {
copyWorkspaceFactory,
@@ -17,7 +17,7 @@ import {
import { MisconfiguredEnvironmentError } from '@/modules/shared/errors'
import { getFeatureFlags } from '@/modules/shared/helpers/envHelper'
import { Optional } from '@speckle/shared'
import { BlobStorageConfig } from '@speckle/shared/dist/commonjs/environment/multiRegionConfig'
import { BlobStorageConfig } from '@speckle/shared/environment/multiRegionConfig'
type RegionStorageClients = {
[regionKey: string]: ObjectStorage
@@ -15,7 +15,7 @@ import {
import { MisconfiguredEnvironmentError } from '@/modules/shared/errors'
import { getGenericRedis } from '@/modules/shared/redis/redis'
import { Optional } from '@speckle/shared'
import { DataRegionsConfig } from '@speckle/shared/dist/commonjs/environment/multiRegionConfig'
import { DataRegionsConfig } from '@speckle/shared/environment/multiRegionConfig'
export const getRegisteredRegionConfigs = async () => {
const registeredKeys = (await getRegionsFactory({ db: mainDb })()).map((r) => r.key)
+8 -14
View File
@@ -11,6 +11,10 @@ import {
import { SpeckleModule } from '@/modules/shared/helpers/typeHelper'
import { shouldDisableNotificationsConsumption } from '@/modules/shared/helpers/envHelper'
import { moduleLogger } from '@/observability/logging'
import MentionedInCommentHandler from '@/modules/notifications/services/handlers/mentionedInComment'
import NewStreamAccessRequestHandler from '@/modules/notifications/services/handlers/newStreamAccessRequest'
import StreamAccessRequestApprovedHandler from '@/modules/notifications/services/handlers/streamAccessRequestApproved'
import ActivityDigestHandler from '@/modules/notifications/services/handlers/activityDigest'
export async function initializeConsumption(
customHandlers?: Partial<NotificationTypeHandlers>
@@ -18,20 +22,10 @@ export async function initializeConsumption(
moduleLogger.info('📞 Initializing notification queue consumption...')
const allHandlers: Partial<NotificationTypeHandlers> = {
[NotificationType.MentionedInComment]: (
await import('@/modules/notifications/services/handlers/mentionedInComment')
).default,
[NotificationType.NewStreamAccessRequest]: (
await import('@/modules/notifications/services/handlers/newStreamAccessRequest')
).default,
[NotificationType.StreamAccessRequestApproved]: (
await import(
'@/modules/notifications/services/handlers/streamAccessRequestApproved'
)
).default,
[NotificationType.ActivityDigest]: (
await import('@/modules/notifications/services/handlers/activityDigest')
).default
[NotificationType.MentionedInComment]: MentionedInCommentHandler,
[NotificationType.NewStreamAccessRequest]: NewStreamAccessRequestHandler,
[NotificationType.StreamAccessRequestApproved]: StreamAccessRequestApprovedHandler,
[NotificationType.ActivityDigest]: ActivityDigestHandler
}
registerNotificationHandlers(customHandlers || allHandlers)
@@ -443,7 +443,7 @@ const digestNotificationEmailHandler = digestNotificationEmailHandlerFactory({
renderEmail
})
const handler: NotificationHandler<ActivityDigestMessage> = async (msg) => {
export const handler: NotificationHandler<ActivityDigestMessage> = async (msg) => {
const {
targetUserId,
data: { streamIds, start, end }
@@ -223,7 +223,9 @@ const mentionedInCommentHandlerFactory =
/**
* Notification that is triggered when a user is mentioned in a comment
*/
const handler: NotificationHandler<MentionedInCommentMessage> = async (...args) => {
export const handler: NotificationHandler<MentionedInCommentMessage> = async (
...args
) => {
const mentionedInCommentHandler = mentionedInCommentHandlerFactory({
getUser: getUserFactory({ db }),
getStream: getStreamFactory({ db }),
@@ -145,7 +145,9 @@ const newStreamAccessRequestHandlerFactory =
})
}
const handler: NotificationHandler<NewStreamAccessRequestMessage> = (...args) => {
export const handler: NotificationHandler<NewStreamAccessRequestMessage> = (
...args
) => {
const newStreamAccessRequestHandler = newStreamAccessRequestHandlerFactory({
getServerInfo: getServerInfoFactory({ db }),
renderEmail,
@@ -123,7 +123,7 @@ const streamAccessRequestApprovedHandlerFactory =
})
}
const handler: NotificationHandler<StreamAccessRequestApprovedMessage> = async (
export const handler: NotificationHandler<StreamAccessRequestApprovedMessage> = async (
...args
) => {
const streamAccessRequestApprovedHandler = streamAccessRequestApprovedHandlerFactory({
@@ -14,7 +14,7 @@ import {
} from '@/modules/notifications/helpers/types'
import { getRedisUrl, isProdEnv, isTestEnv } from '@/modules/shared/helpers/envHelper'
import Bull from 'bull'
import { initializeQueue as setupQueue } from '@speckle/shared/dist/commonjs/queue/index.js'
import { initializeQueue as setupQueue } from '@speckle/shared/queue'
import cryptoRandomString from 'crypto-random-string'
import { logger, notificationsLogger, Observability } from '@/observability/logging'
import { ensureErrorOrWrapAsCause } from '@/modules/shared/errors/ensureError'
+2 -2
View File
@@ -21,7 +21,7 @@ import {
JobPayload,
PreviewResultPayload,
previewResultPayload
} from '@speckle/shared/dist/commonjs/workers/previews/job.js'
} from '@speckle/shared/workers/previews'
import { getProjectDbClient } from '@/modules/multiregion/utils/dbSelector'
import {
storePreviewFactory,
@@ -33,7 +33,7 @@ import {
PreviewJobDurationStep
} from '@/modules/previews/observability/metrics'
import { addRequestQueueListeners } from '@/modules/previews/queues/previews'
import { initializeQueue } from '@speckle/shared/dist/commonjs/queue/index.js'
import { initializeQueue } from '@speckle/shared/queue'
import type Bull from 'bull'
const JobQueueName = 'preview-service-jobs'
@@ -5,7 +5,7 @@ import type { EventEmitter } from 'stream'
import { upsertObjectPreviewFactory } from '@/modules/previews/repository/previews'
import { getProjectDbClient } from '@/modules/multiregion/utils/dbSelector'
import { PreviewStatus } from '@/modules/previews/domain/consts'
import { JobPayload } from '@speckle/shared/dist/commonjs/workers/previews'
import { JobPayload } from '@speckle/shared/workers/previews'
export const requestObjectPreviewFactory =
({
@@ -3,7 +3,7 @@ import { MessageType } from '@/modules/core/utils/dbNotificationListener'
import { getObjectCommitsWithStreamIdsFactory } from '@/modules/core/repositories/commits'
import { publish } from '@/modules/shared/utils/subscriptions'
import { getProjectDbClient } from '@/modules/multiregion/utils/dbSelector'
import { PreviewResultPayload } from '@speckle/shared/dist/commonjs/workers/previews/job.js'
import { PreviewResultPayload } from '@speckle/shared/workers/previews'
import { throwUncoveredError } from '@speckle/shared'
import type { Logger } from '@/observability/logging'
import crypto from 'crypto'
+1 -1
View File
@@ -32,7 +32,7 @@ import {
} from '@/modules/shared/domain/authz/operations'
import { GetRoles } from '@/modules/shared/domain/rolesAndScopes/operations'
import { ValidateUserServerRole } from '@/modules/shared/domain/operations'
import { moduleAuthLoaders } from '@/modules'
import { moduleAuthLoaders } from '@/modules/index'
export { AuthContext, AuthParams }
interface AuthFailedResult extends AuthResult {
@@ -1,6 +1,6 @@
import { MisconfiguredEnvironmentError } from '@/modules/shared/errors'
import { has, trimEnd } from 'lodash'
import * as Environment from '@speckle/shared/dist/commonjs/environment/index.js'
import * as Environment from '@speckle/shared/environment'
import { ensureError, Nullable } from '@speckle/shared'
export function getStringFromEnv(
@@ -3,8 +3,7 @@ import type {
Optional,
MaybeNullOrUndefined,
MaybeAsync,
MaybeFalsy,
Authz
MaybeFalsy
} from '@speckle/shared'
import type { RequestDataLoaders } from '@/modules/core/loaders'
import type { AuthContext } from '@/modules/shared/authz'
@@ -13,7 +12,7 @@ import type { ConditionalKeys, SetRequired } from 'type-fest'
import type { Logger } from 'pino'
import type { BaseContext } from '@apollo/server'
import type { Registry } from 'prom-client'
import { AuthCheckContextLoaders } from '@speckle/shared/dist/commonjs/authz'
import { AuthCheckContextLoaders, AuthPolicies } from '@speckle/shared/authz'
export type MarkNullableOptional<T> = SetRequired<
Partial<T>,
@@ -54,7 +53,7 @@ export type SpeckleModule<T extends Record<string, unknown> = Record<string, unk
export type GraphQLContext = BaseContext &
AuthContext & {
authPolicies: Authz.AuthPolicies & {
authPolicies: AuthPolicies & {
clearCache: () => void
}
/**
@@ -26,7 +26,7 @@ import {
} from '@/modules/shared/helpers/typeHelper'
import { Authz, wait } from '@speckle/shared'
import { mixpanel } from '@/modules/shared/utils/mixpanel'
import * as Observability from '@speckle/shared/dist/commonjs/observability/index.js'
import * as Observability from '@speckle/shared/observability'
import { getIpFromRequest } from '@/modules/shared/utils/ip'
import { Netmask } from 'netmask'
import { resourceAccessRuleToIdentifier } from '@/modules/core/helpers/token'
@@ -46,7 +46,7 @@ import { getTokenAppInfoFactory } from '@/modules/auth/repositories/apps'
import { getUserRoleFactory } from '@/modules/core/repositories/users'
import { UserInputError } from '@/modules/core/errors/userinput'
import compression from 'compression'
import { moduleAuthLoaders } from '@/modules'
import { moduleAuthLoaders } from '@/modules/index'
export const authMiddlewareCreator = (
steps: AuthPipelineFunction[]
@@ -1,5 +1,5 @@
import { Optional, resolveMixpanelUserId } from '@speckle/shared'
import * as MixpanelUtils from '@speckle/shared/dist/commonjs/observability/mixpanel.js'
import * as MixpanelUtils from '@speckle/shared/observability/mixpanel'
import {
enableMixpanel,
getServerOrigin,
+1 -1
View File
@@ -1,6 +1,6 @@
// Note logging is imported by www & ts-www, prior to init() being called
// so we can't use local imports with '@' etc., as they aren't yet defined.
import * as Observability from '@speckle/shared/dist/commonjs/observability/index.js'
import * as Observability from '@speckle/shared/observability'
const { getLogger, extendLoggerComponent } = Observability
@@ -1,6 +1,6 @@
import { BaseError } from '@/modules/shared/errors'
import { isUserGraphqlError } from '@/modules/shared/helpers/graphqlHelper'
import { ApolloError } from '@apollo/client/core'
import { ApolloError } from '@apollo/client/core/core.cjs'
import { ensureError } from '@speckle/shared'
import { GraphQLError } from 'graphql'
import type { Logger } from 'pino'
+1
View File
@@ -7,6 +7,7 @@
"author": "AEC Systems",
"license": "SEE LICENSE IN readme.md",
"main": "./bin/www",
"type": "commonjs",
"repository": {
"type": "git",
"url": "https://github.com/specklesystems/Server.git"
+2 -2
View File
@@ -27,8 +27,8 @@ import * as MockSocket from 'mock-socket'
import type ws from 'ws'
import { createAuthTokenForUser } from '@/test/authHelper'
import { SubscriptionClient } from 'subscriptions-transport-ws'
import { WebSocketLink } from '@apollo/client/link/ws'
import { execute } from '@apollo/client/core'
import { WebSocketLink } from '@apollo/client/link/ws/ws.cjs'
import { execute } from '@apollo/client/core/core.cjs'
import { PingPongDocument } from '@/test/graphql/generated/graphql'
import { BaseError } from '@/modules/shared/errors'
import EventEmitter from 'eventemitter2'
-1
View File
@@ -44,7 +44,6 @@ export function mockRequireModule<
Record<MockTypeFunctionProp, MockedFunc<MockTypeFunctionProp>>
> = {}
// eslint-disable-next-line @typescript-eslint/no-require-imports
const originalModule = require(modulePaths[0]) as MockType
const mockDefinition = new Proxy<MockType>(originalModule, {
get(target, prop) {
+2 -2
View File
@@ -23,9 +23,9 @@
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
/* Modules */
"module": "commonjs" /* Specify what module code is generated. */,
"module": "node16" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */
"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
"moduleResolution": "node16" /* Specify how TypeScript looks up a file from a given module specifier. */,
"baseUrl": "./" /* Specify the base directory to resolve non-relative module names. */,
"paths": {
"@/*": ["./*"],
-22
View File
@@ -1,22 +0,0 @@
// Only need to do this because our CommonJS app does not support true-myth's export maps
declare module 'true-myth/result' {
import { Result } from 'true-myth/dist/cjs/result.cjs'
export * from 'true-myth/dist/cjs/result.cjs'
export default Result
}
declare module 'true-myth/unit' {
import { Unit } from 'true-myth/dist/cjs/unit.cjs'
export * from 'true-myth/dist/cjs/unit.cjs'
export default Unit
}
declare module 'true-myth/maybe' {
import { Maybe } from 'true-myth/dist/cjs/maybe.cjs'
export * from 'true-myth/dist/cjs/maybe.cjs'
export default Maybe
}
declare module 'true-myth' {
export * from 'true-myth/dist/cjs/index.cjs'
}
+33
View File
@@ -87,7 +87,10 @@
"./package.json": "./package.json",
"./pinoPrettyTransport.cjs": "./pinoPrettyTransport.cjs",
"./environment": "./src/environment/index.ts",
"./environment/multiRegionConfig": "./src/environment/multiRegionConfig.ts",
"./observability": "./src/observability/index.ts",
"./observability/mixpanel": "./src/observability/mixpanel.ts",
"./previews": "./src/previews/index.ts",
"./authz": "./src/authz/index.ts",
"./queue": "./src/queue/index.ts",
"./redis": "./src/redis/index.ts",
@@ -130,6 +133,16 @@
"default": "./dist/commonjs/environment/index.js"
}
},
"./environment/multiRegionConfig": {
"import": {
"types": "./dist/esm/environment/multiRegionConfig.d.ts",
"default": "./dist/esm/environment/multiRegionConfig.js"
},
"require": {
"types": "./dist/commonjs/environment/multiRegionConfig.d.ts",
"default": "./dist/commonjs/environment/multiRegionConfig.js"
}
},
"./observability": {
"import": {
"types": "./dist/esm/observability/index.d.ts",
@@ -140,6 +153,26 @@
"default": "./dist/commonjs/observability/index.js"
}
},
"./observability/mixpanel": {
"import": {
"types": "./dist/esm/observability/mixpanel.d.ts",
"default": "./dist/esm/observability/mixpanel.js"
},
"require": {
"types": "./dist/commonjs/observability/mixpanel.d.ts",
"default": "./dist/commonjs/observability/mixpanel.js"
}
},
"./previews": {
"import": {
"types": "./dist/esm/previews/index.d.ts",
"default": "./dist/esm/previews/index.js"
},
"require": {
"types": "./dist/commonjs/previews/index.d.ts",
"default": "./dist/commonjs/previews/index.js"
}
},
"./authz": {
"import": {
"types": "./dist/esm/authz/index.d.ts",
-2
View File
@@ -1,7 +1,5 @@
export * as RichTextEditor from './rich-text-editor/index.js'
// export * as Observability from './observability/index.js' // Import from @speckle/shared/dist/...
export * as SpeckleViewer from './viewer/index.js'
// export * as Environment from './environment/index.js' // Import from @speckle/shared/dist/...
export * as Automate from './automate/index.js'
export * as Authz from './authz/index.js'
export * from './core/index.js'
@@ -1,2 +1,2 @@
export * from './interface.js'
export * from './job.js'
export * from './interface.js'
+2 -2
View File
@@ -1,9 +1,9 @@
'use strict'
const Environment = require('@speckle/shared/dist/commonjs/environment/index.js')
const Environment = require('@speckle/shared/environment')
const {
loadMultiRegionsConfig,
configureKnexClient
} = require('@speckle/shared/dist/commonjs/environment/multiRegionConfig.js')
} = require('@speckle/shared/environment/multiRegionConfig')
const { logger } = require('./observability/logging')
const { FF_WORKSPACES_MULTI_REGION_ENABLED } = Environment.getFeatureFlags()
@@ -1,4 +1,4 @@
const Observability = require('@speckle/shared/dist/commonjs/observability/index.js')
const Observability = require('@speckle/shared/observability')
const logger = Observability.extendLoggerComponent(
Observability.getLogger(