@budibase/backend-core 3.2.4 → 3.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js.map +1 -1
- package/dist/index.js.meta.json +1 -1
- package/dist/package.json +11 -4
- package/dist/plugins.js.meta.json +1 -1
- package/package.json +11 -4
- package/src/accounts/accounts.ts +0 -82
- package/src/accounts/api.ts +0 -59
- package/src/accounts/index.ts +0 -1
- package/src/auth/auth.ts +0 -210
- package/src/auth/index.ts +0 -1
- package/src/auth/tests/auth.spec.ts +0 -14
- package/src/blacklist/blacklist.ts +0 -54
- package/src/blacklist/index.ts +0 -1
- package/src/blacklist/tests/blacklist.spec.ts +0 -46
- package/src/cache/appMetadata.ts +0 -88
- package/src/cache/base/index.ts +0 -150
- package/src/cache/docWritethrough.ts +0 -105
- package/src/cache/generic.ts +0 -33
- package/src/cache/index.ts +0 -8
- package/src/cache/invite.ts +0 -86
- package/src/cache/passwordReset.ts +0 -49
- package/src/cache/tests/docWritethrough.spec.ts +0 -296
- package/src/cache/tests/user.spec.ts +0 -145
- package/src/cache/tests/writethrough.spec.ts +0 -139
- package/src/cache/user.ts +0 -154
- package/src/cache/writethrough.ts +0 -133
- package/src/configs/configs.ts +0 -263
- package/src/configs/index.ts +0 -1
- package/src/configs/tests/configs.spec.ts +0 -184
- package/src/constants/db.ts +0 -75
- package/src/constants/index.ts +0 -2
- package/src/constants/misc.ts +0 -36
- package/src/context/Context.ts +0 -14
- package/src/context/identity.ts +0 -58
- package/src/context/index.ts +0 -3
- package/src/context/mainContext.ts +0 -422
- package/src/context/tests/index.spec.ts +0 -255
- package/src/context/types.ts +0 -26
- package/src/db/Replication.ts +0 -94
- package/src/db/couch/DatabaseImpl.ts +0 -511
- package/src/db/couch/connections.ts +0 -89
- package/src/db/couch/index.ts +0 -4
- package/src/db/couch/pouchDB.ts +0 -97
- package/src/db/couch/pouchDump.ts +0 -0
- package/src/db/couch/tests/DatabaseImpl.spec.ts +0 -118
- package/src/db/couch/utils.ts +0 -55
- package/src/db/db.ts +0 -34
- package/src/db/errors.ts +0 -14
- package/src/db/index.ts +0 -12
- package/src/db/instrumentation.ts +0 -199
- package/src/db/lucene.ts +0 -721
- package/src/db/searchIndexes/index.ts +0 -1
- package/src/db/searchIndexes/searchIndexes.ts +0 -62
- package/src/db/tests/DatabaseImpl.spec.ts +0 -55
- package/src/db/tests/connections.spec.ts +0 -22
- package/src/db/tests/index.spec.ts +0 -32
- package/src/db/tests/lucene.spec.ts +0 -400
- package/src/db/tests/pouch.spec.js +0 -62
- package/src/db/tests/utils.spec.ts +0 -63
- package/src/db/utils.ts +0 -208
- package/src/db/views.ts +0 -245
- package/src/docIds/conversions.ts +0 -60
- package/src/docIds/ids.ts +0 -126
- package/src/docIds/index.ts +0 -2
- package/src/docIds/newid.ts +0 -5
- package/src/docIds/params.ts +0 -189
- package/src/docUpdates/index.ts +0 -24
- package/src/environment.ts +0 -293
- package/src/errors/errors.ts +0 -119
- package/src/errors/index.ts +0 -1
- package/src/events/analytics.ts +0 -6
- package/src/events/asyncEvents/index.ts +0 -2
- package/src/events/asyncEvents/publisher.ts +0 -12
- package/src/events/asyncEvents/queue.ts +0 -22
- package/src/events/backfill.ts +0 -183
- package/src/events/documentId.ts +0 -56
- package/src/events/events.ts +0 -47
- package/src/events/identification.ts +0 -311
- package/src/events/index.ts +0 -15
- package/src/events/processors/AnalyticsProcessor.ts +0 -64
- package/src/events/processors/AuditLogsProcessor.ts +0 -92
- package/src/events/processors/LoggingProcessor.ts +0 -36
- package/src/events/processors/Processors.ts +0 -52
- package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -38
- package/src/events/processors/index.ts +0 -19
- package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
- package/src/events/processors/posthog/index.ts +0 -3
- package/src/events/processors/posthog/rateLimiting.ts +0 -106
- package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -164
- package/src/events/processors/types.ts +0 -1
- package/src/events/publishers/account.ts +0 -41
- package/src/events/publishers/ai.ts +0 -21
- package/src/events/publishers/app.ts +0 -168
- package/src/events/publishers/auditLog.ts +0 -26
- package/src/events/publishers/auth.ts +0 -73
- package/src/events/publishers/automation.ts +0 -110
- package/src/events/publishers/backfill.ts +0 -74
- package/src/events/publishers/backup.ts +0 -42
- package/src/events/publishers/datasource.ts +0 -48
- package/src/events/publishers/email.ts +0 -17
- package/src/events/publishers/environmentVariable.ts +0 -38
- package/src/events/publishers/group.ts +0 -99
- package/src/events/publishers/index.ts +0 -25
- package/src/events/publishers/installation.ts +0 -38
- package/src/events/publishers/layout.ts +0 -26
- package/src/events/publishers/license.ts +0 -84
- package/src/events/publishers/org.ts +0 -37
- package/src/events/publishers/plugin.ts +0 -47
- package/src/events/publishers/query.ts +0 -89
- package/src/events/publishers/role.ts +0 -62
- package/src/events/publishers/rows.ts +0 -29
- package/src/events/publishers/screen.ts +0 -36
- package/src/events/publishers/serve.ts +0 -43
- package/src/events/publishers/table.ts +0 -70
- package/src/events/publishers/user.ts +0 -202
- package/src/events/publishers/view.ts +0 -107
- package/src/features/features.ts +0 -277
- package/src/features/index.ts +0 -2
- package/src/features/tests/features.spec.ts +0 -267
- package/src/features/tests/utils.ts +0 -64
- package/src/helpers.ts +0 -9
- package/src/index.ts +0 -59
- package/src/installation.ts +0 -115
- package/src/logging/alerts.ts +0 -26
- package/src/logging/correlation/correlation.ts +0 -15
- package/src/logging/correlation/index.ts +0 -1
- package/src/logging/correlation/middleware.ts +0 -18
- package/src/logging/index.ts +0 -4
- package/src/logging/pino/logger.ts +0 -239
- package/src/logging/pino/middleware.ts +0 -48
- package/src/logging/system.ts +0 -81
- package/src/logging/tests/system.spec.ts +0 -61
- package/src/middleware/adminOnly.ts +0 -9
- package/src/middleware/auditLog.ts +0 -6
- package/src/middleware/authenticated.ts +0 -247
- package/src/middleware/builderOnly.ts +0 -21
- package/src/middleware/builderOrAdmin.ts +0 -21
- package/src/middleware/contentSecurityPolicy.ts +0 -113
- package/src/middleware/csrf.ts +0 -81
- package/src/middleware/errorHandling.ts +0 -43
- package/src/middleware/index.ts +0 -24
- package/src/middleware/internalApi.ts +0 -23
- package/src/middleware/ip.ts +0 -12
- package/src/middleware/joi-validator.ts +0 -58
- package/src/middleware/matchers.ts +0 -39
- package/src/middleware/passport/datasource/google.ts +0 -102
- package/src/middleware/passport/local.ts +0 -54
- package/src/middleware/passport/sso/google.ts +0 -77
- package/src/middleware/passport/sso/oidc.ts +0 -152
- package/src/middleware/passport/sso/sso.ts +0 -138
- package/src/middleware/passport/sso/tests/google.spec.ts +0 -68
- package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -144
- package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
- package/src/middleware/passport/utils.ts +0 -38
- package/src/middleware/querystringToBody.ts +0 -28
- package/src/middleware/tenancy.ts +0 -36
- package/src/middleware/tests/builder.spec.ts +0 -181
- package/src/middleware/tests/contentSecurityPolicy.spec.ts +0 -75
- package/src/middleware/tests/matchers.spec.ts +0 -100
- package/src/migrations/definitions.ts +0 -40
- package/src/migrations/index.ts +0 -2
- package/src/migrations/migrations.ts +0 -186
- package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
- package/src/migrations/tests/migrations.spec.ts +0 -64
- package/src/objectStore/buckets/app.ts +0 -53
- package/src/objectStore/buckets/global.ts +0 -29
- package/src/objectStore/buckets/index.ts +0 -3
- package/src/objectStore/buckets/plugins.ts +0 -71
- package/src/objectStore/buckets/tests/app.spec.ts +0 -161
- package/src/objectStore/buckets/tests/global.spec.ts +0 -74
- package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
- package/src/objectStore/cloudfront.ts +0 -41
- package/src/objectStore/index.ts +0 -3
- package/src/objectStore/objectStore.ts +0 -585
- package/src/objectStore/utils.ts +0 -113
- package/src/platform/index.ts +0 -3
- package/src/platform/platformDb.ts +0 -6
- package/src/platform/tenants.ts +0 -101
- package/src/platform/tests/tenants.spec.ts +0 -26
- package/src/platform/users.ts +0 -129
- package/src/plugin/index.ts +0 -1
- package/src/plugin/tests/validation.spec.ts +0 -209
- package/src/plugin/utils.ts +0 -175
- package/src/queue/constants.ts +0 -8
- package/src/queue/inMemoryQueue.ts +0 -189
- package/src/queue/index.ts +0 -2
- package/src/queue/listeners.ts +0 -199
- package/src/queue/queue.ts +0 -84
- package/src/redis/index.ts +0 -6
- package/src/redis/init.ts +0 -118
- package/src/redis/redis.ts +0 -358
- package/src/redis/redlockImpl.ts +0 -155
- package/src/redis/tests/redis.spec.ts +0 -207
- package/src/redis/tests/redlockImpl.spec.ts +0 -105
- package/src/redis/utils.ts +0 -128
- package/src/security/auth.ts +0 -24
- package/src/security/encryption.ts +0 -185
- package/src/security/index.ts +0 -1
- package/src/security/permissions.ts +0 -166
- package/src/security/roles.ts +0 -655
- package/src/security/secrets.ts +0 -20
- package/src/security/sessions.ts +0 -123
- package/src/security/tests/auth.spec.ts +0 -45
- package/src/security/tests/encryption.spec.ts +0 -31
- package/src/security/tests/permissions.spec.ts +0 -146
- package/src/security/tests/secrets.spec.ts +0 -35
- package/src/security/tests/sessions.spec.ts +0 -12
- package/src/sql/designDoc.ts +0 -17
- package/src/sql/index.ts +0 -5
- package/src/sql/sql.ts +0 -1854
- package/src/sql/sqlTable.ts +0 -319
- package/src/sql/utils.ts +0 -193
- package/src/tenancy/db.ts +0 -6
- package/src/tenancy/index.ts +0 -2
- package/src/tenancy/tenancy.ts +0 -148
- package/src/tenancy/tests/tenancy.spec.ts +0 -184
- package/src/timers/index.ts +0 -1
- package/src/timers/timers.ts +0 -22
- package/src/users/db.ts +0 -582
- package/src/users/events.ts +0 -176
- package/src/users/index.ts +0 -4
- package/src/users/lookup.ts +0 -99
- package/src/users/test/db.spec.ts +0 -188
- package/src/users/test/utils.spec.ts +0 -67
- package/src/users/users.ts +0 -353
- package/src/users/utils.ts +0 -81
- package/src/utils/Duration.ts +0 -56
- package/src/utils/hashing.ts +0 -15
- package/src/utils/index.ts +0 -4
- package/src/utils/stringUtils.ts +0 -8
- package/src/utils/tests/Duration.spec.ts +0 -19
- package/src/utils/tests/utils.spec.ts +0 -204
- package/src/utils/utils.ts +0 -249
- package/tests/core/logging.ts +0 -34
- package/tests/core/users/users.spec.js +0 -53
- package/tests/core/utilities/index.ts +0 -7
- package/tests/core/utilities/jestUtils.ts +0 -33
- package/tests/core/utilities/mocks/alerts.ts +0 -4
- package/tests/core/utilities/mocks/date.ts +0 -3
- package/tests/core/utilities/mocks/events.ts +0 -132
- package/tests/core/utilities/mocks/index.ts +0 -9
- package/tests/core/utilities/mocks/licenses.ts +0 -119
- package/tests/core/utilities/queue.ts +0 -9
- package/tests/core/utilities/structures/Chance.ts +0 -20
- package/tests/core/utilities/structures/accounts.ts +0 -80
- package/tests/core/utilities/structures/apps.ts +0 -21
- package/tests/core/utilities/structures/common.ts +0 -7
- package/tests/core/utilities/structures/db.ts +0 -12
- package/tests/core/utilities/structures/documents/index.ts +0 -1
- package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
- package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
- package/tests/core/utilities/structures/generator.ts +0 -3
- package/tests/core/utilities/structures/index.ts +0 -15
- package/tests/core/utilities/structures/koa.ts +0 -16
- package/tests/core/utilities/structures/licenses.ts +0 -190
- package/tests/core/utilities/structures/plugins.ts +0 -19
- package/tests/core/utilities/structures/quotas.ts +0 -72
- package/tests/core/utilities/structures/scim.ts +0 -80
- package/tests/core/utilities/structures/sso.ts +0 -118
- package/tests/core/utilities/structures/tenants.ts +0 -5
- package/tests/core/utilities/structures/userGroups.ts +0 -10
- package/tests/core/utilities/structures/users.ts +0 -89
- package/tests/core/utilities/testContainerUtils.ts +0 -165
- package/tests/core/utilities/utils/index.ts +0 -2
- package/tests/core/utilities/utils/queue.ts +0 -27
- package/tests/core/utilities/utils/time.ts +0 -3
- package/tests/extra/DBTestConfiguration.ts +0 -36
- package/tests/extra/index.ts +0 -2
- package/tests/extra/testEnv.ts +0 -95
- package/tests/index.ts +0 -2
- package/tests/jestEnv.ts +0 -10
- package/tests/jestSetup.ts +0 -36
package/src/auth/auth.ts
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
const _passport = require("koa-passport")
|
|
2
|
-
const LocalStrategy = require("passport-local").Strategy
|
|
3
|
-
|
|
4
|
-
import { getGlobalDB } from "../context"
|
|
5
|
-
import { Cookie } from "../constants"
|
|
6
|
-
import { getSessionsForUser, invalidateSessions } from "../security/sessions"
|
|
7
|
-
import {
|
|
8
|
-
authenticated,
|
|
9
|
-
csrf,
|
|
10
|
-
google,
|
|
11
|
-
local,
|
|
12
|
-
oidc,
|
|
13
|
-
tenancy,
|
|
14
|
-
} from "../middleware"
|
|
15
|
-
import * as userCache from "../cache/user"
|
|
16
|
-
import { invalidateUser } from "../cache/user"
|
|
17
|
-
import {
|
|
18
|
-
ConfigType,
|
|
19
|
-
GoogleInnerConfig,
|
|
20
|
-
OIDCInnerConfig,
|
|
21
|
-
PlatformLogoutOpts,
|
|
22
|
-
SessionCookie,
|
|
23
|
-
SSOProviderType,
|
|
24
|
-
} from "@budibase/types"
|
|
25
|
-
import * as events from "../events"
|
|
26
|
-
import * as configs from "../configs"
|
|
27
|
-
import { clearCookie, getCookie } from "../utils"
|
|
28
|
-
import { ssoSaveUserNoOp } from "../middleware/passport/sso/sso"
|
|
29
|
-
|
|
30
|
-
const refresh = require("passport-oauth2-refresh")
|
|
31
|
-
|
|
32
|
-
export {
|
|
33
|
-
auditLog,
|
|
34
|
-
authError,
|
|
35
|
-
internalApi,
|
|
36
|
-
ssoCallbackUrl,
|
|
37
|
-
adminOnly,
|
|
38
|
-
builderOnly,
|
|
39
|
-
builderOrAdmin,
|
|
40
|
-
joiValidator,
|
|
41
|
-
google,
|
|
42
|
-
oidc,
|
|
43
|
-
} from "../middleware"
|
|
44
|
-
export const buildAuthMiddleware = authenticated
|
|
45
|
-
export const buildTenancyMiddleware = tenancy
|
|
46
|
-
export const buildCsrfMiddleware = csrf
|
|
47
|
-
export const passport = _passport
|
|
48
|
-
|
|
49
|
-
// Strategies
|
|
50
|
-
_passport.use(new LocalStrategy(local.options, local.authenticate))
|
|
51
|
-
|
|
52
|
-
async function refreshOIDCAccessToken(
|
|
53
|
-
chosenConfig: OIDCInnerConfig,
|
|
54
|
-
refreshToken: string
|
|
55
|
-
): Promise<RefreshResponse> {
|
|
56
|
-
const callbackUrl = await oidc.getCallbackUrl()
|
|
57
|
-
let enrichedConfig: any
|
|
58
|
-
let strategy: any
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
enrichedConfig = await oidc.fetchStrategyConfig(chosenConfig, callbackUrl)
|
|
62
|
-
if (!enrichedConfig) {
|
|
63
|
-
throw new Error("OIDC Config contents invalid")
|
|
64
|
-
}
|
|
65
|
-
strategy = await oidc.strategyFactory(enrichedConfig, ssoSaveUserNoOp)
|
|
66
|
-
} catch (err) {
|
|
67
|
-
throw new Error("Could not refresh OAuth Token")
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
refresh.use(strategy, {
|
|
71
|
-
setRefreshOAuth2() {
|
|
72
|
-
return strategy._getOAuth2Client(enrichedConfig)
|
|
73
|
-
},
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
return new Promise(resolve => {
|
|
77
|
-
refresh.requestNewAccessToken(
|
|
78
|
-
ConfigType.OIDC,
|
|
79
|
-
refreshToken,
|
|
80
|
-
(err: any, accessToken: string, refreshToken: any, params: any) => {
|
|
81
|
-
resolve({ err, accessToken, refreshToken, params })
|
|
82
|
-
}
|
|
83
|
-
)
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async function refreshGoogleAccessToken(
|
|
88
|
-
config: GoogleInnerConfig,
|
|
89
|
-
refreshToken: any
|
|
90
|
-
): Promise<RefreshResponse> {
|
|
91
|
-
let callbackUrl = await google.getCallbackUrl(config)
|
|
92
|
-
|
|
93
|
-
let strategy
|
|
94
|
-
try {
|
|
95
|
-
strategy = await google.strategyFactory(
|
|
96
|
-
config,
|
|
97
|
-
callbackUrl,
|
|
98
|
-
ssoSaveUserNoOp
|
|
99
|
-
)
|
|
100
|
-
} catch (err: any) {
|
|
101
|
-
throw new Error(
|
|
102
|
-
`Error constructing OIDC refresh strategy: message=${err.message}`
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
refresh.use(strategy)
|
|
107
|
-
|
|
108
|
-
return new Promise(resolve => {
|
|
109
|
-
refresh.requestNewAccessToken(
|
|
110
|
-
ConfigType.GOOGLE,
|
|
111
|
-
refreshToken,
|
|
112
|
-
(err: any, accessToken: string, refreshToken: string, params: any) => {
|
|
113
|
-
resolve({ err, accessToken, refreshToken, params })
|
|
114
|
-
}
|
|
115
|
-
)
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
interface RefreshResponse {
|
|
120
|
-
err?: {
|
|
121
|
-
data?: string
|
|
122
|
-
}
|
|
123
|
-
accessToken?: string
|
|
124
|
-
refreshToken?: string
|
|
125
|
-
params?: any
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export async function refreshOAuthToken(
|
|
129
|
-
refreshToken: string,
|
|
130
|
-
providerType: SSOProviderType,
|
|
131
|
-
configId?: string
|
|
132
|
-
): Promise<RefreshResponse> {
|
|
133
|
-
switch (providerType) {
|
|
134
|
-
case SSOProviderType.OIDC: {
|
|
135
|
-
if (!configId) {
|
|
136
|
-
return { err: { data: "OIDC config id not provided" } }
|
|
137
|
-
}
|
|
138
|
-
const oidcConfig = await configs.getOIDCConfigById(configId)
|
|
139
|
-
if (!oidcConfig) {
|
|
140
|
-
return { err: { data: "OIDC configuration not found" } }
|
|
141
|
-
}
|
|
142
|
-
return refreshOIDCAccessToken(oidcConfig, refreshToken)
|
|
143
|
-
}
|
|
144
|
-
case SSOProviderType.GOOGLE: {
|
|
145
|
-
let googleConfig = await configs.getGoogleConfig()
|
|
146
|
-
if (!googleConfig) {
|
|
147
|
-
return { err: { data: "Google configuration not found" } }
|
|
148
|
-
}
|
|
149
|
-
return refreshGoogleAccessToken(googleConfig, refreshToken)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// TODO: Refactor to use user save function instead to prevent the need for
|
|
155
|
-
// manually saving and invalidating on callback
|
|
156
|
-
export async function updateUserOAuth(userId: string, oAuthConfig: any) {
|
|
157
|
-
const details = {
|
|
158
|
-
accessToken: oAuthConfig.accessToken,
|
|
159
|
-
refreshToken: oAuthConfig.refreshToken,
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
try {
|
|
163
|
-
const db = getGlobalDB()
|
|
164
|
-
const dbUser = await db.get<any>(userId)
|
|
165
|
-
|
|
166
|
-
//Do not overwrite the refresh token if a valid one is not provided.
|
|
167
|
-
if (typeof details.refreshToken !== "string") {
|
|
168
|
-
delete details.refreshToken
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
dbUser.oauth2 = {
|
|
172
|
-
...dbUser.oauth2,
|
|
173
|
-
...details,
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
await db.put(dbUser)
|
|
177
|
-
|
|
178
|
-
await invalidateUser(userId)
|
|
179
|
-
} catch (e) {
|
|
180
|
-
console.error("Could not update OAuth details for current user", e)
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Logs a user out from budibase. Re-used across account portal and builder.
|
|
186
|
-
*/
|
|
187
|
-
export async function platformLogout(opts: PlatformLogoutOpts) {
|
|
188
|
-
const ctx = opts.ctx
|
|
189
|
-
const userId = opts.userId
|
|
190
|
-
const keepActiveSession = opts.keepActiveSession
|
|
191
|
-
|
|
192
|
-
if (!ctx) throw new Error("Koa context must be supplied to logout.")
|
|
193
|
-
|
|
194
|
-
const currentSession = getCookie<SessionCookie>(ctx, Cookie.Auth)
|
|
195
|
-
let sessions = await getSessionsForUser(userId)
|
|
196
|
-
|
|
197
|
-
if (currentSession && keepActiveSession) {
|
|
198
|
-
sessions = sessions.filter(
|
|
199
|
-
session => session.sessionId !== currentSession.sessionId
|
|
200
|
-
)
|
|
201
|
-
} else {
|
|
202
|
-
// clear cookies
|
|
203
|
-
clearCookie(ctx, Cookie.Auth)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const sessionIds = sessions.map(({ sessionId }) => sessionId)
|
|
207
|
-
await invalidateSessions(userId, { sessionIds, reason: "logout" })
|
|
208
|
-
await events.auth.logout(ctx.user?.email)
|
|
209
|
-
await userCache.invalidateUser(userId)
|
|
210
|
-
}
|
package/src/auth/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./auth"
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { structures } from "../../../tests"
|
|
2
|
-
import { testEnv } from "../../../tests/extra"
|
|
3
|
-
import * as auth from "../auth"
|
|
4
|
-
import * as events from "../../events"
|
|
5
|
-
|
|
6
|
-
describe("platformLogout", () => {
|
|
7
|
-
it("should call platform logout", async () => {
|
|
8
|
-
await testEnv.withTenant(async () => {
|
|
9
|
-
const ctx = structures.koa.newContext()
|
|
10
|
-
await auth.platformLogout({ ctx, userId: "test" })
|
|
11
|
-
expect(events.auth.logout).toHaveBeenCalledTimes(1)
|
|
12
|
-
})
|
|
13
|
-
})
|
|
14
|
-
})
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import dns from "dns"
|
|
2
|
-
import net from "net"
|
|
3
|
-
import env from "../environment"
|
|
4
|
-
import { promisify } from "util"
|
|
5
|
-
|
|
6
|
-
let blackListArray: string[] | undefined
|
|
7
|
-
const performLookup = promisify(dns.lookup)
|
|
8
|
-
|
|
9
|
-
async function lookup(address: string): Promise<string[]> {
|
|
10
|
-
if (!net.isIP(address)) {
|
|
11
|
-
// need this for URL parsing simply
|
|
12
|
-
if (!address.startsWith("http")) {
|
|
13
|
-
address = `https://${address}`
|
|
14
|
-
}
|
|
15
|
-
address = new URL(address).hostname
|
|
16
|
-
}
|
|
17
|
-
const addresses = await performLookup(address, {
|
|
18
|
-
all: true,
|
|
19
|
-
})
|
|
20
|
-
return addresses.map(addr => addr.address)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function refreshBlacklist() {
|
|
24
|
-
const blacklist = env.BLACKLIST_IPS
|
|
25
|
-
const list = blacklist?.split(",") || []
|
|
26
|
-
let final: string[] = []
|
|
27
|
-
for (let addr of list) {
|
|
28
|
-
const trimmed = addr.trim()
|
|
29
|
-
if (!net.isIP(trimmed)) {
|
|
30
|
-
const addresses = await lookup(trimmed)
|
|
31
|
-
final = final.concat(addresses)
|
|
32
|
-
} else {
|
|
33
|
-
final.push(trimmed)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
blackListArray = final
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export async function isBlacklisted(address: string): Promise<boolean> {
|
|
40
|
-
if (!blackListArray) {
|
|
41
|
-
await refreshBlacklist()
|
|
42
|
-
}
|
|
43
|
-
if (blackListArray?.length === 0) {
|
|
44
|
-
return false
|
|
45
|
-
}
|
|
46
|
-
// no need for DNS
|
|
47
|
-
let ips: string[]
|
|
48
|
-
if (!net.isIP(address)) {
|
|
49
|
-
ips = await lookup(address)
|
|
50
|
-
} else {
|
|
51
|
-
ips = [address]
|
|
52
|
-
}
|
|
53
|
-
return !!blackListArray?.find(addr => ips.includes(addr))
|
|
54
|
-
}
|
package/src/blacklist/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./blacklist"
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { refreshBlacklist, isBlacklisted } from ".."
|
|
2
|
-
import env from "../../environment"
|
|
3
|
-
|
|
4
|
-
describe("blacklist", () => {
|
|
5
|
-
beforeAll(async () => {
|
|
6
|
-
env._set(
|
|
7
|
-
"BLACKLIST_IPS",
|
|
8
|
-
"www.google.com,192.168.1.1, 1.1.1.1,2.2.2.2/something"
|
|
9
|
-
)
|
|
10
|
-
await refreshBlacklist()
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it("should blacklist 192.168.1.1", async () => {
|
|
14
|
-
expect(await isBlacklisted("192.168.1.1")).toBe(true)
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it("should allow 192.168.1.2", async () => {
|
|
18
|
-
expect(await isBlacklisted("192.168.1.2")).toBe(false)
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it("should blacklist www.google.com", async () => {
|
|
22
|
-
expect(await isBlacklisted("www.google.com")).toBe(true)
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it("should handle a complex domain", async () => {
|
|
26
|
-
expect(
|
|
27
|
-
await isBlacklisted("https://www.google.com/derp/?something=1")
|
|
28
|
-
).toBe(true)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it("should allow www.microsoft.com", async () => {
|
|
32
|
-
expect(await isBlacklisted("www.microsoft.com")).toBe(false)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it("should blacklist an IP that needed trimming", async () => {
|
|
36
|
-
expect(await isBlacklisted("1.1.1.1")).toBe(true)
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it("should blacklist 1.1.1.1/something", async () => {
|
|
40
|
-
expect(await isBlacklisted("1.1.1.1/something")).toBe(true)
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it("should blacklist 2.2.2.2", async () => {
|
|
44
|
-
expect(await isBlacklisted("2.2.2.2")).toBe(true)
|
|
45
|
-
})
|
|
46
|
-
})
|
package/src/cache/appMetadata.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { getAppClient } from "../redis/init"
|
|
2
|
-
import { doWithDB, DocumentType } from "../db"
|
|
3
|
-
import { Database, App } from "@budibase/types"
|
|
4
|
-
|
|
5
|
-
export enum AppState {
|
|
6
|
-
INVALID = "invalid",
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface DeletedApp {
|
|
10
|
-
state: AppState
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const EXPIRY_SECONDS = 3600
|
|
14
|
-
const INVALID_EXPIRY_SECONDS = 60
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* The default populate app metadata function
|
|
18
|
-
*/
|
|
19
|
-
async function populateFromDB(appId: string) {
|
|
20
|
-
return doWithDB(
|
|
21
|
-
appId,
|
|
22
|
-
(db: Database) => {
|
|
23
|
-
return db.get<App>(DocumentType.APP_METADATA)
|
|
24
|
-
},
|
|
25
|
-
{ skip_setup: true }
|
|
26
|
-
)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function isInvalid(metadata?: { state: string }) {
|
|
30
|
-
return !metadata || metadata.state === AppState.INVALID
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Get the requested app metadata by id.
|
|
35
|
-
* Use redis cache to first read the app metadata.
|
|
36
|
-
* If not present fallback to loading the app metadata directly and re-caching.
|
|
37
|
-
* @param appId the id of the app to get metadata from.
|
|
38
|
-
* @returns the app metadata.
|
|
39
|
-
*/
|
|
40
|
-
export async function getAppMetadata(appId: string): Promise<App | DeletedApp> {
|
|
41
|
-
const client = await getAppClient()
|
|
42
|
-
// try cache
|
|
43
|
-
let metadata = await client.get(appId)
|
|
44
|
-
if (!metadata) {
|
|
45
|
-
let expiry: number | undefined = EXPIRY_SECONDS
|
|
46
|
-
try {
|
|
47
|
-
metadata = await populateFromDB(appId)
|
|
48
|
-
} catch (err: any) {
|
|
49
|
-
// app DB left around, but no metadata, it is invalid
|
|
50
|
-
if (err && err.status === 404) {
|
|
51
|
-
metadata = { state: AppState.INVALID }
|
|
52
|
-
// expire invalid apps regularly, in-case it was only briefly invalid
|
|
53
|
-
expiry = INVALID_EXPIRY_SECONDS
|
|
54
|
-
} else {
|
|
55
|
-
throw err
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
// needed for some scenarios where the caching happens
|
|
59
|
-
// so quickly the requests can get slightly out of sync
|
|
60
|
-
// might store its invalid just before it stores its valid
|
|
61
|
-
if (isInvalid(metadata)) {
|
|
62
|
-
const temp = await client.get(appId)
|
|
63
|
-
if (temp) {
|
|
64
|
-
metadata = temp
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
await client.store(appId, metadata, expiry)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return metadata
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Invalidate/reset the cached metadata when a change occurs in the db.
|
|
75
|
-
* @param appId the cache key to bust/update.
|
|
76
|
-
* @param newMetadata optional - can simply provide the new metadata to update with.
|
|
77
|
-
* @return will respond with success when cache is updated.
|
|
78
|
-
*/
|
|
79
|
-
export async function invalidateAppMetadata(appId: string, newMetadata?: any) {
|
|
80
|
-
if (!appId) {
|
|
81
|
-
throw "Cannot invalidate if no app ID provided."
|
|
82
|
-
}
|
|
83
|
-
const client = await getAppClient()
|
|
84
|
-
await client.delete(appId)
|
|
85
|
-
if (newMetadata) {
|
|
86
|
-
await client.store(appId, newMetadata, EXPIRY_SECONDS)
|
|
87
|
-
}
|
|
88
|
-
}
|
package/src/cache/base/index.ts
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { getTenantId } from "../../context"
|
|
2
|
-
import * as redis from "../../redis/init"
|
|
3
|
-
import { Client } from "../../redis"
|
|
4
|
-
|
|
5
|
-
function generateTenantKey(key: string) {
|
|
6
|
-
const tenantId = getTenantId()
|
|
7
|
-
return `${key}:${tenantId}`
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export default class BaseCache {
|
|
11
|
-
client: Client | undefined
|
|
12
|
-
|
|
13
|
-
constructor(client: Client | undefined = undefined) {
|
|
14
|
-
this.client = client
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async getClient() {
|
|
18
|
-
return !this.client ? await redis.getCacheClient() : this.client
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async keys(pattern: string) {
|
|
22
|
-
const client = await this.getClient()
|
|
23
|
-
return client.keys(pattern)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async exists(key: string, opts = { useTenancy: true }) {
|
|
27
|
-
key = opts.useTenancy ? generateTenantKey(key) : key
|
|
28
|
-
const client = await this.getClient()
|
|
29
|
-
return client.exists(key)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async scan(key: string, opts = { useTenancy: true }) {
|
|
33
|
-
key = opts.useTenancy ? generateTenantKey(key) : key
|
|
34
|
-
const client = await this.getClient()
|
|
35
|
-
return client.scan(key)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Read only from the cache.
|
|
40
|
-
*/
|
|
41
|
-
async get(key: string, opts = { useTenancy: true }) {
|
|
42
|
-
key = opts.useTenancy ? generateTenantKey(key) : key
|
|
43
|
-
const client = await this.getClient()
|
|
44
|
-
return client.get(key)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Read only from the cache.
|
|
49
|
-
*/
|
|
50
|
-
async bulkGet<T>(keys: string[], opts = { useTenancy: true }) {
|
|
51
|
-
keys = opts.useTenancy ? keys.map(key => generateTenantKey(key)) : keys
|
|
52
|
-
const client = await this.getClient()
|
|
53
|
-
return client.bulkGet<T>(keys)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Write to the cache.
|
|
58
|
-
*/
|
|
59
|
-
async store(
|
|
60
|
-
key: string,
|
|
61
|
-
value: any,
|
|
62
|
-
ttl: number | null = null,
|
|
63
|
-
opts = { useTenancy: true }
|
|
64
|
-
) {
|
|
65
|
-
key = opts.useTenancy ? generateTenantKey(key) : key
|
|
66
|
-
const client = await this.getClient()
|
|
67
|
-
await client.store(key, value, ttl)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Bulk write to the cache.
|
|
72
|
-
*/
|
|
73
|
-
async bulkStore(
|
|
74
|
-
data: Record<string, any>,
|
|
75
|
-
ttl: number | null = null,
|
|
76
|
-
opts = { useTenancy: true }
|
|
77
|
-
) {
|
|
78
|
-
if (opts.useTenancy) {
|
|
79
|
-
data = Object.entries(data).reduce((acc, [key, value]) => {
|
|
80
|
-
acc[generateTenantKey(key)] = value
|
|
81
|
-
return acc
|
|
82
|
-
}, {} as Record<string, any>)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const client = await this.getClient()
|
|
86
|
-
await client.bulkStore(data, ttl)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Remove from cache.
|
|
91
|
-
*/
|
|
92
|
-
async delete(key: string, opts = { useTenancy: true }) {
|
|
93
|
-
key = opts.useTenancy ? generateTenantKey(key) : key
|
|
94
|
-
const client = await this.getClient()
|
|
95
|
-
return client.delete(key)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Remove from cache.
|
|
100
|
-
*/
|
|
101
|
-
async bulkDelete(keys: string[], opts = { useTenancy: true }) {
|
|
102
|
-
keys = opts.useTenancy ? keys.map(key => generateTenantKey(key)) : keys
|
|
103
|
-
const client = await this.getClient()
|
|
104
|
-
return client.bulkDelete(keys)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Read from the cache. Write to the cache if not exists.
|
|
109
|
-
*/
|
|
110
|
-
async withCache<T>(
|
|
111
|
-
key: string,
|
|
112
|
-
ttl: number | null = null,
|
|
113
|
-
fetchFn: () => Promise<T> | T,
|
|
114
|
-
opts = { useTenancy: true }
|
|
115
|
-
): Promise<T> {
|
|
116
|
-
const cachedValue = await this.get(key, opts)
|
|
117
|
-
if (cachedValue) {
|
|
118
|
-
return cachedValue
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
const fetchedValue = await fetchFn()
|
|
123
|
-
|
|
124
|
-
await this.store(key, fetchedValue, ttl, opts)
|
|
125
|
-
return fetchedValue
|
|
126
|
-
} catch (err) {
|
|
127
|
-
console.error("Error fetching before cache - ", err)
|
|
128
|
-
throw err
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async bustCache(key: string) {
|
|
133
|
-
const client = await this.getClient()
|
|
134
|
-
try {
|
|
135
|
-
await client.delete(generateTenantKey(key))
|
|
136
|
-
} catch (err) {
|
|
137
|
-
console.error("Error busting cache - ", err)
|
|
138
|
-
throw err
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Delete the entry if the provided value matches the stored one.
|
|
144
|
-
*/
|
|
145
|
-
async deleteIfValue(key: string, value: any, opts = { useTenancy: true }) {
|
|
146
|
-
key = opts.useTenancy ? generateTenantKey(key) : key
|
|
147
|
-
const client = await this.getClient()
|
|
148
|
-
await client.deleteIfValue(key, value)
|
|
149
|
-
}
|
|
150
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { AnyDocument, Database } from "@budibase/types"
|
|
2
|
-
|
|
3
|
-
import { JobQueue, Queue, createQueue } from "../queue"
|
|
4
|
-
import * as dbUtils from "../db"
|
|
5
|
-
|
|
6
|
-
interface ProcessDocMessage {
|
|
7
|
-
dbName: string
|
|
8
|
-
docId: string
|
|
9
|
-
data: Record<string, any>
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const PERSIST_MAX_ATTEMPTS = 100
|
|
13
|
-
let processor: DocWritethroughProcessor | undefined
|
|
14
|
-
|
|
15
|
-
export class DocWritethroughProcessor {
|
|
16
|
-
private static _queue: Queue
|
|
17
|
-
|
|
18
|
-
public static get queue() {
|
|
19
|
-
if (!DocWritethroughProcessor._queue) {
|
|
20
|
-
DocWritethroughProcessor._queue = createQueue<ProcessDocMessage>(
|
|
21
|
-
JobQueue.DOC_WRITETHROUGH_QUEUE,
|
|
22
|
-
{
|
|
23
|
-
jobOptions: {
|
|
24
|
-
attempts: PERSIST_MAX_ATTEMPTS,
|
|
25
|
-
},
|
|
26
|
-
}
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return DocWritethroughProcessor._queue
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
init() {
|
|
34
|
-
DocWritethroughProcessor.queue.process(async message => {
|
|
35
|
-
try {
|
|
36
|
-
await this.persistToDb(message.data)
|
|
37
|
-
} catch (err: any) {
|
|
38
|
-
if (err.status === 409) {
|
|
39
|
-
// If we get a 409, it means that another job updated it meanwhile. We want to retry it to persist it again.
|
|
40
|
-
throw new Error(
|
|
41
|
-
`Conflict persisting message ${message.id}. Attempt ${message.attemptsMade}`
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
throw err
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
return this
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private async persistToDb({
|
|
52
|
-
dbName,
|
|
53
|
-
docId,
|
|
54
|
-
data,
|
|
55
|
-
}: {
|
|
56
|
-
dbName: string
|
|
57
|
-
docId: string
|
|
58
|
-
data: Record<string, any>
|
|
59
|
-
}) {
|
|
60
|
-
const db = dbUtils.getDB(dbName)
|
|
61
|
-
let doc: AnyDocument | undefined
|
|
62
|
-
try {
|
|
63
|
-
doc = await db.get(docId)
|
|
64
|
-
} catch {
|
|
65
|
-
doc = { _id: docId }
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
doc = { ...doc, ...data }
|
|
69
|
-
await db.put(doc)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export class DocWritethrough {
|
|
74
|
-
private db: Database
|
|
75
|
-
private _docId: string
|
|
76
|
-
|
|
77
|
-
constructor(db: Database, docId: string) {
|
|
78
|
-
this.db = db
|
|
79
|
-
this._docId = docId
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
get docId() {
|
|
83
|
-
return this._docId
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async patch(data: Record<string, any>) {
|
|
87
|
-
await DocWritethroughProcessor.queue.add({
|
|
88
|
-
dbName: this.db.name,
|
|
89
|
-
docId: this.docId,
|
|
90
|
-
data,
|
|
91
|
-
})
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function init(): DocWritethroughProcessor {
|
|
96
|
-
processor = new DocWritethroughProcessor().init()
|
|
97
|
-
return processor
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function getProcessor(): DocWritethroughProcessor {
|
|
101
|
-
if (!processor) {
|
|
102
|
-
return init()
|
|
103
|
-
}
|
|
104
|
-
return processor
|
|
105
|
-
}
|
package/src/cache/generic.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import BaseCache from "./base"
|
|
2
|
-
|
|
3
|
-
const GENERIC = new BaseCache()
|
|
4
|
-
|
|
5
|
-
export enum CacheKey {
|
|
6
|
-
CHECKLIST = "checklist",
|
|
7
|
-
INSTALLATION = "installation",
|
|
8
|
-
ANALYTICS_ENABLED = "analyticsEnabled",
|
|
9
|
-
UNIQUE_TENANT_ID = "uniqueTenantId",
|
|
10
|
-
EVENTS = "events",
|
|
11
|
-
BACKFILL_METADATA = "backfillMetadata",
|
|
12
|
-
EVENTS_RATE_LIMIT = "eventsRateLimit",
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export enum TTL {
|
|
16
|
-
ONE_MINUTE = 600,
|
|
17
|
-
ONE_HOUR = 3600,
|
|
18
|
-
ONE_DAY = 86400,
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const keys = (...args: Parameters<typeof GENERIC.keys>) =>
|
|
22
|
-
GENERIC.keys(...args)
|
|
23
|
-
export const get = (...args: Parameters<typeof GENERIC.get>) =>
|
|
24
|
-
GENERIC.get(...args)
|
|
25
|
-
export const store = (...args: Parameters<typeof GENERIC.store>) =>
|
|
26
|
-
GENERIC.store(...args)
|
|
27
|
-
export const destroy = (...args: Parameters<typeof GENERIC.delete>) =>
|
|
28
|
-
GENERIC.delete(...args)
|
|
29
|
-
export const withCache = <T>(
|
|
30
|
-
...args: Parameters<typeof GENERIC.withCache<T>>
|
|
31
|
-
) => GENERIC.withCache(...args)
|
|
32
|
-
export const bustCache = (...args: Parameters<typeof GENERIC.bustCache>) =>
|
|
33
|
-
GENERIC.bustCache(...args)
|