@platformatic/composer 3.0.0-alpha.4 → 3.0.0-alpha.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.
Files changed (49) hide show
  1. package/LICENSE +1 -1
  2. package/eslint.config.js +1 -8
  3. package/index.d.ts +1 -58
  4. package/index.js +9 -30
  5. package/package.json +8 -54
  6. package/schema.json +1136 -907
  7. package/scripts/schema.js +12 -0
  8. package/config.d.ts +0 -997
  9. package/lib/application.js +0 -186
  10. package/lib/commands/index.js +0 -15
  11. package/lib/commands/openapi-fetch-schemas.js +0 -47
  12. package/lib/composer-hook.js +0 -60
  13. package/lib/errors.js +0 -18
  14. package/lib/generator.js +0 -127
  15. package/lib/graphql-fetch.js +0 -83
  16. package/lib/graphql-generator.js +0 -33
  17. package/lib/graphql.js +0 -24
  18. package/lib/metrics.js +0 -12
  19. package/lib/not-host-constraints.js +0 -31
  20. package/lib/openapi-composer.js +0 -101
  21. package/lib/openapi-config-schema.js +0 -89
  22. package/lib/openapi-generator.js +0 -213
  23. package/lib/openapi-load-config.js +0 -31
  24. package/lib/openapi-modifier.js +0 -128
  25. package/lib/openapi-scalar.js +0 -22
  26. package/lib/proxy.js +0 -265
  27. package/lib/root.js +0 -75
  28. package/lib/schema.js +0 -258
  29. package/lib/stackable.js +0 -88
  30. package/lib/upgrade.js +0 -20
  31. package/lib/utils.js +0 -16
  32. package/lib/versions/2.0.0.js +0 -9
  33. package/lib/versions/3.0.0.js +0 -14
  34. package/public/images/dark_mode.svg +0 -3
  35. package/public/images/ellipse.svg +0 -21
  36. package/public/images/external-link.svg +0 -5
  37. package/public/images/favicon.ico +0 -0
  38. package/public/images/graphiql.svg +0 -10
  39. package/public/images/graphql.svg +0 -10
  40. package/public/images/light_mode.svg +0 -11
  41. package/public/images/openapi.svg +0 -13
  42. package/public/images/platformatic-logo-dark.svg +0 -30
  43. package/public/images/platformatic-logo-light.svg +0 -30
  44. package/public/images/reverse-proxy.svg +0 -8
  45. package/public/images/triangle_dark.svg +0 -3
  46. package/public/images/triangle_light.svg +0 -3
  47. package/public/index.html +0 -253
  48. package/public/index.njk +0 -101
  49. package/public/main.css +0 -244
@@ -1,186 +0,0 @@
1
- import { isKeyEnabled } from '@platformatic/foundation'
2
- import { platformaticService } from '@platformatic/service'
3
- import deepEqual from 'fast-deep-equal'
4
- import { fetchOpenApiSchema } from './commands/openapi-fetch-schemas.js'
5
- import { composerHook } from './composer-hook.js'
6
- import { fetchGraphqlSubgraphs, isSameGraphqlSchema } from './graphql-fetch.js'
7
- import { graphqlGenerator } from './graphql-generator.js'
8
- import { graphql } from './graphql.js'
9
- import { openApiComposer, openApiGenerator } from './openapi-generator.js'
10
- import { proxy } from './proxy.js'
11
- import { isFetchable } from './utils.js'
12
-
13
- const kITC = Symbol.for('plt.runtime.itc')
14
- const EXPERIMENTAL_GRAPHQL_COMPOSER_FEATURE_MESSAGE = 'graphql composer is an experimental feature'
15
-
16
- async function detectServicesUpdate ({ app, services, fetchOpenApiSchema, fetchGraphqlSubgraphs }) {
17
- let changed
18
-
19
- const graphqlServices = []
20
- // assumes services here are fetchable
21
- for (const service of services) {
22
- const { id, origin, openapi, graphql } = service
23
-
24
- if (openapi) {
25
- const currentSchema = app.openApiSchemas.find(schema => schema.id === id)?.originSchema || null
26
-
27
- let fetchedSchema = null
28
- try {
29
- fetchedSchema = await fetchOpenApiSchema({ origin, openapi })
30
- } catch (err) {
31
- app.log.error({ err }, 'failed to fetch schema (watch) for service ' + id)
32
- }
33
-
34
- if (!changed && !deepEqual(fetchedSchema, currentSchema)) {
35
- changed = true
36
- // it stops at first schema difference since all the schemas will be updated on reload
37
- break
38
- }
39
- }
40
-
41
- if (graphql) {
42
- graphqlServices.push(service)
43
- }
44
- }
45
-
46
- if (!changed && graphqlServices.length > 0) {
47
- const graphqlSupergraph = await fetchGraphqlSubgraphs(graphqlServices, app.graphqlComposerOptions, app)
48
- if (!isSameGraphqlSchema(graphqlSupergraph, app.graphqlSupergraph)) {
49
- changed = true
50
- app.graphqlSupergraph = graphqlSupergraph
51
- }
52
- }
53
-
54
- return changed
55
- }
56
-
57
- /**
58
- * poll services to detect changes, every `opts.composer.refreshTimeout`
59
- * polling is disabled on refreshTimeout = 0
60
- * or there are no network openapi nor graphql remote services (the services are from file or they don't have a schema/graph to fetch)
61
- */
62
- async function watchServices (app, { config, stackable }) {
63
- const { services, refreshTimeout } = config.composer
64
- if (refreshTimeout < 1) {
65
- return
66
- }
67
-
68
- const watching = services.filter(isFetchable)
69
- if (watching.length < 1) {
70
- return
71
- }
72
-
73
- if (!globalThis[Symbol.for('plt.runtime.id')]) {
74
- app.log.warn('Watching services is only supported when running within a Platformatic Runtime.')
75
- return
76
- }
77
-
78
- stackable.emit('watch:start')
79
- app.log.info({ services: watching }, 'start watching services')
80
-
81
- const timer = setInterval(async () => {
82
- try {
83
- if (await detectServicesUpdate({ app, services: watching, fetchOpenApiSchema, fetchGraphqlSubgraphs })) {
84
- clearInterval(timer)
85
- app.log.info('detected services changes, restarting ...')
86
-
87
- globalThis[Symbol.for('plt.runtime.itc')].notify('changed')
88
- }
89
- } catch (error) {
90
- app.log.error(
91
- {
92
- err: {
93
- message: error.message,
94
- stack: error.stack
95
- }
96
- },
97
- 'failed to get services info'
98
- )
99
- }
100
- }, refreshTimeout).unref()
101
-
102
- app.addHook('onClose', async () => {
103
- clearInterval(timer)
104
- })
105
- }
106
-
107
- export async function ensureServices (composerId, config) {
108
- if (config.composer?.services?.length) {
109
- return
110
- }
111
-
112
- composerId ??= globalThis.platformatic?.serviceId
113
- config.composer ??= {}
114
- config.composer.services ??= []
115
-
116
- // When no services are defined, all services are exposed in the composer
117
- const services = await globalThis[kITC]?.send('listServices')
118
-
119
- if (services) {
120
- config.composer.services = services
121
- .filter(id => id !== composerId) // Remove ourself
122
- .map(id => ({ id, proxy: { prefix: `/${id}` } }))
123
- }
124
- }
125
-
126
- export async function platformaticComposer (app, stackable) {
127
- const config = await stackable.getConfig()
128
- let hasGraphqlServices, hasOpenapiServices
129
-
130
- // When no services are specified, get the list from the runtime.
131
- await ensureServices(stackable.serviceId, config)
132
-
133
- const { services } = config.composer
134
-
135
- for (const service of services) {
136
- if (!service.origin) {
137
- service.origin = `http://${service.id}.plt.local`
138
- }
139
- if (service.openapi && !hasOpenapiServices) {
140
- hasOpenapiServices = true
141
- }
142
- if (service.graphql && !hasGraphqlServices) {
143
- hasGraphqlServices = true
144
- }
145
- }
146
-
147
- await app.register(composerHook)
148
-
149
- let generatedComposedOpenAPI = null
150
- if (hasOpenapiServices) {
151
- generatedComposedOpenAPI = await openApiGenerator(app, config.composer)
152
- }
153
-
154
- if (isKeyEnabled('healthCheck', config.server)) {
155
- if (typeof config.server.healthCheck !== 'object') {
156
- config.server.healthCheck = {}
157
- }
158
-
159
- config.server.healthCheck.fn = stackable.isHealthy.bind(stackable)
160
- }
161
-
162
- await app.register(proxy, { ...config.composer, stackable, context: stackable.context })
163
-
164
- await platformaticService(app, stackable)
165
-
166
- if (generatedComposedOpenAPI) {
167
- await app.register(openApiComposer, { opts: config.composer, generated: generatedComposedOpenAPI })
168
- }
169
-
170
- if (hasGraphqlServices) {
171
- app.log.warn(EXPERIMENTAL_GRAPHQL_COMPOSER_FEATURE_MESSAGE)
172
- app.register(graphql, config.composer)
173
- await app.register(graphqlGenerator, config.composer)
174
- }
175
-
176
- if (!app.hasRoute({ url: '/', method: 'GET' }) && !app.hasRoute({ url: '/*', method: 'GET' })) {
177
- const rootHandler = await import('./root.js')
178
- await app.register(rootHandler.default, config)
179
- }
180
-
181
- if (!stackable.context?.isProduction) {
182
- await watchServices(app, { config, stackable, context: stackable.context })
183
- }
184
- }
185
-
186
- platformaticComposer[Symbol.for('skip-override')] = true
@@ -1,15 +0,0 @@
1
- import { fetchOpenApiSchemas } from './openapi-fetch-schemas.js'
2
-
3
- export function createCommands (id) {
4
- return {
5
- commands: {
6
- [`${id}:fetch-openapi-schemas`]: fetchOpenApiSchemas
7
- },
8
- help: {
9
- [`${id}:fetch-openapi-schemas`]: {
10
- usage: `${id}:fetch-openapi-schemas`,
11
- description: 'Fetch OpenAPI schemas from remote services'
12
- }
13
- }
14
- }
15
- }
@@ -1,47 +0,0 @@
1
- import { loadConfiguration } from '@platformatic/foundation'
2
- import { writeFile } from 'node:fs/promises'
3
- import { request } from 'undici'
4
- import { FailedToFetchOpenAPISchemaError } from '../errors.js'
5
- import { schema } from '../schema.js'
6
- import { prefixWithSlash } from '../utils.js'
7
-
8
- export async function fetchOpenApiSchema (service) {
9
- const { origin, openapi } = service
10
-
11
- const openApiUrl = origin + prefixWithSlash(openapi.url)
12
- const { statusCode, body } = await request(openApiUrl)
13
-
14
- if (statusCode !== 200 && statusCode !== 201) {
15
- throw new FailedToFetchOpenAPISchemaError(openApiUrl)
16
- }
17
- const schema = await body.json()
18
-
19
- if (openapi.file !== undefined) {
20
- await writeFile(openapi.file, JSON.stringify(schema, null, 2))
21
- }
22
-
23
- return schema
24
- }
25
-
26
- export async function fetchOpenApiSchemas (logger, configFile, _args, { colorette }) {
27
- const { bold } = colorette
28
- const config = await loadConfiguration(configFile, schema)
29
- const { services } = config.composer
30
-
31
- const servicesWithValidOpenApi = services.filter(({ openapi }) => openapi && openapi.url && openapi.file)
32
-
33
- const fetchOpenApiRequests = servicesWithValidOpenApi.map(service => fetchOpenApiSchema(service))
34
-
35
- const fetchOpenApiResults = await Promise.allSettled(fetchOpenApiRequests)
36
-
37
- logger.info('Fetching schemas for all services.')
38
-
39
- fetchOpenApiResults.forEach((result, index) => {
40
- const serviceId = servicesWithValidOpenApi[index].id
41
- if (result.status === 'rejected') {
42
- logger.error(`Failed to fetch OpenAPI schema for service with id ${bold(serviceId)}: ${result.reason}`)
43
- } else {
44
- logger.info(`Successfully fetched OpenAPI schema for service with id ${bold(serviceId)}`)
45
- }
46
- })
47
- }
@@ -1,60 +0,0 @@
1
- import fp from 'fastify-plugin'
2
- import rfdc from 'rfdc'
3
- import { FastifyInstanceIsAlreadyListeningError } from './errors.js'
4
-
5
- const deepClone = rfdc()
6
-
7
- async function composerHookPlugin (app) {
8
- const onRoutesHooks = {}
9
-
10
- app.addHook('onRoute', routeOptions => {
11
- if (routeOptions.schema) {
12
- routeOptions.schema = deepClone(routeOptions.schema)
13
- }
14
-
15
- const method = routeOptions.method
16
- const openApiPath = routeOptions.config?.openApiPath
17
-
18
- const onRouteHooks = onRoutesHooks[openApiPath]?.[method]
19
- if (Array.isArray(onRouteHooks)) {
20
- for (const onRouteHook of onRouteHooks) {
21
- onRouteHook(routeOptions)
22
- }
23
- }
24
- })
25
-
26
- let isApplicationReady = false
27
- app.addHook('onReady', () => {
28
- isApplicationReady = true
29
- })
30
-
31
- function addComposerOnRouteHook (openApiPath, methods, hook) {
32
- /* c8 ignore next 5 */
33
- if (isApplicationReady) {
34
- throw new FastifyInstanceIsAlreadyListeningError()
35
- }
36
-
37
- if (onRoutesHooks[openApiPath] === undefined) {
38
- onRoutesHooks[openApiPath] = {}
39
- }
40
-
41
- const routeHooks = onRoutesHooks[openApiPath]
42
-
43
- for (let method of methods) {
44
- method = method.toUpperCase()
45
-
46
- if (routeHooks[method] === undefined) {
47
- routeHooks[method] = []
48
- }
49
- routeHooks[method].push(hook)
50
- }
51
- }
52
-
53
- Object.defineProperty(app.platformatic, 'addComposerOnRouteHook', {
54
- value: addComposerOnRouteHook,
55
- writable: false,
56
- configurable: false
57
- })
58
- }
59
-
60
- export const composerHook = fp(composerHookPlugin)
package/lib/errors.js DELETED
@@ -1,18 +0,0 @@
1
- import createError from '@fastify/error'
2
-
3
- const ERROR_PREFIX = 'PLT_COMPOSER'
4
-
5
- export const FastifyInstanceIsAlreadyListeningError = createError(
6
- `${ERROR_PREFIX}_FASTIFY_INSTANCE_IS_ALREADY_LISTENING`,
7
- 'Fastify instance is already listening. Cannot call "addComposerOnRouteHook"!'
8
- )
9
- export const FailedToFetchOpenAPISchemaError = createError(
10
- `${ERROR_PREFIX}_FAILED_TO_FETCH_OPENAPI_SCHEMA`,
11
- 'Failed to fetch OpenAPI schema from %s'
12
- )
13
- export const ValidationErrors = createError(`${ERROR_PREFIX}_VALIDATION_ERRORS`, 'Validation errors: %s')
14
- export const PathAlreadyExistsError = createError(`${ERROR_PREFIX}_PATH_ALREADY_EXISTS`, 'Path "%s" already exists')
15
- export const CouldNotReadOpenAPIConfigError = createError(
16
- `${ERROR_PREFIX}_COULD_NOT_READ_OPENAPI_CONFIG`,
17
- 'Could not read openapi config for "%s" service'
18
- )
package/lib/generator.js DELETED
@@ -1,127 +0,0 @@
1
- import { Generator as ServiceGenerator } from '@platformatic/service'
2
-
3
- export class Generator extends ServiceGenerator {
4
- constructor (opts) {
5
- super({
6
- ...opts,
7
- module: '@platformatic/composer'
8
- })
9
- }
10
-
11
- getDefaultConfig () {
12
- const defaultBaseConfig = super.getDefaultConfig()
13
-
14
- return {
15
- ...defaultBaseConfig,
16
- plugin: false,
17
- routes: false,
18
- tests: false
19
- }
20
- }
21
-
22
- async _beforePrepare () {
23
- if (this.config.isUpdating) {
24
- return
25
- }
26
-
27
- await super._beforePrepare()
28
-
29
- this.addEnvVars(
30
- {
31
- PLT_EXAMPLE_ORIGIN: 'http://127.0.0.1:3043'
32
- },
33
- { overwrite: false, default: true }
34
- )
35
-
36
- this.config.dependencies = {
37
- '@platformatic/composer': `^${this.platformaticVersion}`
38
- }
39
- }
40
-
41
- async _afterPrepare () {
42
- if (this.config.isUpdating) {
43
- return
44
- }
45
-
46
- await super._afterPrepare()
47
- const PLT_ENVIRONMENT_TEMPLATE = `
48
- import { type FastifyInstance } from 'fastify'
49
- import { PlatformaticApplication, PlatformaticComposerConfig } from '@platformatic/composer'
50
-
51
- declare module 'fastify' {
52
- interface FastifyInstance {
53
- platformatic: PlatformaticApplication<PlatformaticComposerConfig>
54
- }
55
- }
56
- `
57
-
58
- const README = `
59
- # Platformatic Composer API
60
-
61
- This is a generated [Platformatic Composer](https://docs.platformatic.dev/docs/composer/overview) application.
62
-
63
- ## Requirements
64
-
65
- Platformatic supports macOS, Linux and Windows ([WSL](https://docs.microsoft.com/windows/wsl/) recommended).
66
- You'll need to have [Node.js](https://nodejs.org/) >= v18.8.0 or >= v20.6.0
67
-
68
- ## Setup
69
-
70
- 1. Install dependencies:
71
-
72
- \`\`\`bash
73
- npm install
74
- \`\`\`
75
-
76
- ## Usage
77
-
78
- Run the API with:
79
-
80
- \`\`\`bash
81
- npm start
82
- \`\`\`
83
-
84
- ### Explore
85
- - ⚡ The Platformatic Composer server is running at http://localhost:3042/
86
- - 📔 View the REST API's Swagger documentation at http://localhost:3042/documentation/
87
- `
88
-
89
- this.addFile({ path: '', file: 'plt-env.d.ts', contents: PLT_ENVIRONMENT_TEMPLATE })
90
- this.addFile({ path: '', file: 'README.md', contents: README })
91
- }
92
-
93
- async _getConfigFileContents () {
94
- const config = await super._getConfigFileContents()
95
- delete config.service
96
- config.$schema = `https://schemas.platformatic.dev/@platformatic/composer/${this.platformaticVersion}.json`
97
-
98
- config.composer = {
99
- services: [
100
- {
101
- id: 'example',
102
- origin: `{${this.getEnvVarName('PLT_EXAMPLE_ORIGIN')}}`,
103
- openapi: {
104
- url: '/documentation/json'
105
- }
106
- }
107
- ],
108
- refreshTimeout: 1000
109
- }
110
-
111
- if (this.runtime !== null) {
112
- config.composer.services = this.runtime.services
113
- .filter(serviceMeta => serviceMeta.service.module !== '@platformatic/composer')
114
- .map(serviceMeta => {
115
- return {
116
- id: serviceMeta.name,
117
- openapi: {
118
- url: '/documentation/json',
119
- prefix: `/${serviceMeta.name}`
120
- }
121
- }
122
- })
123
- }
124
-
125
- return config
126
- }
127
- }
@@ -1,83 +0,0 @@
1
- import { compose } from '@platformatic/graphql-composer'
2
-
3
- const placeholderSdl = 'Query { _info: String }'
4
- const placeholderResolvers = { Query: { _info: '@platformatic/composer' } }
5
-
6
- // TODO support subscriptions
7
- // const defaultSubscriptionsOptions = {
8
- // onError: function onComposerSubscriptionsError (ctx, topic, err) {
9
- // // TODO log.error({err})
10
- // throw err
11
- // },
12
- // publish (ctx, topic, payload) {
13
- // ctx.pubsub.publish({ topic, payload })
14
- // },
15
- // subscribe (ctx, topic) {
16
- // return ctx.pubsub.subscribe(topic)
17
- // },
18
- // unsubscribe (ctx, topic) {
19
- // ctx.pubsub.close()
20
- // }
21
- // }
22
-
23
- function toComposerOptions (options, app) {
24
- return {
25
- logger: app.log,
26
- defaultArgsAdapter: options?.defaultArgsAdapter,
27
- addEntitiesResolvers: options?.addEntitiesResolvers,
28
- entities: options?.entities,
29
- onSubgraphError: (err, subgraphName) => {
30
- app.log.error({ err }, 'graphql composer error on subgraph ' + subgraphName)
31
-
32
- if (options?.onSubgraphError) {
33
- try {
34
- options.onSubgraphError(err, subgraphName)
35
- } catch (err) {
36
- app.log.error({ err }, 'running onSubgraphError')
37
- }
38
- }
39
- }
40
- }
41
- }
42
-
43
- export function createSupergraph ({ sdl = null, resolvers = {} } = {}) {
44
- // in case of temporary failures of subgraphs on watching, the service can restart if no subgraphs are (tempoary) available
45
- if (!sdl) {
46
- return {
47
- sdl: placeholderSdl,
48
- resolvers: placeholderResolvers
49
- }
50
- }
51
- return { sdl, resolvers }
52
- }
53
-
54
- export function isSameGraphqlSchema (a, b) {
55
- // TODO review
56
- return a?.sdl === b?.sdl
57
- }
58
-
59
- export function serviceToSubgraphConfig (service) {
60
- if (!service.graphql) {
61
- return
62
- }
63
- return {
64
- name: service.graphql.name || service.id || service.origin,
65
- entities: service.graphql.entities,
66
- server: {
67
- host: service.graphql.host || service.origin,
68
- composeEndpoint: service.graphql.composeEndpoint,
69
- graphqlEndpoint: service.graphql.graphqlEndpoint
70
- }
71
- }
72
- }
73
-
74
- export async function fetchGraphqlSubgraphs (services, options, app) {
75
- const subgraphs = services.map(serviceToSubgraphConfig).filter(s => !!s)
76
- const composer = await compose({ ...toComposerOptions(options, app), subgraphs })
77
-
78
- return createSupergraph({
79
- logger: app.log,
80
- sdl: composer.toSdl(),
81
- resolvers: composer.resolvers
82
- })
83
- }
@@ -1,33 +0,0 @@
1
- import fp from 'fastify-plugin'
2
- import mercurius from 'mercurius'
3
- import { fetchGraphqlSubgraphs } from './graphql-fetch.js'
4
-
5
- async function graphqlGeneratorPlugin (app, opts) {
6
- if (!opts.services.some(s => s.graphql)) {
7
- return
8
- }
9
-
10
- const services = []
11
-
12
- for (const service of opts.services) {
13
- if (!service.graphql) {
14
- continue
15
- }
16
- services.push(service)
17
- }
18
-
19
- const graphqlConfig = {
20
- graphiql: opts.graphql?.graphiql
21
- }
22
- if (services.length > 0) {
23
- const graphqlSupergraph = await fetchGraphqlSubgraphs(services, opts.graphql, app)
24
- graphqlConfig.schema = graphqlSupergraph.sdl
25
- graphqlConfig.resolvers = graphqlSupergraph.resolvers
26
- graphqlConfig.subscription = false // TODO support subscriptions, will be !!opts.graphql.subscriptions
27
- app.graphqlSupergraph = graphqlSupergraph
28
- }
29
-
30
- await app.register(mercurius, graphqlConfig)
31
- }
32
-
33
- export const graphqlGenerator = fp(graphqlGeneratorPlugin)
package/lib/graphql.js DELETED
@@ -1,24 +0,0 @@
1
- import fp from 'fastify-plugin'
2
- import { createSupergraph } from './graphql-fetch.js'
3
-
4
- const graphqlSupergraphSymbol = Symbol('graphqlSupergraph')
5
-
6
- export async function graphqlPlugin (app, opts) {
7
- app.decorate('graphqlSupergraph', {
8
- getter () {
9
- return this[graphqlSupergraphSymbol]
10
- },
11
- setter (v) {
12
- this[graphqlSupergraphSymbol] = v
13
- }
14
- })
15
- app.decorate('graphqlComposerOptions', {
16
- getter () {
17
- return opts
18
- }
19
- })
20
-
21
- app.graphqlSupergraph = createSupergraph()
22
- }
23
-
24
- export const graphql = fp(graphqlPlugin)
package/lib/metrics.js DELETED
@@ -1,12 +0,0 @@
1
- export function initMetrics (prometheus) {
2
- if (!prometheus?.registry || !prometheus?.client) return null
3
- const { client, registry } = prometheus
4
-
5
- return {
6
- activeWsConnections: new client.Gauge({
7
- name: 'active_ws_composer_connections',
8
- help: 'Active Websocket composer connections in "@platformatic/composer"',
9
- registers: [registry]
10
- })
11
- }
12
- }
@@ -1,31 +0,0 @@
1
- export const notHostConstraints = {
2
- name: 'notHost',
3
- storage () {
4
- const store = []
5
-
6
- return {
7
- get (host) {
8
- if (typeof host === 'string') {
9
- for (const [hosts, value] of store) {
10
- if (!hosts.includes(host)) {
11
- return value
12
- }
13
- }
14
- }
15
-
16
- return null
17
- },
18
- set: (hosts, value) => {
19
- store.push([hosts, value])
20
- },
21
- store
22
- }
23
- },
24
- deriveConstraint (req) {
25
- return req.headers.host || req.headers[':authority']
26
- },
27
- mustMatchWhenDerived: false,
28
- validate () {
29
- return true
30
- }
31
- }