@nasebanal/cli 0.4.0 → 0.6.0
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 +15 -1
- package/dist/apis.js +1 -2
- package/dist/config.js +1 -1
- package/dist/index.js +4 -0
- package/dist/update.js +127 -0
- package/package.json +1 -1
- package/specs/app-template.yaml +0 -488
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Contract-Driven Development (CDD) pipeline, alongside the web frontends.
|
|
|
10
10
|
|
|
11
11
|
```console
|
|
12
12
|
$ nb account me get
|
|
13
|
-
$ nb
|
|
13
|
+
$ nb record records list
|
|
14
14
|
$ nb target shares accept <id>
|
|
15
15
|
$ nb account me tokens create --data '{"name":"ci"}'
|
|
16
16
|
```
|
|
@@ -117,6 +117,20 @@ needed for a registry install.
|
|
|
117
117
|
> `api-specs-*` packages), it captures this package too. Install with
|
|
118
118
|
> `npm install -g @nasebanal/cli --@nasebanal:registry=https://registry.npmjs.org/`.
|
|
119
119
|
|
|
120
|
+
### Upgrading
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
nb upgrade # install the latest published version
|
|
124
|
+
nb upgrade --check # only report whether a newer version exists
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
When a newer version is out, interactive runs print a one-line notice on stderr
|
|
128
|
+
(`Update available: 0.5.0 -> 0.6.0`). The registry is checked at most once a day
|
|
129
|
+
and the result is cached in `~/.config/nasebanal/update-check.json`. Nothing is
|
|
130
|
+
printed when stderr is not a terminal or `CI` is set; `NB_NO_UPDATE_NOTIFIER=1`
|
|
131
|
+
turns the notice off. A dev link to a source checkout is never overwritten:
|
|
132
|
+
`nb upgrade` tells you to `git pull && npm run build` instead.
|
|
133
|
+
|
|
120
134
|
### Versioning and releases
|
|
121
135
|
|
|
122
136
|
Versions follow SemVer (0.x until 1.0: breaking changes bump the minor). Each
|
package/dist/apis.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export const API_CATALOG = [
|
|
2
2
|
{ name: "account", spec: "account.yaml", summary: "User profiles, subscriptions, billing, and API tokens" },
|
|
3
|
-
{ name: "
|
|
3
|
+
{ name: "record", spec: "recorder.yaml", summary: "Records and tags (NASEBANAL Recorder)" },
|
|
4
4
|
{ name: "target", spec: "target.yaml", summary: "Targets, cells, and shares (NASEBANAL Target)" },
|
|
5
5
|
{ name: "assurance", spec: "assurance.yaml", summary: "Monitors, projects and CI/CD test results (NASEBANAL Assurance)" },
|
|
6
|
-
{ name: "app-template", spec: "app-template.yaml", summary: "Reference API surface (App Template)" },
|
|
7
6
|
];
|
package/dist/config.js
CHANGED
|
@@ -12,7 +12,7 @@ import { homedir } from "node:os";
|
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
import { mkdirSync, readFileSync, writeFileSync, chmodSync, existsSync } from "node:fs";
|
|
14
14
|
import { refreshTokens } from "./oauth.js";
|
|
15
|
-
function configDir() {
|
|
15
|
+
export function configDir() {
|
|
16
16
|
const base = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
17
17
|
return join(base, "nasebanal");
|
|
18
18
|
}
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import { buildAuthCommand } from "./auth.js";
|
|
|
14
14
|
import { specExists } from "./spec/loader.js";
|
|
15
15
|
import { printError } from "./output.js";
|
|
16
16
|
import { buildReportUploadCommand } from "./reports/upload.js";
|
|
17
|
+
import { buildUpgradeCommand, startUpdateNotifier } from "./update.js";
|
|
17
18
|
// Single source of truth for the version: package.json (dist/ and src/ both sit
|
|
18
19
|
// next to it). A hard-coded string here drifts from the release tag.
|
|
19
20
|
const { version } = createRequire(import.meta.url)("../package.json");
|
|
@@ -26,6 +27,7 @@ program
|
|
|
26
27
|
.option("--token <token>", "override the stored PAT for this invocation")
|
|
27
28
|
.showHelpAfterError();
|
|
28
29
|
program.addCommand(buildAuthCommand());
|
|
30
|
+
program.addCommand(buildUpgradeCommand(version));
|
|
29
31
|
for (const api of API_CATALOG) {
|
|
30
32
|
if (!specExists(api.spec)) {
|
|
31
33
|
// Spec not synced yet — register a stub that explains how to fix it rather
|
|
@@ -50,8 +52,10 @@ for (const api of API_CATALOG) {
|
|
|
50
52
|
program.addCommand(group);
|
|
51
53
|
}
|
|
52
54
|
async function main() {
|
|
55
|
+
const notifier = startUpdateNotifier(version, process.argv);
|
|
53
56
|
try {
|
|
54
57
|
await program.parseAsync(process.argv);
|
|
58
|
+
await notifier.refresh();
|
|
55
59
|
}
|
|
56
60
|
catch (err) {
|
|
57
61
|
printError(err);
|
package/dist/update.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-update: a passive "new version available" notice and `nb upgrade`.
|
|
3
|
+
*
|
|
4
|
+
* Follows the usual CLI convention (npm, gh, gcloud): the notice is a single
|
|
5
|
+
* line on stderr, shown at most once a day from a cached registry lookup, and
|
|
6
|
+
* silent for non-interactive use (pipes, CI) so scripted output never changes.
|
|
7
|
+
* `NB_NO_UPDATE_NOTIFIER=1` turns it off.
|
|
8
|
+
*/
|
|
9
|
+
import { spawnSync } from "node:child_process";
|
|
10
|
+
import { mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { Command } from "commander";
|
|
13
|
+
import { configDir } from "./config.js";
|
|
14
|
+
const PACKAGE = "@nasebanal/cli";
|
|
15
|
+
const REGISTRY = "https://registry.npmjs.org";
|
|
16
|
+
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
17
|
+
const FETCH_TIMEOUT_MS = 1500;
|
|
18
|
+
/** 1 if a > b, -1 if a < b, 0 if equal (plain `x.y.z`; pre-release tags are ignored). */
|
|
19
|
+
export function compareVersions(a, b) {
|
|
20
|
+
const pa = a.split("-")[0].split(".").map(Number);
|
|
21
|
+
const pb = b.split("-")[0].split(".").map(Number);
|
|
22
|
+
for (let i = 0; i < 3; i++) {
|
|
23
|
+
const d = (pa[i] || 0) - (pb[i] || 0);
|
|
24
|
+
if (d !== 0)
|
|
25
|
+
return d > 0 ? 1 : -1;
|
|
26
|
+
}
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
function cachePath() {
|
|
30
|
+
return join(configDir(), "update-check.json");
|
|
31
|
+
}
|
|
32
|
+
function readCache() {
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(readFileSync(cachePath(), "utf8"));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function writeCache(cache) {
|
|
41
|
+
try {
|
|
42
|
+
mkdirSync(configDir(), { recursive: true });
|
|
43
|
+
writeFileSync(cachePath(), JSON.stringify(cache) + "\n");
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
/* best effort */
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Latest published version. Goes to the public registry directly, so a `~/.npmrc` scope mapping cannot hide it. */
|
|
50
|
+
export async function fetchLatest(timeoutMs = FETCH_TIMEOUT_MS) {
|
|
51
|
+
try {
|
|
52
|
+
const res = await fetch(`${REGISTRY}/${PACKAGE.replace("/", "%2F")}/latest`, {
|
|
53
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
54
|
+
});
|
|
55
|
+
if (!res.ok)
|
|
56
|
+
return undefined;
|
|
57
|
+
return (await res.json()).version;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function notifierEnabled() {
|
|
64
|
+
return !process.env.NB_NO_UPDATE_NOTIFIER && !process.env.CI && !!process.stderr.isTTY;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Arrange for the update notice to print when the process exits. Reads the
|
|
68
|
+
* cache synchronously; when it is older than a day, refreshes it afterwards
|
|
69
|
+
* (bounded by a short timeout) so the notice appears from the next run on.
|
|
70
|
+
*/
|
|
71
|
+
export function startUpdateNotifier(current, argv) {
|
|
72
|
+
const noop = { refresh: async () => { } };
|
|
73
|
+
if (!notifierEnabled() || argv.slice(2).some((a) => a === "upgrade" || a === "--version" || a === "-V"))
|
|
74
|
+
return noop;
|
|
75
|
+
const cache = readCache();
|
|
76
|
+
if (cache?.latest && compareVersions(cache.latest, current) > 0) {
|
|
77
|
+
const latest = cache.latest;
|
|
78
|
+
process.on("exit", () => {
|
|
79
|
+
process.stderr.write(`\nUpdate available: ${current} -> ${latest}. Run \`nb upgrade\` to install it.\n`);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const stale = !cache || Date.now() - cache.checkedAt > CHECK_INTERVAL_MS;
|
|
83
|
+
return {
|
|
84
|
+
refresh: async () => {
|
|
85
|
+
if (!stale)
|
|
86
|
+
return;
|
|
87
|
+
const latest = await fetchLatest();
|
|
88
|
+
// Record the attempt even on failure so an offline machine is not retried on every command.
|
|
89
|
+
writeCache({ checkedAt: Date.now(), latest: latest ?? cache?.latest });
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** True when `nb` is a dev link to a checkout rather than an npm-installed copy. */
|
|
94
|
+
function isLinkedCheckout() {
|
|
95
|
+
try {
|
|
96
|
+
return !realpathSync(process.argv[1]).includes("node_modules");
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export function buildUpgradeCommand(current) {
|
|
103
|
+
return new Command("upgrade")
|
|
104
|
+
.description("Upgrade nb to the latest published version")
|
|
105
|
+
.option("--check", "only report whether a newer version exists")
|
|
106
|
+
.action(async (opts) => {
|
|
107
|
+
const latest = await fetchLatest(5000);
|
|
108
|
+
if (!latest)
|
|
109
|
+
throw new Error("Could not reach the npm registry to look up the latest version.");
|
|
110
|
+
writeCache({ checkedAt: Date.now(), latest });
|
|
111
|
+
if (compareVersions(latest, current) <= 0) {
|
|
112
|
+
process.stdout.write(`nb ${current} is up to date.\n`);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
process.stdout.write(`Update available: ${current} -> ${latest}\n`);
|
|
116
|
+
if (opts.check)
|
|
117
|
+
return;
|
|
118
|
+
if (isLinkedCheckout()) {
|
|
119
|
+
process.stdout.write("This nb is linked to a source checkout: `git pull && npm run build` there instead.\n");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const r = spawnSync("npm", ["install", "-g", `${PACKAGE}@${latest}`, `--@nasebanal:registry=${REGISTRY}/`], { stdio: "inherit" });
|
|
123
|
+
if (r.status !== 0) {
|
|
124
|
+
throw new Error(`npm install failed. Run it yourself: npm install -g ${PACKAGE}@latest --@nasebanal:registry=${REGISTRY}/`);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
package/package.json
CHANGED
package/specs/app-template.yaml
DELETED
|
@@ -1,488 +0,0 @@
|
|
|
1
|
-
openapi: 3.0.3
|
|
2
|
-
info:
|
|
3
|
-
title: NASEBANAL - App Template API
|
|
4
|
-
description: |-
|
|
5
|
-
A template API for NASEBANAL applications. Provides sample CRUD endpoints, user authentication via Auth0 JWT and Personal Access Tokens (PAT), and integration with the Account API.
|
|
6
|
-
|
|
7
|
-
All responses use a uniform envelope: successful responses are `{ "success": true, "data": ... }` and failures are `{ "success": false, "error": { "code", "message" } }`. This mirrors `successResponse()` / `errorResponse()` in the implementation. The `success` discriminator is pinned with `enum` so both Specmatic stub generation and contract tests treat it as a fixed value per response class.
|
|
8
|
-
version: 1.1.1
|
|
9
|
-
contact:
|
|
10
|
-
name: NASEBANAL
|
|
11
|
-
url: https://www.nasebanal.com
|
|
12
|
-
servers:
|
|
13
|
-
- url: http://localhost:8789
|
|
14
|
-
description: Local dev (wrangler dev)
|
|
15
|
-
- url: https://api.app-template.nasebanal.com
|
|
16
|
-
description: Production
|
|
17
|
-
security:
|
|
18
|
-
- BearerAuth: []
|
|
19
|
-
paths:
|
|
20
|
-
/api/v1/health:
|
|
21
|
-
get:
|
|
22
|
-
operationId: getHealth
|
|
23
|
-
tags:
|
|
24
|
-
- Health
|
|
25
|
-
summary: Health check
|
|
26
|
-
description: Returns the health status of the API.
|
|
27
|
-
security: []
|
|
28
|
-
responses:
|
|
29
|
-
"200":
|
|
30
|
-
description: API is healthy
|
|
31
|
-
content:
|
|
32
|
-
application/json:
|
|
33
|
-
schema:
|
|
34
|
-
type: object
|
|
35
|
-
required:
|
|
36
|
-
- success
|
|
37
|
-
- data
|
|
38
|
-
properties:
|
|
39
|
-
success:
|
|
40
|
-
type: boolean
|
|
41
|
-
enum:
|
|
42
|
-
- true
|
|
43
|
-
data:
|
|
44
|
-
type: object
|
|
45
|
-
required:
|
|
46
|
-
- status
|
|
47
|
-
- timestamp
|
|
48
|
-
properties:
|
|
49
|
-
status:
|
|
50
|
-
type: string
|
|
51
|
-
timestamp:
|
|
52
|
-
type: string
|
|
53
|
-
format: date-time
|
|
54
|
-
examples:
|
|
55
|
-
valid:
|
|
56
|
-
value:
|
|
57
|
-
success: true
|
|
58
|
-
data:
|
|
59
|
-
status: ok
|
|
60
|
-
timestamp: 2026-05-14T12:00:00Z
|
|
61
|
-
/api/v1/me:
|
|
62
|
-
get:
|
|
63
|
-
operationId: getCurrentUser
|
|
64
|
-
tags:
|
|
65
|
-
- User
|
|
66
|
-
summary: Get current user profile
|
|
67
|
-
description: Returns the authenticated user's profile information from the Account API.
|
|
68
|
-
responses:
|
|
69
|
-
"200":
|
|
70
|
-
description: User profile
|
|
71
|
-
content:
|
|
72
|
-
application/json:
|
|
73
|
-
schema:
|
|
74
|
-
$ref: "#/components/schemas/UserResponse"
|
|
75
|
-
examples:
|
|
76
|
-
valid:
|
|
77
|
-
value:
|
|
78
|
-
success: true
|
|
79
|
-
data:
|
|
80
|
-
id: 42
|
|
81
|
-
auth0_sub: auth0|0123456789abcdef
|
|
82
|
-
email: user@example.com
|
|
83
|
-
name: Sample User
|
|
84
|
-
language: ja
|
|
85
|
-
plan: pro
|
|
86
|
-
subscription_status: active
|
|
87
|
-
subscription_expires_at: 2026-12-31T23:59:59Z
|
|
88
|
-
"401":
|
|
89
|
-
$ref: "#/components/responses/Unauthorized"
|
|
90
|
-
/api/v1/items:
|
|
91
|
-
get:
|
|
92
|
-
operationId: listItems
|
|
93
|
-
tags:
|
|
94
|
-
- Items
|
|
95
|
-
summary: List items
|
|
96
|
-
description: Returns all items belonging to the authenticated user.
|
|
97
|
-
responses:
|
|
98
|
-
"200":
|
|
99
|
-
description: List of items
|
|
100
|
-
content:
|
|
101
|
-
application/json:
|
|
102
|
-
schema:
|
|
103
|
-
type: object
|
|
104
|
-
required:
|
|
105
|
-
- success
|
|
106
|
-
- data
|
|
107
|
-
properties:
|
|
108
|
-
success:
|
|
109
|
-
type: boolean
|
|
110
|
-
enum:
|
|
111
|
-
- true
|
|
112
|
-
data:
|
|
113
|
-
type: object
|
|
114
|
-
required:
|
|
115
|
-
- data
|
|
116
|
-
- total
|
|
117
|
-
properties:
|
|
118
|
-
data:
|
|
119
|
-
type: array
|
|
120
|
-
items:
|
|
121
|
-
$ref: "#/components/schemas/Item"
|
|
122
|
-
total:
|
|
123
|
-
type: integer
|
|
124
|
-
examples:
|
|
125
|
-
valid:
|
|
126
|
-
value:
|
|
127
|
-
success: true
|
|
128
|
-
data:
|
|
129
|
-
data:
|
|
130
|
-
- id: itm_a1b2c3d4
|
|
131
|
-
user_id: 42
|
|
132
|
-
name: My Item
|
|
133
|
-
description: A sample item description
|
|
134
|
-
created_at: 2026-05-14T12:00:00Z
|
|
135
|
-
updated_at: 2026-05-14T12:00:00Z
|
|
136
|
-
total: 1
|
|
137
|
-
"401":
|
|
138
|
-
$ref: "#/components/responses/Unauthorized"
|
|
139
|
-
post:
|
|
140
|
-
operationId: createItem
|
|
141
|
-
tags:
|
|
142
|
-
- Items
|
|
143
|
-
summary: Create item
|
|
144
|
-
description: Creates a new item for the authenticated user.
|
|
145
|
-
requestBody:
|
|
146
|
-
required: true
|
|
147
|
-
content:
|
|
148
|
-
application/json:
|
|
149
|
-
schema:
|
|
150
|
-
$ref: "#/components/schemas/CreateItemInput"
|
|
151
|
-
examples:
|
|
152
|
-
valid:
|
|
153
|
-
value:
|
|
154
|
-
name: My Item
|
|
155
|
-
description: A sample item description
|
|
156
|
-
responses:
|
|
157
|
-
"201":
|
|
158
|
-
description: Item created
|
|
159
|
-
content:
|
|
160
|
-
application/json:
|
|
161
|
-
schema:
|
|
162
|
-
$ref: "#/components/schemas/ItemResponse"
|
|
163
|
-
examples:
|
|
164
|
-
valid:
|
|
165
|
-
value:
|
|
166
|
-
success: true
|
|
167
|
-
data:
|
|
168
|
-
id: itm_a1b2c3d4
|
|
169
|
-
user_id: 42
|
|
170
|
-
name: My Item
|
|
171
|
-
description: A sample item description
|
|
172
|
-
created_at: 2026-05-14T12:00:00Z
|
|
173
|
-
updated_at: 2026-05-14T12:00:00Z
|
|
174
|
-
"401":
|
|
175
|
-
$ref: "#/components/responses/Unauthorized"
|
|
176
|
-
/api/v1/items/{id}:
|
|
177
|
-
get:
|
|
178
|
-
operationId: getItem
|
|
179
|
-
tags:
|
|
180
|
-
- Items
|
|
181
|
-
summary: Get item
|
|
182
|
-
description: Returns a single item by ID.
|
|
183
|
-
parameters:
|
|
184
|
-
- name: id
|
|
185
|
-
in: path
|
|
186
|
-
required: true
|
|
187
|
-
schema:
|
|
188
|
-
type: string
|
|
189
|
-
examples:
|
|
190
|
-
valid:
|
|
191
|
-
value: itm_a1b2c3d4
|
|
192
|
-
responses:
|
|
193
|
-
"200":
|
|
194
|
-
description: Item details
|
|
195
|
-
content:
|
|
196
|
-
application/json:
|
|
197
|
-
schema:
|
|
198
|
-
$ref: "#/components/schemas/ItemResponse"
|
|
199
|
-
examples:
|
|
200
|
-
valid:
|
|
201
|
-
value:
|
|
202
|
-
success: true
|
|
203
|
-
data:
|
|
204
|
-
id: itm_a1b2c3d4
|
|
205
|
-
user_id: 42
|
|
206
|
-
name: My Item
|
|
207
|
-
description: A sample item description
|
|
208
|
-
created_at: 2026-05-14T12:00:00Z
|
|
209
|
-
updated_at: 2026-05-14T12:00:00Z
|
|
210
|
-
"401":
|
|
211
|
-
$ref: "#/components/responses/Unauthorized"
|
|
212
|
-
"404":
|
|
213
|
-
$ref: "#/components/responses/NotFound"
|
|
214
|
-
put:
|
|
215
|
-
operationId: updateItem
|
|
216
|
-
tags:
|
|
217
|
-
- Items
|
|
218
|
-
summary: Update item
|
|
219
|
-
description: Updates an existing item.
|
|
220
|
-
parameters:
|
|
221
|
-
- name: id
|
|
222
|
-
in: path
|
|
223
|
-
required: true
|
|
224
|
-
schema:
|
|
225
|
-
type: string
|
|
226
|
-
examples:
|
|
227
|
-
valid:
|
|
228
|
-
value: itm_a1b2c3d4
|
|
229
|
-
requestBody:
|
|
230
|
-
required: true
|
|
231
|
-
content:
|
|
232
|
-
application/json:
|
|
233
|
-
schema:
|
|
234
|
-
$ref: "#/components/schemas/UpdateItemInput"
|
|
235
|
-
examples:
|
|
236
|
-
valid:
|
|
237
|
-
value:
|
|
238
|
-
name: Updated Item
|
|
239
|
-
description: An updated item description
|
|
240
|
-
responses:
|
|
241
|
-
"200":
|
|
242
|
-
description: Item updated
|
|
243
|
-
content:
|
|
244
|
-
application/json:
|
|
245
|
-
schema:
|
|
246
|
-
$ref: "#/components/schemas/ItemResponse"
|
|
247
|
-
examples:
|
|
248
|
-
valid:
|
|
249
|
-
value:
|
|
250
|
-
success: true
|
|
251
|
-
data:
|
|
252
|
-
id: itm_a1b2c3d4
|
|
253
|
-
user_id: 42
|
|
254
|
-
name: Updated Item
|
|
255
|
-
description: An updated item description
|
|
256
|
-
created_at: 2026-05-14T12:00:00Z
|
|
257
|
-
updated_at: 2026-05-15T09:30:00Z
|
|
258
|
-
"401":
|
|
259
|
-
$ref: "#/components/responses/Unauthorized"
|
|
260
|
-
"404":
|
|
261
|
-
$ref: "#/components/responses/NotFound"
|
|
262
|
-
delete:
|
|
263
|
-
operationId: deleteItem
|
|
264
|
-
tags:
|
|
265
|
-
- Items
|
|
266
|
-
summary: Delete item
|
|
267
|
-
description: Deletes an item by ID.
|
|
268
|
-
parameters:
|
|
269
|
-
- name: id
|
|
270
|
-
in: path
|
|
271
|
-
required: true
|
|
272
|
-
schema:
|
|
273
|
-
type: string
|
|
274
|
-
examples:
|
|
275
|
-
valid:
|
|
276
|
-
value: itm_a1b2c3d4
|
|
277
|
-
responses:
|
|
278
|
-
"200":
|
|
279
|
-
description: Item deleted
|
|
280
|
-
content:
|
|
281
|
-
application/json:
|
|
282
|
-
schema:
|
|
283
|
-
$ref: "#/components/schemas/SuccessResponse"
|
|
284
|
-
examples:
|
|
285
|
-
valid:
|
|
286
|
-
value:
|
|
287
|
-
success: true
|
|
288
|
-
data:
|
|
289
|
-
success: true
|
|
290
|
-
"401":
|
|
291
|
-
$ref: "#/components/responses/Unauthorized"
|
|
292
|
-
"404":
|
|
293
|
-
$ref: "#/components/responses/NotFound"
|
|
294
|
-
components:
|
|
295
|
-
securitySchemes:
|
|
296
|
-
BearerAuth:
|
|
297
|
-
type: http
|
|
298
|
-
scheme: bearer
|
|
299
|
-
bearerFormat: JWT or PAT
|
|
300
|
-
description: Use either an Auth0 JWT token or a Personal Access Token (PAT) starting with `nbpat_`.
|
|
301
|
-
schemas:
|
|
302
|
-
User:
|
|
303
|
-
type: object
|
|
304
|
-
required:
|
|
305
|
-
- id
|
|
306
|
-
- auth0_sub
|
|
307
|
-
- email
|
|
308
|
-
- name
|
|
309
|
-
- language
|
|
310
|
-
- plan
|
|
311
|
-
properties:
|
|
312
|
-
id:
|
|
313
|
-
type: integer
|
|
314
|
-
auth0_sub:
|
|
315
|
-
type: string
|
|
316
|
-
email:
|
|
317
|
-
type: string
|
|
318
|
-
format: email
|
|
319
|
-
name:
|
|
320
|
-
type: string
|
|
321
|
-
language:
|
|
322
|
-
type: string
|
|
323
|
-
enum:
|
|
324
|
-
- ja
|
|
325
|
-
- en
|
|
326
|
-
plan:
|
|
327
|
-
type: string
|
|
328
|
-
enum:
|
|
329
|
-
- free
|
|
330
|
-
- pro
|
|
331
|
-
- family
|
|
332
|
-
- enterprise
|
|
333
|
-
subscription_status:
|
|
334
|
-
type: string
|
|
335
|
-
enum:
|
|
336
|
-
- active
|
|
337
|
-
- canceled
|
|
338
|
-
- past_due
|
|
339
|
-
- trialing
|
|
340
|
-
- null
|
|
341
|
-
nullable: true
|
|
342
|
-
subscription_expires_at:
|
|
343
|
-
type: string
|
|
344
|
-
format: date-time
|
|
345
|
-
nullable: true
|
|
346
|
-
UserResponse:
|
|
347
|
-
type: object
|
|
348
|
-
required:
|
|
349
|
-
- success
|
|
350
|
-
- data
|
|
351
|
-
properties:
|
|
352
|
-
success:
|
|
353
|
-
type: boolean
|
|
354
|
-
enum:
|
|
355
|
-
- true
|
|
356
|
-
data:
|
|
357
|
-
$ref: "#/components/schemas/User"
|
|
358
|
-
Item:
|
|
359
|
-
type: object
|
|
360
|
-
required:
|
|
361
|
-
- id
|
|
362
|
-
- user_id
|
|
363
|
-
- name
|
|
364
|
-
- created_at
|
|
365
|
-
- updated_at
|
|
366
|
-
properties:
|
|
367
|
-
id:
|
|
368
|
-
type: string
|
|
369
|
-
user_id:
|
|
370
|
-
type: integer
|
|
371
|
-
name:
|
|
372
|
-
type: string
|
|
373
|
-
description:
|
|
374
|
-
type: string
|
|
375
|
-
nullable: true
|
|
376
|
-
created_at:
|
|
377
|
-
type: string
|
|
378
|
-
format: date-time
|
|
379
|
-
updated_at:
|
|
380
|
-
type: string
|
|
381
|
-
format: date-time
|
|
382
|
-
ItemResponse:
|
|
383
|
-
type: object
|
|
384
|
-
required:
|
|
385
|
-
- success
|
|
386
|
-
- data
|
|
387
|
-
properties:
|
|
388
|
-
success:
|
|
389
|
-
type: boolean
|
|
390
|
-
enum:
|
|
391
|
-
- true
|
|
392
|
-
data:
|
|
393
|
-
$ref: "#/components/schemas/Item"
|
|
394
|
-
CreateItemInput:
|
|
395
|
-
type: object
|
|
396
|
-
required:
|
|
397
|
-
- name
|
|
398
|
-
properties:
|
|
399
|
-
name:
|
|
400
|
-
type: string
|
|
401
|
-
minLength: 1
|
|
402
|
-
maxLength: 200
|
|
403
|
-
description:
|
|
404
|
-
type: string
|
|
405
|
-
maxLength: 1000
|
|
406
|
-
UpdateItemInput:
|
|
407
|
-
type: object
|
|
408
|
-
properties:
|
|
409
|
-
name:
|
|
410
|
-
type: string
|
|
411
|
-
minLength: 1
|
|
412
|
-
maxLength: 200
|
|
413
|
-
description:
|
|
414
|
-
type: string
|
|
415
|
-
maxLength: 1000
|
|
416
|
-
SuccessResponse:
|
|
417
|
-
type: object
|
|
418
|
-
required:
|
|
419
|
-
- success
|
|
420
|
-
- data
|
|
421
|
-
properties:
|
|
422
|
-
success:
|
|
423
|
-
type: boolean
|
|
424
|
-
enum:
|
|
425
|
-
- true
|
|
426
|
-
data:
|
|
427
|
-
type: object
|
|
428
|
-
required:
|
|
429
|
-
- success
|
|
430
|
-
properties:
|
|
431
|
-
success:
|
|
432
|
-
type: boolean
|
|
433
|
-
enum:
|
|
434
|
-
- true
|
|
435
|
-
Error:
|
|
436
|
-
type: object
|
|
437
|
-
required:
|
|
438
|
-
- success
|
|
439
|
-
- error
|
|
440
|
-
properties:
|
|
441
|
-
success:
|
|
442
|
-
type: boolean
|
|
443
|
-
enum:
|
|
444
|
-
- false
|
|
445
|
-
error:
|
|
446
|
-
type: object
|
|
447
|
-
required:
|
|
448
|
-
- code
|
|
449
|
-
- message
|
|
450
|
-
properties:
|
|
451
|
-
code:
|
|
452
|
-
type: string
|
|
453
|
-
message:
|
|
454
|
-
type: string
|
|
455
|
-
responses:
|
|
456
|
-
Unauthorized:
|
|
457
|
-
description: Authentication required or invalid token
|
|
458
|
-
content:
|
|
459
|
-
application/json:
|
|
460
|
-
schema:
|
|
461
|
-
$ref: "#/components/schemas/Error"
|
|
462
|
-
examples:
|
|
463
|
-
unauthorized:
|
|
464
|
-
value:
|
|
465
|
-
success: false
|
|
466
|
-
error:
|
|
467
|
-
code: AUTH_ERROR
|
|
468
|
-
message: No authentication token provided
|
|
469
|
-
NotFound:
|
|
470
|
-
description: Resource not found
|
|
471
|
-
content:
|
|
472
|
-
application/json:
|
|
473
|
-
schema:
|
|
474
|
-
$ref: "#/components/schemas/Error"
|
|
475
|
-
examples:
|
|
476
|
-
not_found:
|
|
477
|
-
value:
|
|
478
|
-
success: false
|
|
479
|
-
error:
|
|
480
|
-
code: NOT_FOUND
|
|
481
|
-
message: Resource not found
|
|
482
|
-
tags:
|
|
483
|
-
- name: Health
|
|
484
|
-
description: Health check endpoints
|
|
485
|
-
- name: User
|
|
486
|
-
description: User profile endpoints
|
|
487
|
-
- name: Items
|
|
488
|
-
description: Sample CRUD endpoints (replace with your domain)
|