@adobe/aio-cli-plugin-app-storage 1.0.3 → 1.2.0-pre.2025-11-18.sha-9c4079ac
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/README.md +676 -12
- package/package.json +33 -6
- package/src/BaseCommand.js +11 -58
- package/src/DBBaseCommand.js +112 -0
- package/src/StateBaseCommand.js +87 -0
- package/src/commands/app/add/db.js +20 -0
- package/src/commands/app/db/collection/create.js +119 -0
- package/src/commands/app/db/collection/drop.js +90 -0
- package/src/commands/app/db/collection/list.js +100 -0
- package/src/commands/app/db/collection/rename.js +98 -0
- package/src/commands/app/db/collection/stats.js +94 -0
- package/src/commands/app/db/delete.js +89 -0
- package/src/commands/app/db/document/count.js +96 -0
- package/src/commands/app/db/document/delete.js +95 -0
- package/src/commands/app/db/document/find.js +133 -0
- package/src/commands/app/db/document/insert.js +147 -0
- package/src/commands/app/db/document/replace.js +122 -0
- package/src/commands/app/db/document/update.js +144 -0
- package/src/commands/app/db/index/create.js +170 -0
- package/src/commands/app/db/index/drop.js +87 -0
- package/src/commands/app/db/index/list.js +82 -0
- package/src/commands/app/db/ping.js +77 -0
- package/src/commands/app/db/provision.js +190 -0
- package/src/commands/app/db/stats.js +87 -0
- package/src/commands/app/db/status.js +159 -0
- package/src/commands/app/state/delete.js +3 -3
- package/src/commands/app/state/get.js +2 -2
- package/src/commands/app/state/list.js +3 -3
- package/src/commands/app/state/put.js +4 -4
- package/src/commands/app/state/stats.js +2 -2
- package/src/constants/db.js +32 -0
- package/src/constants/global.js +14 -0
- package/src/{constants.js → constants/state.js} +3 -0
- package/src/utils/inputValidation.js +74 -0
- package/src/utils/output.js +35 -0
- package/oclif.manifest.json +0 -306
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { DBBaseCommand } from '../../../DBBaseCommand.js'
|
|
14
|
+
import chalk from 'chalk'
|
|
15
|
+
import { prettyJson } from '../../../utils/output.js'
|
|
16
|
+
|
|
17
|
+
export class Stats extends DBBaseCommand {
|
|
18
|
+
async run () {
|
|
19
|
+
try {
|
|
20
|
+
this.log(chalk.blue('Fetching database statistics...'))
|
|
21
|
+
|
|
22
|
+
const client = await this.db.connect()
|
|
23
|
+
const stats = await client.dbStats()
|
|
24
|
+
|
|
25
|
+
this.debugLogger?.info?.('Database statistics retrieved:', stats)
|
|
26
|
+
|
|
27
|
+
const result = {
|
|
28
|
+
...stats,
|
|
29
|
+
namespace: this.rtNamespace,
|
|
30
|
+
timestamp: new Date().toISOString()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.displayStats(stats)
|
|
34
|
+
|
|
35
|
+
return result
|
|
36
|
+
} catch (error) {
|
|
37
|
+
this.debugLogger?.error?.('Stats command error:', error)
|
|
38
|
+
|
|
39
|
+
this.log(chalk.red('Failed to retrieve database statistics'))
|
|
40
|
+
this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
|
|
41
|
+
this.log(chalk.dim(` Error: ${error.message}`))
|
|
42
|
+
|
|
43
|
+
this.error(`Failed to fetch database statistics: ${error.message}`)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
displayStats (stats) {
|
|
48
|
+
this.log(chalk.green('Database Statistics:'))
|
|
49
|
+
this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
|
|
50
|
+
|
|
51
|
+
if (stats && typeof stats === 'object') {
|
|
52
|
+
// Format and display stats in a readable way
|
|
53
|
+
Object.entries(stats).forEach(([key, value]) => {
|
|
54
|
+
this.log(chalk.dim(` ${key}: ${this.formatValue(value)}`))
|
|
55
|
+
})
|
|
56
|
+
} else {
|
|
57
|
+
this.log(chalk.dim(` Raw Stats: ${this.formatValue(stats)}`))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.log('')
|
|
61
|
+
this.log(chalk.dim(` Retrieved: ${new Date().toLocaleString()}`))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
formatValue (value) {
|
|
65
|
+
if (typeof value === 'number') {
|
|
66
|
+
// Format large numbers with commas
|
|
67
|
+
return value.toLocaleString()
|
|
68
|
+
}
|
|
69
|
+
if (typeof value === 'object' && value !== null) {
|
|
70
|
+
return `\n${prettyJson(value)}`
|
|
71
|
+
}
|
|
72
|
+
return String(value)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
Stats.description = 'Get statistics about your App Builder database'
|
|
77
|
+
|
|
78
|
+
Stats.examples = [
|
|
79
|
+
'$ aio app db stats',
|
|
80
|
+
'$ aio app db stats --json'
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
Stats.flags = {
|
|
84
|
+
...DBBaseCommand.flags
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
Stats.args = {}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { DBBaseCommand } from '../../../DBBaseCommand.js'
|
|
14
|
+
import { Flags } from '@oclif/core'
|
|
15
|
+
import chalk from 'chalk'
|
|
16
|
+
import { DB_STATUS } from '../../../constants/db.js'
|
|
17
|
+
|
|
18
|
+
export class Status extends DBBaseCommand {
|
|
19
|
+
async run () {
|
|
20
|
+
const { watch } = this.flags
|
|
21
|
+
|
|
22
|
+
this.debugLogger?.info?.('Checking database provisioning status')
|
|
23
|
+
|
|
24
|
+
if (watch) {
|
|
25
|
+
return this.watchStatus()
|
|
26
|
+
} else {
|
|
27
|
+
return this.checkStatus()
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async checkStatus () {
|
|
32
|
+
try {
|
|
33
|
+
this.log(chalk.blue('Checking database provisioning status...'))
|
|
34
|
+
|
|
35
|
+
const provisionStatusResponse = await this.db.provisionStatus()
|
|
36
|
+
this.debugLogger?.info?.('Status result:', provisionStatusResponse)
|
|
37
|
+
|
|
38
|
+
this.displayStatus(provisionStatusResponse)
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
...provisionStatusResponse,
|
|
42
|
+
namespace: this.rtNamespace,
|
|
43
|
+
timestamp: new Date().toISOString()
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
this.debugLogger?.error?.('Status command error:', error)
|
|
47
|
+
|
|
48
|
+
if (error.httpStatusCode === 404) {
|
|
49
|
+
this.log(chalk.yellow('No database has been provisioned for this workspace'))
|
|
50
|
+
this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
|
|
51
|
+
this.log(chalk.dim(` Status: ${DB_STATUS.NOT_PROVISIONED}`))
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
status: DB_STATUS.NOT_PROVISIONED,
|
|
55
|
+
namespace: this.rtNamespace,
|
|
56
|
+
timestamp: new Date().toISOString()
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.error(`Failed to check database status: ${error.message}`)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async watchStatus () {
|
|
65
|
+
this.log(chalk.blue('Watching database provisioning status (press Ctrl+C to stop)...'))
|
|
66
|
+
|
|
67
|
+
let previousStatus = null
|
|
68
|
+
const checkInterval = 3000 // 3 seconds
|
|
69
|
+
|
|
70
|
+
const watchLoop = async () => {
|
|
71
|
+
try {
|
|
72
|
+
const provisionStatusResponse = await this.db.provisionStatus()
|
|
73
|
+
|
|
74
|
+
// Only display if status changed
|
|
75
|
+
if (previousStatus?.status !== provisionStatusResponse?.status) {
|
|
76
|
+
this.log(chalk.dim(`\n[${new Date().toLocaleTimeString()}]`))
|
|
77
|
+
this.displayStatus(provisionStatusResponse, false) // Don't show timestamp in watch mode
|
|
78
|
+
previousStatus = provisionStatusResponse
|
|
79
|
+
|
|
80
|
+
// Stop watching if provisioning is complete or failed
|
|
81
|
+
const currentStatus = provisionStatusResponse.status?.toUpperCase()
|
|
82
|
+
if (currentStatus !== DB_STATUS.REQUESTED && currentStatus !== DB_STATUS.PROCESSING) {
|
|
83
|
+
this.log(chalk.dim('\nStopping watch mode.'))
|
|
84
|
+
return provisionStatusResponse
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Schedule next check
|
|
89
|
+
setTimeout(watchLoop, checkInterval)
|
|
90
|
+
} catch (error) {
|
|
91
|
+
this.debugLogger?.error?.('Watch status error:', error)
|
|
92
|
+
this.log(chalk.red(`\n[${new Date().toLocaleTimeString()}] Error: ${error.message}`))
|
|
93
|
+
|
|
94
|
+
// Continue watching despite errors
|
|
95
|
+
setTimeout(watchLoop, checkInterval)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Start watching
|
|
100
|
+
return watchLoop()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
displayStatus (provisionStatusResponse, showTimestamp = true) {
|
|
104
|
+
const currentStatus = provisionStatusResponse.status.toUpperCase()
|
|
105
|
+
const statusColor = this.getStatusColor(currentStatus)
|
|
106
|
+
|
|
107
|
+
this.log(statusColor(`Database Status: ${currentStatus}`))
|
|
108
|
+
this.log(chalk.dim(` Namespace: ${this.rtNamespace}`))
|
|
109
|
+
|
|
110
|
+
if (provisionStatusResponse.message) {
|
|
111
|
+
this.log(chalk.dim(` Message: ${provisionStatusResponse.message}`))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (provisionStatusResponse.submitted) {
|
|
115
|
+
this.log(chalk.dim(` Submitted: ${new Date(provisionStatusResponse.submitted).toLocaleString()}`))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (showTimestamp) {
|
|
119
|
+
this.log(chalk.dim(` Checked: ${new Date().toLocaleString()}`))
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* istanbul ignore next */
|
|
124
|
+
getStatusColor (statusValue) {
|
|
125
|
+
const status = statusValue.toUpperCase()
|
|
126
|
+
switch (status) {
|
|
127
|
+
case DB_STATUS.PROVISIONED:
|
|
128
|
+
return chalk.green
|
|
129
|
+
case DB_STATUS.REQUESTED:
|
|
130
|
+
case DB_STATUS.PROCESSING:
|
|
131
|
+
return chalk.yellow
|
|
132
|
+
case DB_STATUS.FAILED:
|
|
133
|
+
case DB_STATUS.REJECTED:
|
|
134
|
+
return chalk.red
|
|
135
|
+
case DB_STATUS.NOT_PROVISIONED:
|
|
136
|
+
return chalk.blue
|
|
137
|
+
default:
|
|
138
|
+
return chalk.gray
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
Status.description = 'Check the provisioning status of your App Builder database'
|
|
144
|
+
|
|
145
|
+
Status.examples = [
|
|
146
|
+
'$ aio app db status',
|
|
147
|
+
'$ aio app db status --watch',
|
|
148
|
+
'$ aio app db status --json'
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
Status.flags = {
|
|
152
|
+
...DBBaseCommand.flags,
|
|
153
|
+
watch: Flags.boolean({
|
|
154
|
+
description: 'Watch for status changes (press Ctrl+C to stop)',
|
|
155
|
+
default: false
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
Status.args = {}
|
|
@@ -10,12 +10,12 @@ OF ANY KIND, either express or implied. See the License for the specific languag
|
|
|
10
10
|
governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
import chalk from 'chalk'
|
|
13
|
-
import {
|
|
13
|
+
import { StateBaseCommand } from '../../../StateBaseCommand.js'
|
|
14
14
|
import { Args, Flags } from '@oclif/core'
|
|
15
15
|
|
|
16
16
|
const MAX_ARGV_NO_CONFIRM = 5
|
|
17
17
|
|
|
18
|
-
export class Delete extends
|
|
18
|
+
export class Delete extends StateBaseCommand {
|
|
19
19
|
async run () {
|
|
20
20
|
const { match, force } = this.flags
|
|
21
21
|
const { argv: keysToDelete } = await this.parse(Delete)
|
|
@@ -100,7 +100,7 @@ Delete.args = {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
Delete.flags = {
|
|
103
|
-
...
|
|
103
|
+
...StateBaseCommand.flags,
|
|
104
104
|
match: Flags.string({
|
|
105
105
|
description: '[use with caution!] deletes ALL key-values matching the provided glob-like pattern',
|
|
106
106
|
required: false
|
|
@@ -10,10 +10,10 @@ OF ANY KIND, either express or implied. See the License for the specific languag
|
|
|
10
10
|
governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
import chalk from 'chalk'
|
|
13
|
-
import {
|
|
13
|
+
import { StateBaseCommand } from '../../../StateBaseCommand.js'
|
|
14
14
|
import { Args } from '@oclif/core'
|
|
15
15
|
|
|
16
|
-
export class Get extends
|
|
16
|
+
export class Get extends StateBaseCommand {
|
|
17
17
|
async run () {
|
|
18
18
|
const ret = await this.state.get(this.args.key)
|
|
19
19
|
|
|
@@ -9,14 +9,14 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA
|
|
|
9
9
|
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
12
|
+
import { StateBaseCommand } from '../../../StateBaseCommand.js'
|
|
13
13
|
import { Flags } from '@oclif/core'
|
|
14
14
|
import chalk from 'chalk'
|
|
15
15
|
|
|
16
16
|
const MAX_KEYS = 5000
|
|
17
17
|
const COUNT_HINT = 500 // per iteration
|
|
18
18
|
|
|
19
|
-
export class List extends
|
|
19
|
+
export class List extends StateBaseCommand {
|
|
20
20
|
async run () {
|
|
21
21
|
const allKeys = []
|
|
22
22
|
|
|
@@ -55,7 +55,7 @@ List.examples = [
|
|
|
55
55
|
]
|
|
56
56
|
|
|
57
57
|
List.flags = {
|
|
58
|
-
...
|
|
58
|
+
...StateBaseCommand.flags,
|
|
59
59
|
match: Flags.string({
|
|
60
60
|
name: 'match',
|
|
61
61
|
char: 'm',
|
|
@@ -9,12 +9,12 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA
|
|
|
9
9
|
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
12
|
+
import { StateBaseCommand } from '../../../StateBaseCommand.js'
|
|
13
13
|
import { Args, Flags } from '@oclif/core'
|
|
14
|
-
import { DEFAULT_TTL_SECONDS } from '../../../constants.js'
|
|
14
|
+
import { DEFAULT_TTL_SECONDS } from '../../../constants/state.js'
|
|
15
15
|
import chalk from 'chalk'
|
|
16
16
|
|
|
17
|
-
export class Put extends
|
|
17
|
+
export class Put extends StateBaseCommand {
|
|
18
18
|
async run () {
|
|
19
19
|
const { key, value } = this.args
|
|
20
20
|
const { json, ttl } = this.flags
|
|
@@ -55,7 +55,7 @@ Put.args = {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
Put.flags = {
|
|
58
|
-
...
|
|
58
|
+
...StateBaseCommand.flags,
|
|
59
59
|
ttl: Flags.integer({
|
|
60
60
|
char: 't',
|
|
61
61
|
description: 'Time to live in seconds. Default is 86400 (24 hours), max is 31536000 (1 year).',
|
|
@@ -9,9 +9,9 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA
|
|
|
9
9
|
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
12
|
+
import { StateBaseCommand } from '../../../StateBaseCommand.js'
|
|
13
13
|
|
|
14
|
-
export class Stats extends
|
|
14
|
+
export class Stats extends StateBaseCommand {
|
|
15
15
|
async run () {
|
|
16
16
|
const ret = await this.state.stats()
|
|
17
17
|
this.log(
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const DB_STATUS = {
|
|
14
|
+
PROVISIONED: 'PROVISIONED',
|
|
15
|
+
REQUESTED: 'REQUESTED',
|
|
16
|
+
PROCESSING: 'PROCESSING',
|
|
17
|
+
FAILED: 'FAILED',
|
|
18
|
+
REJECTED: 'REJECTED',
|
|
19
|
+
NOT_PROVISIONED: 'NOT_PROVISIONED',
|
|
20
|
+
DELETED: 'DELETED',
|
|
21
|
+
UNKNOWN: 'UNKNOWN'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Region constants for db are separate from state in case they diverge in the future
|
|
25
|
+
export const CONFIG_DB_REGION = 'db.region'
|
|
26
|
+
export const DEFAULT_REGION = 'amer'
|
|
27
|
+
export const AVAILABLE_REGIONS = {
|
|
28
|
+
prod: ['amer', 'emea', 'apac'],
|
|
29
|
+
stage: ['amer', 'amer2']
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const CONFIG_DB_ENDPOINT = 'db.endpoint'
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const CONFIG_RUNTIME_NAMESPACE = 'runtime.namespace'
|
|
14
|
+
export const CONFIG_RUNTIME_AUTH = 'runtime.auth'
|
|
@@ -11,6 +11,9 @@ governing permissions and limitations under the License.
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
// state.region is a new configuration (env=AIO_STATE_REGION)
|
|
14
|
+
// Region constants for state are separate from db in case they diverge in the future
|
|
14
15
|
export const CONFIG_STATE_REGION = 'state.region'
|
|
16
|
+
export const DEFAULT_REGION = 'amer'
|
|
17
|
+
export const AVAILABLE_REGIONS = ['amer', 'emea', 'apac']
|
|
15
18
|
|
|
16
19
|
export const DEFAULT_TTL_SECONDS = 60 * 60 * 24 // 24 hours
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2025 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Helper to verify the argument/option input is a javascript or json object
|
|
15
|
+
* Returns the object if valid, or throws an error if invalid
|
|
16
|
+
*
|
|
17
|
+
* @param {object|string} input - The input to validate
|
|
18
|
+
* @param {string=} label - Optional label for an error message, such as the argument/option name
|
|
19
|
+
* @returns {object} - The validated object
|
|
20
|
+
*/
|
|
21
|
+
export function asObject (input, label = undefined) {
|
|
22
|
+
label = label ? `${label}: ` : ''
|
|
23
|
+
if (typeof input === 'object' && input !== null && !Array.isArray(input)) {
|
|
24
|
+
return input
|
|
25
|
+
}
|
|
26
|
+
if (typeof input !== 'string' || input.trim().length === 0) {
|
|
27
|
+
throw new Error(`${label}Value '${input}' is not a JSON object`)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let result
|
|
31
|
+
try {
|
|
32
|
+
result = JSON.parse(input)
|
|
33
|
+
} catch (e) {
|
|
34
|
+
e.message = `${label}JSON parse error: ${e.message}`
|
|
35
|
+
throw e
|
|
36
|
+
}
|
|
37
|
+
if (typeof result !== 'object' || result === null || Array.isArray(result)) {
|
|
38
|
+
throw new Error(`${label}Value '${input}' is not a JSON object`)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return result
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Helper to verify the argument/option input is a non-empty string
|
|
46
|
+
* Throws an error if the input is not a string with length > 0
|
|
47
|
+
* Does not check for whitespace-only strings, call `trim()` when passing the input if needed
|
|
48
|
+
*
|
|
49
|
+
* @param {string} input - The input to validate
|
|
50
|
+
* @param {string=} label - Optional label for an error message, such as the argument/option name
|
|
51
|
+
* @returns {string} - The validated non-empty string
|
|
52
|
+
*/
|
|
53
|
+
export function isNonEmptyString (input, label = undefined) {
|
|
54
|
+
label = label ? `${label}: ` : ''
|
|
55
|
+
if (typeof input !== 'string' || input.length === 0) {
|
|
56
|
+
throw new Error(`${label}Must be a non-empty string`)
|
|
57
|
+
}
|
|
58
|
+
return input
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Determine if a runtime namespace corresponds to a production workspace.
|
|
63
|
+
* production if optional prefix<development-> + orgId + projectName with no trailing workspace suffix.
|
|
64
|
+
*
|
|
65
|
+
* @param {string} namespace - The runtime namespace to check
|
|
66
|
+
* @returns {boolean} - True if the namespace is a production workspace, false otherwise
|
|
67
|
+
*/
|
|
68
|
+
export function isProductionNamespace (namespace) {
|
|
69
|
+
if (typeof namespace !== 'string' || !namespace.trim()) {
|
|
70
|
+
throw new Error('Invalid runtime namespace')
|
|
71
|
+
}
|
|
72
|
+
const PROD_NS_REGEX = /^(?:development-)?\d+-[a-z0-9]+$/i
|
|
73
|
+
return PROD_NS_REGEX.test(namespace)
|
|
74
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Prettifies json for readable log output
|
|
15
|
+
*
|
|
16
|
+
* @param {*} val - The value to pretty print as JSON.
|
|
17
|
+
* @param {number} indent - The number of spaces to indent the entire output.
|
|
18
|
+
* @returns {string} - The pretty printed JSON string.
|
|
19
|
+
*/
|
|
20
|
+
export function prettyJson (val, indent = 5) {
|
|
21
|
+
let out
|
|
22
|
+
if (typeof val === 'string') {
|
|
23
|
+
try {
|
|
24
|
+
out = JSON.stringify(JSON.parse(val), null, 2)
|
|
25
|
+
} catch (e) {
|
|
26
|
+
out = val // If parsing fails, return the original string
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
out = JSON.stringify(val, null, 2)
|
|
30
|
+
}
|
|
31
|
+
if (indent) {
|
|
32
|
+
out = out.replace(/^/gm, ' '.repeat(indent))
|
|
33
|
+
}
|
|
34
|
+
return out
|
|
35
|
+
}
|