@architect/inventory 2.1.3 → 2.2.1

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/changelog.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  ---
4
4
 
5
+ ## [2.2.1] 2021-11-22
6
+
7
+ ### Fixed
8
+
9
+ - Fixed HTTP route sorting; however you've organized your `@http` pragma, Sandbox should now behave much more like API Gateway; fixes #977
10
+ - Fixed overly strict path parameter validation; allow `_`, `.`, `-`; thanks @jkarsrud!
11
+
12
+ ---
13
+
14
+ ## [2.2.0] 2021-11-16
15
+
16
+ ### Added
17
+
18
+ - Finally formalized `@tables-streams`, the fully customizable successor to `@tables` with `stream true`
19
+ - Added `@tables-indexes` pragma
20
+ - `@tables-indexes` has identical semantics as (and will eventually supersede) `@indexes`
21
+ - Until Arc 10.0 + Inventory 3.0, consumers should now check both `inv.indexes` AND `inv.tables-indexes`
22
+
23
+ ---
24
+
5
25
  ## [2.1.3] 2021-11-04
6
26
 
7
27
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@architect/inventory",
3
- "version": "2.1.3",
3
+ "version": "2.2.1",
4
4
  "description": "Architect project resource enumeration utility",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -23,19 +23,19 @@
23
23
  "@architect/asap": "~4.1.0",
24
24
  "@architect/parser": "~5.0.2",
25
25
  "@architect/utils": "~3.0.4",
26
- "lambda-runtimes": "~1.0.1"
26
+ "lambda-runtimes": "~1.1.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@architect/eslint-config": "~2.0.1",
30
30
  "aws-sdk": "2.880.0",
31
31
  "aws-sdk-mock": "~5.4.0",
32
32
  "cross-env": "~7.0.3",
33
- "eslint": "~8.0.1",
34
- "mock-fs": "~5.1.1",
33
+ "eslint": "~8.2.0",
34
+ "mock-fs": "~5.1.2",
35
35
  "mock-require": "~3.0.3",
36
36
  "nyc": "~15.1.0",
37
37
  "tap-spec": "^5.0.0",
38
- "tape": "^5.3.1"
38
+ "tape": "^5.3.2"
39
39
  },
40
40
  "eslintConfig": {
41
41
  "extends": "@architect/eslint-config"
@@ -2,6 +2,7 @@ let { join } = require('path')
2
2
  let populate = require('./populate-lambda')
3
3
  let asapSrc = require('../../lib/asap-src')
4
4
  let validate = require('./validate')
5
+ let sort = require('./sort/http')
5
6
 
6
7
  module.exports = function configureHTTP ({ arc, inventory, errors }) {
7
8
  if (!arc.http) return null
@@ -67,7 +68,9 @@ module.exports = function configureHTTP ({ arc, inventory, errors }) {
67
68
  // Impure but it's way less complicated to just do this
68
69
  inventory._project.rootHandler = rootHandler
69
70
 
71
+ // Final steps: validate, then ensure the route order works as API Gateway would
70
72
  validate.http(http, errors)
73
+ http = sort(http)
71
74
 
72
75
  return http
73
76
  }
@@ -1,7 +1,7 @@
1
1
  let { all: allPragmas } = require('../../lib/pragmas')
2
2
 
3
3
  // Get all pragmas except special cases
4
- let isSpecial = p => p === 'shared' || p === 'views'
4
+ let isSpecial = p => [ 'shared', 'views' ].includes(p)
5
5
  let visitors = allPragmas.map(p => {
6
6
  // eslint-disable-next-line
7
7
  if (!isSpecial(p)) return require(`./${p}`)
@@ -21,6 +21,9 @@ module.exports = function configureArcPragmas ({ arc, inventory }, errors) {
21
21
  visitors.forEach(visitor => {
22
22
  // Expects pragma visitors to have function name of: `configure${pragma}`
23
23
  let name = visitor.name.replace('configure', '').toLowerCase()
24
+ // Special cases for dasherization
25
+ if (name === 'tablesindexes') name = 'tables-indexes'
26
+ if (name === 'tablesstreams') name = 'tables-streams'
24
27
  pragmas[name] = visitor({ arc, inventory, errors })
25
28
  })
26
29
 
@@ -1,5 +1,5 @@
1
- let is = require('../../lib/is')
2
1
  let validate = require('./validate')
2
+ let { getIndexes } = require('./tables-indexes')
3
3
 
4
4
  module.exports = function configureIndexes ({ arc, errors }) {
5
5
  if (!arc.indexes || !arc.indexes.length) return null
@@ -7,43 +7,12 @@ module.exports = function configureIndexes ({ arc, errors }) {
7
7
  errors.push(`Specifying @indexes requires specifying corresponding @tables`)
8
8
  return null
9
9
  }
10
+ if (arc['tables-indexes']?.length && arc.indexes?.length) {
11
+ errors.push(`Either @tables-indexes or @indexes can be specified, but not both`)
12
+ return null
13
+ }
10
14
 
11
- let isCustomName = key => is.string(key) && key.toLowerCase() === 'name'
12
- function error (item) { errors.push(`Invalid @indexes item: ${item}`) }
13
-
14
- let indexes = arc.indexes.map(index => {
15
- if (is.object(index)) {
16
- let name = Object.keys(index)[0]
17
- let partitionKey = null
18
- let partitionKeyType = null
19
- let sortKey = null
20
- let sortKeyType = null
21
- let indexName = null
22
- Object.entries(index[name]).forEach(([ key, value ]) => {
23
- if (is.sortKey(value)) {
24
- sortKey = key
25
- sortKeyType = value.replace('**', '')
26
- }
27
- else if (is.primaryKey(value)) {
28
- partitionKey = key
29
- partitionKeyType = value.replace('*', '')
30
- }
31
- else if (isCustomName(key)) {
32
- indexName = value
33
- }
34
- })
35
- return {
36
- indexName,
37
- name,
38
- partitionKey,
39
- partitionKeyType,
40
- sortKey,
41
- sortKeyType,
42
- }
43
- }
44
- error(index)
45
- }).filter(Boolean) // Invalid indexes may create undefined entries in the map
46
-
15
+ let indexes = getIndexes(arc, 'indexes', errors)
47
16
  validate.indexes(indexes, '@indexes', errors)
48
17
 
49
18
  return indexes
@@ -2,23 +2,29 @@ let { join } = require('path')
2
2
  let { existsSync } = require('fs')
3
3
  let is = require('../../../lib/is')
4
4
 
5
- module.exports = function populateStreams ({ type, item, dir, cwd, errors }) {
5
+ module.exports = function populateTablesStreams ({ type, item, dir, cwd, errors }) {
6
6
  if (type === 'tables' && is.object(item)) {
7
7
  let name = Object.keys(item)[0]
8
- // Check for the legacy dir from before `@tables tablename stream true` generated an @streams item
8
+ // Check for the legacy dir from before `@tables tablename stream true` generated a @tables-streams item
9
9
  let legacySrc = join(cwd, dir, name)
10
10
  let streamSrc = join(cwd, 'src', 'streams', name)
11
- let src = existsSync(legacySrc) ? legacySrc : streamSrc
11
+ let tablesStreamsSrc = join(cwd, 'src', 'tables-streams', name)
12
+
13
+ let src
14
+ if (existsSync(legacySrc)) src = legacySrc
15
+ else if (existsSync(streamSrc)) src = streamSrc // TODO [remove] in 10.0
16
+ else src = tablesStreamsSrc
17
+
12
18
  let table = name
13
19
  return { name, src, table }
14
20
  }
15
- else if (type === 'streams' && is.string(item)) {
21
+ else if (type === 'tables-streams' && is.string(item)) {
16
22
  let name = item
17
23
  let src = join(cwd, dir, name)
18
24
  let table = name
19
25
  return { name, src, table }
20
26
  }
21
- else if (type === 'streams' && is.object(item)) {
27
+ else if (type === 'tables-streams' && is.object(item)) {
22
28
  let name = Object.keys(item)[0]
23
29
  let src = item[name].src
24
30
  ? join(cwd, item[name].src)
@@ -10,7 +10,7 @@ let getEvents = require('./_events')
10
10
  let getPlugins = require('./_plugins')
11
11
  let getScheduled = require('./_scheduled')
12
12
  let getWS = require('./_websockets')
13
- let getStreams = require('./_streams')
13
+ let getTablesStreams = require('./_tables-streams')
14
14
 
15
15
  /**
16
16
  * Build out the Lambda tree
@@ -87,6 +87,8 @@ function populateLambda (type, pragma, inventory, errors) {
87
87
  return lambdas
88
88
  }
89
89
 
90
+ let ts = 'tables-streams'
91
+
90
92
  function getLambda (params) {
91
93
  let { type } = params
92
94
  params.dir = `src/${type}/`
@@ -96,9 +98,9 @@ function getLambda (params) {
96
98
  if (type === 'plugins') return getPlugins(params)
97
99
  if (type === 'queues') return getEvents(params) // Effectively the same as events
98
100
  if (type === 'scheduled') return getScheduled(params)
99
- if (type === 'streams') return getStreams(params)
100
- if (type === 'tables') return getStreams(params) // Shortcut for creating streams
101
- /* istanbul ignore else */ /* Clearer to be explicit here */
101
+ if (type === ts) return getTablesStreams(params)
102
+ if (type === 'tables') return getTablesStreams(params) // Shortcut for creating streams
103
+ /* istanbul ignore else: clearer to be explicit here */
102
104
  if (type === 'ws') return getWS(params)
103
105
  }
104
106
 
@@ -108,7 +110,7 @@ module.exports = {
108
110
  plugins: populateLambda.bind({}, 'plugins'),
109
111
  queues: populateLambda.bind({}, 'queues'),
110
112
  scheduled: populateLambda.bind({}, 'scheduled'),
111
- streams: populateLambda.bind({}, 'streams'),
112
113
  tables: populateLambda.bind({}, 'tables'),
114
+ [ts]: populateLambda.bind({}, ts),
113
115
  ws: populateLambda.bind({}, 'ws'),
114
116
  }
@@ -0,0 +1,72 @@
1
+ let methods = require('../../../lib/http-methods')
2
+
3
+ /**
4
+ * HTTP route sorter; this is a multifurcating tree, so we'll do a few passes
5
+ * Broadly in the theme of most to least specific:
6
+ * - First, by method, with `any` last
7
+ * - Then by path depth (descending)
8
+ * - Within each depth downrank for contained params
9
+ * - Then sort alphabetically
10
+ * - Then, ensure trailing captures are last
11
+ * - Finally, ensure root captures rank below a root literal
12
+ */
13
+ module.exports = function sortHTTP (http) {
14
+ // Construct the tree from HTTP methods
15
+ let tree = {}
16
+ http.forEach(({ method, path }) => {
17
+ if (!tree[method]) tree[method] = []
18
+ let parts = path.split('/').filter(Boolean)
19
+ let depth = parts.length
20
+ let item = { depth, path }
21
+ let param = /\/:/
22
+ if (path.match(param)) {
23
+ item.hasParam = true
24
+ item.paramIndex = path.match(param).index // If multiple, we want the earliest
25
+ }
26
+ if (parts.length) {
27
+ if (parts[depth - 1] === '*') item.trailingCapture = 'catchall'
28
+ if (parts[depth - 1].startsWith(':')) item.trailingCapture = 'param'
29
+ }
30
+ tree[method].push(item)
31
+ })
32
+
33
+ // Multi-pass route sort
34
+ let sorted = []
35
+ methods.forEach(method => {
36
+ if (!tree[method]) return
37
+ /* istanbul ignore next: random test shuffles may not trigger all paths */
38
+ tree[method]
39
+ // Sort by depth
40
+ .sort((a, b) => b.depth - a.depth)
41
+ // Sort within a given depth
42
+ .sort((a, b) => {
43
+ // Handle root (depth: 0)
44
+ if (a.depth - b.depth < 0) return
45
+ if (a.hasParam && b.hasParam) {
46
+ // Sort at the earliest param
47
+ if (a.paramIndex < b.paramIndex) return 1
48
+ if (a.paramIndex > b.paramIndex) return -1
49
+ // Then sort alphabetically
50
+ if (a.path < b.path) return -1
51
+ if (a.path > b.path) return 1
52
+ }
53
+ if (a.hasParam) return 1
54
+ if (b.hasParam) return -1
55
+ if (a.path < b.path) return -1
56
+ if (a.path > b.path) return 1
57
+ })
58
+ // Trailing capture sort
59
+ .sort((a, b) => {
60
+ if (!a.depth && b.depth === 1 && b.trailingCapture) return -1
61
+ if (a.depth - b.depth < 0) return
62
+ if (a.trailingCapture) return 1
63
+ if (b.trailingCapture) return -1
64
+ })
65
+ tree[method].forEach(({ path }) => {
66
+ let route = http.find(i => i.method === method && i.path === path)
67
+ sorted.push(route)
68
+ })
69
+ })
70
+
71
+ return sorted
72
+ }
@@ -0,0 +1,59 @@
1
+ let is = require('../../lib/is')
2
+ let validate = require('./validate')
3
+
4
+ function configureTablesIndexes ({ arc, errors }) {
5
+ if (!arc['tables-indexes'] || !arc['tables-indexes'].length) return null
6
+ if (arc['tables-indexes'] && !arc.tables) {
7
+ errors.push(`Specifying @tables-indexes requires specifying corresponding @tables`)
8
+ return null
9
+ }
10
+ if (arc['tables-indexes']?.length && arc.indexes?.length) {
11
+ errors.push(`Either @tables-indexes or @indexes can be specified, but not both`)
12
+ return null
13
+ }
14
+
15
+ let indexes = getIndexes(arc, 'tables-indexes', errors)
16
+ validate.indexes(indexes, '@tables-indexes', errors)
17
+
18
+ return indexes
19
+ }
20
+
21
+ let getIndexes = (arc, pragma, errors) => {
22
+ let isCustomName = key => is.string(key) && key.toLowerCase() === 'name'
23
+ function error (item) { errors.push(`Invalid @${pragma} item: ${item}`) }
24
+ return arc[pragma].map(index => {
25
+ if (is.object(index)) {
26
+ let name = Object.keys(index)[0]
27
+ let partitionKey = null
28
+ let partitionKeyType = null
29
+ let sortKey = null
30
+ let sortKeyType = null
31
+ let indexName = null
32
+ Object.entries(index[name]).forEach(([ key, value ]) => {
33
+ if (is.sortKey(value)) {
34
+ sortKey = key
35
+ sortKeyType = value.replace('**', '')
36
+ }
37
+ else if (is.primaryKey(value)) {
38
+ partitionKey = key
39
+ partitionKeyType = value.replace('*', '')
40
+ }
41
+ else if (isCustomName(key)) {
42
+ indexName = value
43
+ }
44
+ })
45
+ return {
46
+ indexName,
47
+ name,
48
+ partitionKey,
49
+ partitionKeyType,
50
+ sortKey,
51
+ sortKeyType,
52
+ }
53
+ }
54
+ error(index)
55
+ }).filter(Boolean) // Invalid indexes may create undefined entries in the map
56
+ }
57
+
58
+ configureTablesIndexes.getIndexes = getIndexes
59
+ module.exports = configureTablesIndexes
@@ -3,15 +3,15 @@ let validate = require('./validate')
3
3
  let is = require('../../lib/is')
4
4
 
5
5
  /**
6
- * `@streams` (formerly `@tables`)
6
+ * `@tables-streams`
7
7
  * - Originally `@tables {tablename} stream true` created a lambda at src/tables/{tablename}
8
- * - This was superseded by `@streams`; `@tables` remains for backwards compat and as a convenience for creating `@streams`
8
+ * - This was superseded by `@tables-streams`; `@tables` remains for backwards compat and as a convenience for creating `@tables-streams`
9
9
  * - If a project has an existing `@tables` Lambda, we'll continue using that so long as the directory exists
10
10
  */
11
- module.exports = function configureStreams ({ arc, inventory, errors }) {
12
- if (!arc.streams && !arc.tables) return null
13
- if (arc.streams && !arc.tables) {
14
- errors.push(`Specifying @streams requires specifying corresponding @tables`)
11
+ module.exports = function configureTablesStreams ({ arc, inventory, errors }) {
12
+ if (!arc['tables-streams'] && !arc.tables) return null
13
+ if (arc['tables-streams'] && !arc.tables) {
14
+ errors.push(`Specifying @tables-streams requires specifying corresponding @tables`)
15
15
  return null
16
16
  }
17
17
 
@@ -22,21 +22,21 @@ module.exports = function configureStreams ({ arc, inventory, errors }) {
22
22
  }
23
23
  else tables = null
24
24
 
25
- // Populate @streams
26
- let streams = populate.streams(arc.streams, inventory, errors)
25
+ // Populate @tables-streams
26
+ let streams = populate['tables-streams'](arc['tables-streams'], inventory, errors)
27
27
 
28
28
  if (tables && streams) {
29
29
  let uniqueTables = tables.filter(t => !streams.some(s => s.table === t.table))
30
30
  let merged = streams.concat(uniqueTables)
31
- validate.streams(merged, errors)
31
+ validate.tablesStreams(merged, errors)
32
32
  return merged
33
33
  }
34
34
  else if (streams) {
35
- validate.streams(streams, errors)
35
+ validate.tablesStreams(streams, errors)
36
36
  return streams
37
37
  }
38
38
  else if (tables) {
39
- validate.streams(tables, errors)
39
+ validate.tablesStreams(tables, errors)
40
40
  return tables
41
41
  }
42
42
  return null
@@ -1,10 +1,10 @@
1
1
  let { unique } = require('./_lib')
2
+ let methods = require('../../../lib/http-methods')
2
3
 
3
4
  module.exports = function validateHTTP (http, errors) {
4
5
  if (http.length) {
5
6
  unique(http, '@http routes', errors)
6
7
 
7
- let methods = [ 'get', 'post', 'put', 'patch', 'delete', 'options', 'head', 'any' ]
8
8
  let validMethod = str => methods.includes(str.toLowerCase())
9
9
  let validPath = str => str.match(/^\/[a-zA-Z0-9/\-:._\*]*$/)
10
10
  http.forEach(route => {
@@ -49,7 +49,7 @@ module.exports = function validateHTTP (http, errors) {
49
49
  let params = path.match(/\/:/g)
50
50
  if (params) {
51
51
  // Params cannot have non-alphanumeric characters
52
- let match = path.match(/\/:[a-zA-Z0-9]+(\/|$)/g)
52
+ let match = path.match(/\/:[\w.-]+(\/|$)/g)
53
53
  if (!match) errors.push(`Invalid @http path (parameters must have only alphanumeric characters): ${name}`)
54
54
  }
55
55
 
@@ -0,0 +1,19 @@
1
+ let { regex, size, unique } = require('./_lib')
2
+
3
+ /**
4
+ * Validate @tables-streams (& @tables streams true)
5
+ *
6
+ * Where possible, attempts to follow DynamoDB validation
7
+ * See: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html
8
+ */
9
+ module.exports = function validateTablesStreams (tablesStreams, errors) {
10
+ if (tablesStreams.length) {
11
+ unique(tablesStreams, '@tables-streams', errors)
12
+
13
+ tablesStreams.forEach(stream => {
14
+ let { name } = stream
15
+ size(name, 3, 255, '@tables-streams', errors)
16
+ regex(name, 'veryLooseName', '@tables-streams', errors)
17
+ })
18
+ }
19
+ }
@@ -47,7 +47,7 @@ module.exports = function validateTablesAndIndexes (pragma, pragmaName, errors)
47
47
  }
48
48
  })
49
49
  if (foundDupe) {
50
- let err = `Duplicate @indexes value: '${index.name}'`
50
+ let err = `Duplicate ${pragmaName} value: '${index.name}'`
51
51
  if (!errors.includes(err)) errors.push(err)
52
52
  }
53
53
  })
@@ -1,18 +1,18 @@
1
1
  /* eslint-disable global-require */
2
2
  module.exports = {
3
3
  // Pragmas and project validation
4
- aws: require('./_aws'),
5
- events: require('./_events'),
6
- http: require('./_http'),
7
- indexes: require('./_tables'), // Same ruleset as @tables (more or less)
8
- proxy: require('./_proxy'),
9
- tables: require('./_tables'),
10
- queues: require('./_events'), // Same ruleset as @events
11
- scheduled: require('./_scheduled'),
12
- shared: require('./_shared'), // Also includes @views
13
- streams: require('./_streams'),
14
- websockets: require('./_websockets'),
4
+ aws: require('./_aws'),
5
+ events: require('./_events'),
6
+ http: require('./_http'),
7
+ indexes: require('./_tables'), // Same ruleset as @tables (more or less)
8
+ proxy: require('./_proxy'),
9
+ tables: require('./_tables'),
10
+ queues: require('./_events'), // Same ruleset as @events
11
+ scheduled: require('./_scheduled'),
12
+ shared: require('./_shared'), // Also includes @views
13
+ tablesStreams: require('./_tables-streams'),
14
+ websockets: require('./_websockets'),
15
15
 
16
16
  // Misc
17
- validate: require('./_lib')
17
+ validate: require('./_lib')
18
18
  }
@@ -36,7 +36,7 @@ module.exports = function getProjectConfig (params, errors) {
36
36
  project[`${scope}PreferencesFile`] = p.preferencesFile
37
37
 
38
38
  // Build out the final preferences
39
- /* istanbul ignore else */ // jic
39
+ /* istanbul ignore else: jic */
40
40
  if (!project.preferences) project.preferences = {}
41
41
  Object.keys(p.preferences).forEach(pragma => {
42
42
  // Ignore the raw data
@@ -47,7 +47,7 @@ module.exports = function getProjectConfig (params, errors) {
47
47
  return
48
48
  }
49
49
  // Traverse and merge individual settings
50
- /* istanbul ignore else */ // jic
50
+ /* istanbul ignore else: jic */
51
51
  if (!project.preferences[pragma]) project.preferences[pragma] = {}
52
52
  Object.entries(p.preferences[pragma]).forEach(([ setting, value ]) => {
53
53
  project.preferences[pragma][setting] = value
@@ -18,13 +18,13 @@ module.exports = function getPrefs ({ scope, inventory, errors }) {
18
18
  Object.entries(prefs.arc).forEach(([ key, val ]) => {
19
19
  // TODO add additional preferences checks and normalization
20
20
 
21
- /* istanbul ignore else */ // Parser should get this, but jic
21
+ /* istanbul ignore else: Parser should get this, but jic */
22
22
  if (!preferences[key]) preferences[key] = {}
23
- /* istanbul ignore else */ // Parser should only produce arrays, but jic
23
+ /* istanbul ignore else: Parser should only produce arrays, but jic */
24
24
  if (is.array(val)) {
25
25
  val.forEach(v => {
26
26
  if (is.array(v)) {
27
- /* istanbul ignore if */ // Single vals should be strings, but jic
27
+ /* istanbul ignore if: Single vals should be strings, but jic */
28
28
  if (v.length === 1) preferences[key] = v[0]
29
29
  if (v.length === 2) preferences[key][v[0]] = v[1]
30
30
  if (v.length > 2) preferences[key][v[0]] = [ ...v.slice(1) ]
@@ -39,7 +39,7 @@ module.exports = function getPrefs ({ scope, inventory, errors }) {
39
39
  // Turn env vars with spaces into strings
40
40
  if (key === 'env') {
41
41
  [ 'testing', 'staging', 'production' ].forEach(e => {
42
- /* istanbul ignore else */ // Yet another jic
42
+ /* istanbul ignore else: Yet another jic */
43
43
  if (preferences.env[e]) {
44
44
  Object.entries(preferences.env[e]).forEach(([ key, val ]) => {
45
45
  if (is.array(val)) preferences.env[e][key] = val.join(' ')
@@ -51,7 +51,7 @@ module.exports = function getPrefs ({ scope, inventory, errors }) {
51
51
  if (key === 'sandbox-startup') {
52
52
  preferences[key] = val.map(v => {
53
53
  if (is.string(v)) return v
54
- /* istanbul ignore else */ // Yet another jic
54
+ /* istanbul ignore else: Yet another jic */
55
55
  if (is.array(v)) return v.join(' ')
56
56
  })
57
57
  }
@@ -60,8 +60,9 @@ module.exports = function inventoryDefaults (params = {}) {
60
60
  scheduled: null,
61
61
  shared: null,
62
62
  static: null,
63
- streams: null,
64
63
  tables: null,
64
+ 'tables-indexes': null,
65
+ 'tables-streams': null,
65
66
  views: null,
66
67
  ws: null,
67
68
  // Collection of all Lambda paths
package/src/env/index.js CHANGED
@@ -45,7 +45,7 @@ module.exports = function env (params, inventory, callback) {
45
45
  }
46
46
  }))
47
47
  // Check for more data and, if so, recurse
48
- /* istanbul ignore if */ // Sadly no way to easily mock this for testing
48
+ /* istanbul ignore if: Sadly no way to easily mock this for testing */
49
49
  if (data.NextToken) {
50
50
  getSomeEnvVars(name, data.NextToken, callback)
51
51
  }
package/src/get.js CHANGED
@@ -8,7 +8,7 @@ module.exports = function _get (inventory) {
8
8
  if (pragma === null) return null
9
9
  if (is.array(pragma)) {
10
10
  // Handle arrays of named entities or string values
11
- let finder = i => i && i.name && i.name === name || i === name
11
+ let finder = i => i?.name === name || i === name
12
12
  if (multipleResults.includes(prag)) {
13
13
  let results = pragma.filter(finder)
14
14
  return results.length ? results : undefined
@@ -37,5 +37,6 @@ module.exports = function _get (inventory) {
37
37
  // Everything is uniquely named except in certain special-case pragmas
38
38
  // These refer to other pragmas, and thus may allow multiple same/same-named entities
39
39
  let multipleResults = [
40
- 'indexes'
40
+ 'tables-indexes',
41
+ 'indexes',
41
42
  ]
@@ -0,0 +1,2 @@
1
+ // Any must come last for Sandbox route sorting purposes
2
+ module.exports = [ 'get', 'post', 'put', 'patch', 'delete', 'options', 'head', 'any' ]
@@ -6,7 +6,7 @@ module.exports = {
6
6
  'cdn',
7
7
  'events',
8
8
  'http',
9
- 'indexes',
9
+ 'indexes', // -> transitioning to @tables-indexes
10
10
  'macros',
11
11
  'plugins',
12
12
  'proxy',
@@ -14,8 +14,9 @@ module.exports = {
14
14
  'scheduled',
15
15
  'shared',
16
16
  'static',
17
- 'streams',
18
17
  'tables',
18
+ 'tables-indexes',
19
+ 'tables-streams',
19
20
  'views',
20
21
  'ws',
21
22
  ],
@@ -26,7 +27,7 @@ module.exports = {
26
27
  'plugins',
27
28
  'queues',
28
29
  'scheduled',
29
- 'streams',
30
+ 'tables-streams',
30
31
  'ws',
31
32
  ],
32
33
  }
@@ -31,8 +31,7 @@ module.exports = function finalValidation (params, inventory) {
31
31
  /**
32
32
  * Deal with project validation errors
33
33
  */
34
-
35
- // Ensure @tables children (@streams, @indexes) have parent tables present
34
+ // Ensure @tables children (@tables-streams, @indexes) have parent tables present
36
35
  tablesChildren(inventory, errors)
37
36
 
38
37
  if (errors.length) {
@@ -1,17 +1,17 @@
1
1
  /**
2
- * Ensure @tables children (@streams, @indexes) have parent tables present
2
+ * Ensure @tables children (@tables-streams, @indexes) have parent tables present
3
3
  * - If not, configuration is invalid
4
4
  */
5
5
  module.exports = function validateTablesChildren (inventory, errors) {
6
- let { indexes, streams, tables } = inventory
6
+ let { indexes, 'tables-streams': tablesStreams, tables } = inventory
7
7
 
8
8
  function check (table, type) {
9
9
  if (!tables.some(t => t.name === table)) {
10
10
  errors.push(`@${type} ${table} missing corresponding table`)
11
11
  }
12
12
  }
13
- if (streams) {
14
- streams.forEach(stream => check(stream.table, 'streams'))
13
+ if (tablesStreams) {
14
+ tablesStreams.forEach(stream => check(stream.table, 'tables-streams'))
15
15
  }
16
16
  if (indexes) {
17
17
  indexes.forEach(index => check(index.name, 'indexes'))
@@ -1,19 +0,0 @@
1
- let { regex, size, unique } = require('./_lib')
2
-
3
- /**
4
- * Validate @streams (& @tables streams true)
5
- *
6
- * Where possible, attempts to follow DynamoDB validation
7
- * See: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html
8
- */
9
- module.exports = function validateStreams (streams, errors) {
10
- if (streams.length) {
11
- unique(streams, '@streams', errors)
12
-
13
- streams.forEach(stream => {
14
- let { name } = stream
15
- size(name, 3, 255, '@streams', errors)
16
- regex(name, 'veryLooseName', '@streams', errors)
17
- })
18
- }
19
- }