aranea-sdk-cli 0.5.2 → 0.5.5

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.
@@ -0,0 +1,18 @@
1
+ /**
2
+ * AraneaSDK CLI - Permission Command
3
+ *
4
+ * TypeDefaultPermissions management for AraneaDevice types
5
+ *
6
+ * Usage:
7
+ * aranea-sdk permission list # List all typeDefaultPermissions
8
+ * aranea-sdk permission get <type> # Get permission for specific type
9
+ * aranea-sdk permission set <type> <level> # Set default permission level
10
+ * aranea-sdk permission delete <type> # Delete typeDefaultPermission
11
+ *
12
+ * Note: Requires System Authority Layer permission (71+)
13
+ */
14
+ import { Command } from 'commander';
15
+ /**
16
+ * Permission command
17
+ */
18
+ export declare const permissionCommand: Command;
@@ -0,0 +1,412 @@
1
+ "use strict";
2
+ /**
3
+ * AraneaSDK CLI - Permission Command
4
+ *
5
+ * TypeDefaultPermissions management for AraneaDevice types
6
+ *
7
+ * Usage:
8
+ * aranea-sdk permission list # List all typeDefaultPermissions
9
+ * aranea-sdk permission get <type> # Get permission for specific type
10
+ * aranea-sdk permission set <type> <level> # Set default permission level
11
+ * aranea-sdk permission delete <type> # Delete typeDefaultPermission
12
+ *
13
+ * Note: Requires System Authority Layer permission (71+)
14
+ */
15
+ var __importDefault = (this && this.__importDefault) || function (mod) {
16
+ return (mod && mod.__esModule) ? mod : { "default": mod };
17
+ };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.permissionCommand = void 0;
20
+ const commander_1 = require("commander");
21
+ const chalk_1 = __importDefault(require("chalk"));
22
+ const auth_1 = require("./auth");
23
+ const config_1 = require("../config");
24
+ // Firebase project configuration
25
+ const FIREBASE_PROJECTS = {
26
+ production: 'mobesorder',
27
+ staging: 'mobesorder-staging',
28
+ };
29
+ const FIREBASE_REGION = 'asia-northeast1';
30
+ /**
31
+ * Call Firebase Callable Function
32
+ */
33
+ async function callFunction(functionName, data, token, env) {
34
+ const projectId = FIREBASE_PROJECTS[env];
35
+ const url = `https://${FIREBASE_REGION}-${projectId}.cloudfunctions.net/${functionName}`;
36
+ const response = await fetch(url, {
37
+ method: 'POST',
38
+ headers: {
39
+ 'Content-Type': 'application/json',
40
+ Authorization: `Bearer ${token}`,
41
+ },
42
+ body: JSON.stringify({ data }),
43
+ });
44
+ if (!response.ok) {
45
+ const errorBody = await response.json().catch(() => ({}));
46
+ const errorMessage = errorBody.error?.message || `HTTP ${response.status}`;
47
+ throw new Error(errorMessage);
48
+ }
49
+ const result = await response.json();
50
+ return result.result;
51
+ }
52
+ /**
53
+ * Firestore REST API for direct reads
54
+ */
55
+ async function firestoreGet(path, token, env) {
56
+ const projectId = FIREBASE_PROJECTS[env];
57
+ const url = `https://firestore.googleapis.com/v1/projects/${projectId}/databases/(default)/documents/${path}`;
58
+ const response = await fetch(url, {
59
+ method: 'GET',
60
+ headers: {
61
+ Authorization: `Bearer ${token}`,
62
+ },
63
+ });
64
+ if (!response.ok) {
65
+ if (response.status === 404) {
66
+ return null;
67
+ }
68
+ const errorBody = await response.json().catch(() => ({}));
69
+ throw new Error(errorBody.error?.message || `HTTP ${response.status}`);
70
+ }
71
+ return response.json();
72
+ }
73
+ /**
74
+ * List all typeDefaultPermissions
75
+ */
76
+ async function firestoreListTypeDefaultPermissions(token, env) {
77
+ const projectId = FIREBASE_PROJECTS[env];
78
+ const collectionPath = 'LacisOathConfig/permissionConfig/typeDefaultPermissions';
79
+ const url = `https://firestore.googleapis.com/v1/projects/${projectId}/databases/(default)/documents/${collectionPath}`;
80
+ const response = await fetch(url, {
81
+ method: 'GET',
82
+ headers: {
83
+ Authorization: `Bearer ${token}`,
84
+ },
85
+ });
86
+ if (!response.ok) {
87
+ if (response.status === 404) {
88
+ return [];
89
+ }
90
+ const errorBody = await response.json().catch(() => ({}));
91
+ throw new Error(errorBody.error?.message || `HTTP ${response.status}`);
92
+ }
93
+ const result = await response.json();
94
+ return result.documents || [];
95
+ }
96
+ /**
97
+ * Parse Firestore document fields to plain object
98
+ */
99
+ function parseFirestoreFields(fields) {
100
+ const result = {};
101
+ for (const [key, value] of Object.entries(fields)) {
102
+ if ('stringValue' in value) {
103
+ result[key] = value.stringValue;
104
+ }
105
+ else if ('integerValue' in value) {
106
+ result[key] = parseInt(value.integerValue, 10);
107
+ }
108
+ else if ('doubleValue' in value) {
109
+ result[key] = value.doubleValue;
110
+ }
111
+ else if ('booleanValue' in value) {
112
+ result[key] = value.booleanValue;
113
+ }
114
+ else if ('timestampValue' in value) {
115
+ result[key] = new Date(value.timestampValue);
116
+ }
117
+ else if ('mapValue' in value) {
118
+ result[key] = parseFirestoreFields(value.mapValue.fields || {});
119
+ }
120
+ else if ('arrayValue' in value) {
121
+ result[key] = (value.arrayValue.values || []).map((v) => parseFirestoreFields({ _: v })._);
122
+ }
123
+ }
124
+ return result;
125
+ }
126
+ /**
127
+ * Format permission level with description
128
+ */
129
+ function formatPermissionLevel(level) {
130
+ if (level >= 100)
131
+ return chalk_1.default.magenta(`${level} (Lacis/SU)`);
132
+ if (level >= 71)
133
+ return chalk_1.default.red(`${level} (System Authority)`);
134
+ if (level >= 61)
135
+ return chalk_1.default.yellow(`${level} (Tenant Primary)`);
136
+ if (level >= 41)
137
+ return chalk_1.default.blue(`${level} (Management Authority)`);
138
+ if (level >= 21)
139
+ return chalk_1.default.cyan(`${level} (Standard User)`);
140
+ if (level >= 11)
141
+ return chalk_1.default.green(`${level} (Guest+)`);
142
+ if (level >= 3)
143
+ return chalk_1.default.gray(`${level} (Guest)`);
144
+ return chalk_1.default.red(`${level} (Reserved/BAN)`);
145
+ }
146
+ /**
147
+ * Permission command
148
+ */
149
+ exports.permissionCommand = new commander_1.Command('permission')
150
+ .description('TypeDefaultPermissions management for AraneaDevice types')
151
+ .addHelpText('after', `
152
+ Permission Levels (Cathedral Orders):
153
+ 100 : Lacis (System Super User)
154
+ 71-99 : System Authority Layer (cross-tenant)
155
+ 61-70 : Tenant Primary Layer
156
+ 41-60 : Management Authority Layer
157
+ 21-40 : Standard User Layer
158
+ 11-20 : Guest+ Layer
159
+ 3-10 : Guest Layer
160
+ 0-2 : Reserved/BAN
161
+
162
+ Examples:
163
+ aranea-sdk permission list
164
+ aranea-sdk permission get aranea_ar-is22
165
+ aranea-sdk permission set aranea_ar-is22 21
166
+ aranea-sdk permission set aranea_ar-is22 21 --display-name "AR-IS22センサー"
167
+ aranea-sdk permission delete aranea_ar-is22
168
+
169
+ Note: Requires System Authority Layer permission (71+) for modifications.
170
+ `);
171
+ // permission list
172
+ exports.permissionCommand
173
+ .command('list')
174
+ .description('List all typeDefaultPermissions')
175
+ .option('--endpoint <env>', 'Target environment (production|staging)')
176
+ .option('--json', 'Output as JSON')
177
+ .action(async (options) => {
178
+ try {
179
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
180
+ (0, config_1.checkStagingAvailability)(env, 'permission list');
181
+ const token = await (0, auth_1.getValidToken)();
182
+ if (!token) {
183
+ console.error(chalk_1.default.red('\n✖ Not authenticated. Run "aranea-sdk auth login" first.'));
184
+ process.exit(1);
185
+ }
186
+ if (!options.json) {
187
+ console.log(chalk_1.default.cyan('\n=== TypeDefaultPermissions List ===\n'));
188
+ console.log(`Environment: ${env === 'production' ? chalk_1.default.red('PRODUCTION') : chalk_1.default.yellow('staging')}`);
189
+ console.log('');
190
+ }
191
+ const documents = await firestoreListTypeDefaultPermissions(token, env);
192
+ if (documents.length === 0) {
193
+ if (options.json) {
194
+ console.log(JSON.stringify([], null, 2));
195
+ }
196
+ else {
197
+ console.log(chalk_1.default.yellow('No typeDefaultPermissions configured.'));
198
+ console.log('\nTo add a permission, use:');
199
+ console.log(' aranea-sdk permission set <typeId> <level>');
200
+ }
201
+ return;
202
+ }
203
+ const permissions = documents.map((doc) => {
204
+ const name = doc.name.split('/').pop();
205
+ const fields = parseFirestoreFields(doc.fields || {});
206
+ return {
207
+ id: name,
208
+ typeDomainId: fields.typeDomainId,
209
+ typeId: fields.typeId,
210
+ defaultPermission: fields.defaultPermission,
211
+ displayName: fields.displayName,
212
+ ...fields,
213
+ };
214
+ });
215
+ if (options.json) {
216
+ console.log(JSON.stringify(permissions, null, 2));
217
+ }
218
+ else {
219
+ console.log(chalk_1.default.gray('─'.repeat(80)));
220
+ console.log(chalk_1.default.bold(`${'TypeDomain'.padEnd(20)} ${'TypeId'.padEnd(25)} ${'Permission'.padEnd(20)} DisplayName`));
221
+ console.log(chalk_1.default.gray('─'.repeat(80)));
222
+ for (const perm of permissions) {
223
+ const typeDomain = (perm.typeDomainId || '').padEnd(20);
224
+ const typeId = (perm.typeId || '').padEnd(25);
225
+ const level = formatPermissionLevel(perm.defaultPermission || 0).padEnd(30);
226
+ const displayName = perm.displayName || '-';
227
+ console.log(`${typeDomain} ${typeId} ${level} ${displayName}`);
228
+ }
229
+ console.log(chalk_1.default.gray('─'.repeat(80)));
230
+ console.log(`\nTotal: ${permissions.length} type(s)`);
231
+ }
232
+ }
233
+ catch (error) {
234
+ console.error(chalk_1.default.red(`\n✖ Error: ${error.message}`));
235
+ process.exit(1);
236
+ }
237
+ });
238
+ // permission get
239
+ exports.permissionCommand
240
+ .command('get <typeId>')
241
+ .description('Get typeDefaultPermission for specific type')
242
+ .option('--endpoint <env>', 'Target environment (production|staging)')
243
+ .option('--type-domain <domain>', 'TypeDomain ID (default: araneaDevice)')
244
+ .option('--json', 'Output as JSON')
245
+ .action(async (typeId, options) => {
246
+ try {
247
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
248
+ (0, config_1.checkStagingAvailability)(env, 'permission get');
249
+ const token = await (0, auth_1.getValidToken)();
250
+ if (!token) {
251
+ console.error(chalk_1.default.red('\n✖ Not authenticated. Run "aranea-sdk auth login" first.'));
252
+ process.exit(1);
253
+ }
254
+ const typeDomainId = options.typeDomain || 'araneaDevice';
255
+ const docId = `${typeDomainId}_${typeId}`;
256
+ const path = `LacisOathConfig/permissionConfig/typeDefaultPermissions/${docId}`;
257
+ const doc = await firestoreGet(path, token, env);
258
+ if (!doc) {
259
+ if (options.json) {
260
+ console.log(JSON.stringify({ found: false, id: docId }, null, 2));
261
+ }
262
+ else {
263
+ console.log(chalk_1.default.yellow(`\nNo typeDefaultPermission found for: ${docId}`));
264
+ console.log('\nThis type will use the fallback default permission (Guest: 3).');
265
+ console.log('\nTo set a permission, use:');
266
+ console.log(` aranea-sdk permission set ${typeId} <level>`);
267
+ }
268
+ return;
269
+ }
270
+ const fields = parseFirestoreFields(doc.fields || {});
271
+ if (options.json) {
272
+ console.log(JSON.stringify({ found: true, id: docId, ...fields }, null, 2));
273
+ }
274
+ else {
275
+ console.log(chalk_1.default.cyan(`\n=== TypeDefaultPermission: ${docId} ===\n`));
276
+ console.log(` TypeDomain: ${fields.typeDomainId || '-'}`);
277
+ console.log(` TypeId: ${fields.typeId || '-'}`);
278
+ console.log(` Permission: ${formatPermissionLevel(fields.defaultPermission || 0)}`);
279
+ console.log(` DisplayName: ${fields.displayName || '-'}`);
280
+ if (fields.created_at) {
281
+ console.log(` Created: ${new Date(fields.created_at).toLocaleString('ja-JP')}`);
282
+ }
283
+ if (fields.updated_at) {
284
+ console.log(` Updated: ${new Date(fields.updated_at).toLocaleString('ja-JP')}`);
285
+ }
286
+ }
287
+ }
288
+ catch (error) {
289
+ console.error(chalk_1.default.red(`\n✖ Error: ${error.message}`));
290
+ process.exit(1);
291
+ }
292
+ });
293
+ // permission set
294
+ exports.permissionCommand
295
+ .command('set <typeId> <level>')
296
+ .description('Set typeDefaultPermission for a type')
297
+ .option('--endpoint <env>', 'Target environment (production|staging)')
298
+ .option('--type-domain <domain>', 'TypeDomain ID (default: araneaDevice)')
299
+ .option('--display-name <name>', 'Display name for the type')
300
+ .action(async (typeId, level, options) => {
301
+ try {
302
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
303
+ (0, config_1.checkStagingAvailability)(env, 'permission set');
304
+ (0, config_1.warnIfProduction)(env, 'permission set');
305
+ const token = await (0, auth_1.getValidToken)();
306
+ if (!token) {
307
+ console.error(chalk_1.default.red('\n✖ Not authenticated. Run "aranea-sdk auth login" first.'));
308
+ process.exit(1);
309
+ }
310
+ const permissionLevel = parseInt(level, 10);
311
+ if (isNaN(permissionLevel) || permissionLevel < 3 || permissionLevel > 100) {
312
+ console.error(chalk_1.default.red('\n✖ Permission level must be between 3 and 100.'));
313
+ console.error(' 0 = BAN, 1-2 = Reserved, 3-10 = Guest, 11-20 = Guest+, ...');
314
+ process.exit(1);
315
+ }
316
+ const typeDomainId = options.typeDomain || 'araneaDevice';
317
+ console.log(chalk_1.default.cyan('\n=== Setting TypeDefaultPermission ===\n'));
318
+ console.log(` Environment: ${env === 'production' ? chalk_1.default.red('PRODUCTION') : chalk_1.default.yellow('staging')}`);
319
+ console.log(` TypeDomain: ${typeDomainId}`);
320
+ console.log(` TypeId: ${typeId}`);
321
+ console.log(` Permission: ${formatPermissionLevel(permissionLevel)}`);
322
+ if (options.displayName) {
323
+ console.log(` DisplayName: ${options.displayName}`);
324
+ }
325
+ console.log('');
326
+ const requestData = {
327
+ typeDomainId,
328
+ typeId,
329
+ defaultPermission: permissionLevel,
330
+ };
331
+ if (options.displayName) {
332
+ requestData.displayName = options.displayName;
333
+ }
334
+ const result = await callFunction('upsertTypeDefaultPermission', requestData, token, env);
335
+ if (result.ok) {
336
+ console.log(chalk_1.default.green('✓ TypeDefaultPermission set successfully!'));
337
+ console.log(` Document ID: ${result.id}`);
338
+ }
339
+ else {
340
+ console.error(chalk_1.default.red('✖ Failed to set permission.'));
341
+ process.exit(1);
342
+ }
343
+ }
344
+ catch (error) {
345
+ const message = error.message;
346
+ // Translate common error messages
347
+ if (message.includes('permission-denied') || message.includes('71')) {
348
+ console.error(chalk_1.default.red('\n✖ Permission denied.'));
349
+ console.error(' System Authority Layer permission (71+) is required.');
350
+ console.error(' Your account does not have sufficient privileges.');
351
+ }
352
+ else if (message.includes('not-found')) {
353
+ console.error(chalk_1.default.red(`\n✖ ${message}`));
354
+ console.error(' Make sure the typeDomain and type definitions exist.');
355
+ }
356
+ else {
357
+ console.error(chalk_1.default.red(`\n✖ Error: ${message}`));
358
+ }
359
+ process.exit(1);
360
+ }
361
+ });
362
+ // permission delete
363
+ exports.permissionCommand
364
+ .command('delete <typeId>')
365
+ .description('Delete typeDefaultPermission for a type')
366
+ .option('--endpoint <env>', 'Target environment (production|staging)')
367
+ .option('--type-domain <domain>', 'TypeDomain ID (default: araneaDevice)')
368
+ .option('--force', 'Skip confirmation')
369
+ .action(async (typeId, options) => {
370
+ try {
371
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
372
+ (0, config_1.checkStagingAvailability)(env, 'permission delete');
373
+ (0, config_1.warnIfProduction)(env, 'permission delete');
374
+ const token = await (0, auth_1.getValidToken)();
375
+ if (!token) {
376
+ console.error(chalk_1.default.red('\n✖ Not authenticated. Run "aranea-sdk auth login" first.'));
377
+ process.exit(1);
378
+ }
379
+ const typeDomainId = options.typeDomain || 'araneaDevice';
380
+ const docId = `${typeDomainId}_${typeId}`;
381
+ console.log(chalk_1.default.cyan('\n=== Delete TypeDefaultPermission ===\n'));
382
+ console.log(` Environment: ${env === 'production' ? chalk_1.default.red('PRODUCTION') : chalk_1.default.yellow('staging')}`);
383
+ console.log(` Document ID: ${docId}`);
384
+ if (!options.force) {
385
+ console.log(chalk_1.default.yellow('\n⚠ This will delete the typeDefaultPermission.'));
386
+ console.log(' The type will fall back to default permission (Guest: 3).');
387
+ console.log('\nUse --force to confirm deletion.');
388
+ process.exit(1);
389
+ }
390
+ // Use Firestore REST API to delete
391
+ const projectId = FIREBASE_PROJECTS[env];
392
+ const path = `LacisOathConfig/permissionConfig/typeDefaultPermissions/${docId}`;
393
+ const url = `https://firestore.googleapis.com/v1/projects/${projectId}/databases/(default)/documents/${path}`;
394
+ const response = await fetch(url, {
395
+ method: 'DELETE',
396
+ headers: {
397
+ Authorization: `Bearer ${token}`,
398
+ },
399
+ });
400
+ if (response.ok || response.status === 404) {
401
+ console.log(chalk_1.default.green('\n✓ TypeDefaultPermission deleted.'));
402
+ }
403
+ else {
404
+ const errorBody = await response.json().catch(() => ({}));
405
+ throw new Error(errorBody.error?.message || `HTTP ${response.status}`);
406
+ }
407
+ }
408
+ catch (error) {
409
+ console.error(chalk_1.default.red(`\n✖ Error: ${error.message}`));
410
+ process.exit(1);
411
+ }
412
+ });
@@ -0,0 +1,21 @@
1
+ /**
2
+ * AraneaSDK CLI - Type Command
3
+ *
4
+ * UserTypeDefinitions management for AraneaDevice types
5
+ *
6
+ * Usage:
7
+ * aranea-sdk type list # List all types
8
+ * aranea-sdk type get <typeId> # Get specific type
9
+ * aranea-sdk type create <typeId> # Create new type
10
+ * aranea-sdk type update <typeId> # Update type
11
+ * aranea-sdk type delete <typeId> # Delete type
12
+ *
13
+ * Note:
14
+ * - Read operations require System Authority Layer (71+)
15
+ * - Write operations require Super User (91+)
16
+ */
17
+ import { Command } from 'commander';
18
+ /**
19
+ * Type command
20
+ */
21
+ export declare const typeCommand: Command;
@@ -0,0 +1,469 @@
1
+ "use strict";
2
+ /**
3
+ * AraneaSDK CLI - Type Command
4
+ *
5
+ * UserTypeDefinitions management for AraneaDevice types
6
+ *
7
+ * Usage:
8
+ * aranea-sdk type list # List all types
9
+ * aranea-sdk type get <typeId> # Get specific type
10
+ * aranea-sdk type create <typeId> # Create new type
11
+ * aranea-sdk type update <typeId> # Update type
12
+ * aranea-sdk type delete <typeId> # Delete type
13
+ *
14
+ * Note:
15
+ * - Read operations require System Authority Layer (71+)
16
+ * - Write operations require Super User (91+)
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ var __importDefault = (this && this.__importDefault) || function (mod) {
52
+ return (mod && mod.__esModule) ? mod : { "default": mod };
53
+ };
54
+ Object.defineProperty(exports, "__esModule", { value: true });
55
+ exports.typeCommand = void 0;
56
+ const commander_1 = require("commander");
57
+ const chalk_1 = __importDefault(require("chalk"));
58
+ const auth_1 = require("./auth");
59
+ const config_1 = require("../config");
60
+ // Firebase project configuration
61
+ const FIREBASE_PROJECTS = {
62
+ production: 'mobesorder',
63
+ staging: 'mobesorder-staging',
64
+ };
65
+ const FIREBASE_REGION = 'asia-northeast1';
66
+ /**
67
+ * Call araneaTypeDefinitionHTTP API
68
+ */
69
+ async function callTypeDefinitionAPI(request, token, env) {
70
+ const projectId = FIREBASE_PROJECTS[env];
71
+ const url = `https://${FIREBASE_REGION}-${projectId}.cloudfunctions.net/araneaTypeDefinitionHTTP`;
72
+ const response = await fetch(url, {
73
+ method: 'POST',
74
+ headers: {
75
+ 'Content-Type': 'application/json',
76
+ Authorization: `Bearer ${token}`,
77
+ },
78
+ body: JSON.stringify(request),
79
+ });
80
+ const result = await response.json();
81
+ if (!response.ok || !result.ok) {
82
+ throw new Error(result.error || `HTTP ${response.status}`);
83
+ }
84
+ return result;
85
+ }
86
+ /**
87
+ * Format permission level with Cathedral Order name
88
+ */
89
+ function formatPermissionLevel(level) {
90
+ if (level >= 100)
91
+ return chalk_1.default.magenta(`${level} (Lacis)`);
92
+ if (level >= 91)
93
+ return chalk_1.default.red(`${level} (SU)`);
94
+ if (level >= 71)
95
+ return chalk_1.default.yellow(`${level} (System)`);
96
+ if (level >= 61)
97
+ return chalk_1.default.blue(`${level} (Tenant Primary)`);
98
+ if (level >= 41)
99
+ return chalk_1.default.cyan(`${level} (Management)`);
100
+ if (level >= 21)
101
+ return chalk_1.default.green(`${level} (Standard)`);
102
+ if (level >= 11)
103
+ return chalk_1.default.gray(`${level} (Guest+)`);
104
+ return chalk_1.default.gray(`${level} (Guest)`);
105
+ }
106
+ /**
107
+ * Load credentials for LacisOath
108
+ */
109
+ async function loadLacisCredentials() {
110
+ // For now, we'll prompt for these or read from config
111
+ // In production, these should come from stored credentials
112
+ const fs = await Promise.resolve().then(() => __importStar(require('fs')));
113
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
114
+ const os = await Promise.resolve().then(() => __importStar(require('os')));
115
+ const credFile = path.join(os.homedir(), '.aranea-sdk', 'lacis-credentials.json');
116
+ if (fs.existsSync(credFile)) {
117
+ try {
118
+ const data = JSON.parse(fs.readFileSync(credFile, 'utf8'));
119
+ if (data.lacisId && data.cic && data.tid) {
120
+ return data;
121
+ }
122
+ }
123
+ catch {
124
+ // Ignore parse errors
125
+ }
126
+ }
127
+ return null;
128
+ }
129
+ /**
130
+ * Prompt for LacisOath credentials
131
+ */
132
+ async function promptLacisCredentials() {
133
+ const readline = await Promise.resolve().then(() => __importStar(require('readline')));
134
+ const rl = readline.createInterface({
135
+ input: process.stdin,
136
+ output: process.stdout,
137
+ });
138
+ const question = (prompt) => new Promise((resolve) => rl.question(prompt, resolve));
139
+ console.log(chalk_1.default.cyan('\n=== LacisOath Authentication ===\n'));
140
+ console.log('Type definition management requires LacisOath credentials.');
141
+ console.log('(Save to ~/.aranea-sdk/lacis-credentials.json for future use)\n');
142
+ const lacisId = await question('LacisID (20 digits): ');
143
+ const cic = await question('CIC (6 digits): ');
144
+ const tid = await question('TID (20 chars): ');
145
+ rl.close();
146
+ return { lacisId: lacisId.trim(), cic: cic.trim(), tid: tid.trim() };
147
+ }
148
+ /**
149
+ * Type command
150
+ */
151
+ exports.typeCommand = new commander_1.Command('type')
152
+ .description('UserTypeDefinitions management for AraneaDevice types')
153
+ .addHelpText('after', `
154
+ Permission Requirements:
155
+ - list, get: System Authority Layer (71+)
156
+ - create, update, delete: Super User (91+)
157
+
158
+ LacisOath Authentication:
159
+ This command uses LacisOath (lacisId + cic + tid) for authentication.
160
+ Store credentials in ~/.aranea-sdk/lacis-credentials.json:
161
+ {
162
+ "lacisId": "17347487748391988274",
163
+ "cic": "123456",
164
+ "tid": "T9999999999999999999"
165
+ }
166
+
167
+ Examples:
168
+ aranea-sdk type list
169
+ aranea-sdk type list --type-domain araneaDevice
170
+ aranea-sdk type get aranea_ar-is22
171
+ aranea-sdk type create aranea_ar-is22 --display-name "AR-IS22 Sensor" --permission 21
172
+ aranea-sdk type update aranea_ar-is22 --permission 31
173
+ aranea-sdk type delete aranea_ar-is22 --force
174
+ `);
175
+ // type list
176
+ exports.typeCommand
177
+ .command('list')
178
+ .description('List all type definitions')
179
+ .option('--endpoint <env>', 'Target environment (production|staging)')
180
+ .option('--type-domain <domain>', 'Filter by TypeDomain (default: araneaDevice)')
181
+ .option('--json', 'Output as JSON')
182
+ .action(async (options) => {
183
+ try {
184
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
185
+ (0, config_1.checkStagingAvailability)(env, 'type list');
186
+ const token = await (0, auth_1.getValidToken)();
187
+ if (!token) {
188
+ console.error(chalk_1.default.red('\n✖ Not authenticated. Run "aranea-sdk auth login" first.'));
189
+ process.exit(1);
190
+ }
191
+ let credentials = await loadLacisCredentials();
192
+ if (!credentials) {
193
+ credentials = await promptLacisCredentials();
194
+ }
195
+ if (!options.json) {
196
+ console.log(chalk_1.default.cyan('\n=== UserTypeDefinitions List ===\n'));
197
+ console.log(`Environment: ${env === 'production' ? chalk_1.default.red('PRODUCTION') : chalk_1.default.yellow('staging')}`);
198
+ console.log('');
199
+ }
200
+ const typeDomainId = options.typeDomain || 'araneaDevice';
201
+ const result = await callTypeDefinitionAPI({
202
+ auth: credentials,
203
+ method: 'list',
204
+ params: { typeDomainId },
205
+ }, token, env);
206
+ if (options.json) {
207
+ console.log(JSON.stringify(result.definitions, null, 2));
208
+ }
209
+ else {
210
+ if (result.definitions.length === 0) {
211
+ console.log(chalk_1.default.yellow(`No types found for TypeDomain: ${typeDomainId}`));
212
+ return;
213
+ }
214
+ console.log(chalk_1.default.gray('─'.repeat(90)));
215
+ console.log(chalk_1.default.bold(`${'TypeId'.padEnd(25)} ${'DisplayName'.padEnd(25)} ${'Permission'.padEnd(20)} Status`));
216
+ console.log(chalk_1.default.gray('─'.repeat(90)));
217
+ for (const def of result.definitions) {
218
+ const typeId = def.typeId.padEnd(25);
219
+ const displayName = (def.displayName || '-').substring(0, 24).padEnd(25);
220
+ const permission = formatPermissionLevel(def.defaultCathedralOrder).padEnd(30);
221
+ const status = def.status === 'deprecated' ? chalk_1.default.red('deprecated') : chalk_1.default.green('active');
222
+ console.log(`${typeId} ${displayName} ${permission} ${status}`);
223
+ }
224
+ console.log(chalk_1.default.gray('─'.repeat(90)));
225
+ console.log(`\nTotal: ${result.count} type(s) in ${typeDomainId}`);
226
+ }
227
+ }
228
+ catch (error) {
229
+ console.error(chalk_1.default.red(`\n✖ Error: ${error.message}`));
230
+ process.exit(1);
231
+ }
232
+ });
233
+ // type get
234
+ exports.typeCommand
235
+ .command('get <typeId>')
236
+ .description('Get specific type definition')
237
+ .option('--endpoint <env>', 'Target environment (production|staging)')
238
+ .option('--type-domain <domain>', 'TypeDomain ID (default: araneaDevice)')
239
+ .option('--json', 'Output as JSON')
240
+ .action(async (typeId, options) => {
241
+ try {
242
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
243
+ (0, config_1.checkStagingAvailability)(env, 'type get');
244
+ const token = await (0, auth_1.getValidToken)();
245
+ if (!token) {
246
+ console.error(chalk_1.default.red('\n✖ Not authenticated. Run "aranea-sdk auth login" first.'));
247
+ process.exit(1);
248
+ }
249
+ let credentials = await loadLacisCredentials();
250
+ if (!credentials) {
251
+ credentials = await promptLacisCredentials();
252
+ }
253
+ const typeDomainId = options.typeDomain || 'araneaDevice';
254
+ const result = await callTypeDefinitionAPI({
255
+ auth: credentials,
256
+ method: 'get',
257
+ params: { typeDomainId, typeId },
258
+ }, token, env);
259
+ if (options.json) {
260
+ console.log(JSON.stringify(result.definition, null, 2));
261
+ }
262
+ else {
263
+ const def = result.definition;
264
+ console.log(chalk_1.default.cyan(`\n=== TypeDefinition: ${def.id} ===\n`));
265
+ console.log(` TypeDomain: ${def.typeDomainId}`);
266
+ console.log(` TypeId: ${def.typeId}`);
267
+ console.log(` DisplayName: ${def.displayName}`);
268
+ console.log(` Description: ${def.description || '-'}`);
269
+ console.log(` Permission: ${formatPermissionLevel(def.defaultCathedralOrder)}`);
270
+ console.log(` Status: ${def.status === 'deprecated' ? chalk_1.default.red('deprecated') : chalk_1.default.green('active')}`);
271
+ console.log(` Created: ${def.metadata.createdAt}`);
272
+ console.log(` Updated: ${def.metadata.updatedAt}`);
273
+ }
274
+ }
275
+ catch (error) {
276
+ console.error(chalk_1.default.red(`\n✖ Error: ${error.message}`));
277
+ process.exit(1);
278
+ }
279
+ });
280
+ // type create
281
+ exports.typeCommand
282
+ .command('create <typeId>')
283
+ .description('Create new type definition')
284
+ .option('--endpoint <env>', 'Target environment (production|staging)')
285
+ .option('--type-domain <domain>', 'TypeDomain ID (default: araneaDevice)')
286
+ .option('--display-name <name>', 'Display name for the type (required)')
287
+ .option('--description <desc>', 'Description of the type')
288
+ .option('--permission <level>', 'Default permission level (required)', parseInt)
289
+ .action(async (typeId, options) => {
290
+ try {
291
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
292
+ (0, config_1.checkStagingAvailability)(env, 'type create');
293
+ (0, config_1.warnIfProduction)(env, 'type create');
294
+ if (!options.displayName) {
295
+ console.error(chalk_1.default.red('\n✖ --display-name is required'));
296
+ process.exit(1);
297
+ }
298
+ if (options.permission === undefined || isNaN(options.permission)) {
299
+ console.error(chalk_1.default.red('\n✖ --permission is required (e.g., --permission 21)'));
300
+ process.exit(1);
301
+ }
302
+ const token = await (0, auth_1.getValidToken)();
303
+ if (!token) {
304
+ console.error(chalk_1.default.red('\n✖ Not authenticated. Run "aranea-sdk auth login" first.'));
305
+ process.exit(1);
306
+ }
307
+ let credentials = await loadLacisCredentials();
308
+ if (!credentials) {
309
+ credentials = await promptLacisCredentials();
310
+ }
311
+ const typeDomainId = options.typeDomain || 'araneaDevice';
312
+ console.log(chalk_1.default.cyan('\n=== Creating TypeDefinition ===\n'));
313
+ console.log(` Environment: ${env === 'production' ? chalk_1.default.red('PRODUCTION') : chalk_1.default.yellow('staging')}`);
314
+ console.log(` TypeDomain: ${typeDomainId}`);
315
+ console.log(` TypeId: ${typeId}`);
316
+ console.log(` DisplayName: ${options.displayName}`);
317
+ console.log(` Description: ${options.description || '-'}`);
318
+ console.log(` Permission: ${formatPermissionLevel(options.permission)}`);
319
+ console.log('');
320
+ const result = await callTypeDefinitionAPI({
321
+ auth: credentials,
322
+ method: 'create',
323
+ params: {
324
+ typeDomainId,
325
+ typeId,
326
+ displayName: options.displayName,
327
+ description: options.description,
328
+ defaultCathedralOrder: options.permission,
329
+ },
330
+ }, token, env);
331
+ console.log(chalk_1.default.green('✓ TypeDefinition created successfully!'));
332
+ console.log(` Document ID: ${result.id}`);
333
+ console.log('');
334
+ console.log(chalk_1.default.yellow('Note: To set typeDefaultPermissions separately, use:'));
335
+ console.log(` aranea-sdk permission set ${typeId} ${options.permission} --endpoint ${env}`);
336
+ }
337
+ catch (error) {
338
+ const message = error.message;
339
+ if (message.includes('91')) {
340
+ console.error(chalk_1.default.red('\n✖ Permission denied. Super User (91+) is required for create operations.'));
341
+ }
342
+ else {
343
+ console.error(chalk_1.default.red(`\n✖ Error: ${message}`));
344
+ }
345
+ process.exit(1);
346
+ }
347
+ });
348
+ // type update
349
+ exports.typeCommand
350
+ .command('update <typeId>')
351
+ .description('Update existing type definition')
352
+ .option('--endpoint <env>', 'Target environment (production|staging)')
353
+ .option('--type-domain <domain>', 'TypeDomain ID (default: araneaDevice)')
354
+ .option('--display-name <name>', 'New display name')
355
+ .option('--description <desc>', 'New description')
356
+ .option('--permission <level>', 'New default permission level', parseInt)
357
+ .option('--status <status>', 'Status (active|deprecated)')
358
+ .action(async (typeId, options) => {
359
+ try {
360
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
361
+ (0, config_1.checkStagingAvailability)(env, 'type update');
362
+ (0, config_1.warnIfProduction)(env, 'type update');
363
+ const token = await (0, auth_1.getValidToken)();
364
+ if (!token) {
365
+ console.error(chalk_1.default.red('\n✖ Not authenticated. Run "aranea-sdk auth login" first.'));
366
+ process.exit(1);
367
+ }
368
+ let credentials = await loadLacisCredentials();
369
+ if (!credentials) {
370
+ credentials = await promptLacisCredentials();
371
+ }
372
+ const typeDomainId = options.typeDomain || 'araneaDevice';
373
+ const params = {
374
+ typeDomainId,
375
+ typeId,
376
+ };
377
+ if (options.displayName)
378
+ params.displayName = options.displayName;
379
+ if (options.description)
380
+ params.description = options.description;
381
+ if (options.permission !== undefined)
382
+ params.defaultCathedralOrder = options.permission;
383
+ if (options.status === 'active' || options.status === 'deprecated') {
384
+ params.status = options.status;
385
+ }
386
+ console.log(chalk_1.default.cyan('\n=== Updating TypeDefinition ===\n'));
387
+ console.log(` Environment: ${env === 'production' ? chalk_1.default.red('PRODUCTION') : chalk_1.default.yellow('staging')}`);
388
+ console.log(` TypeDomain: ${typeDomainId}`);
389
+ console.log(` TypeId: ${typeId}`);
390
+ if (options.displayName)
391
+ console.log(` DisplayName: ${options.displayName}`);
392
+ if (options.permission !== undefined)
393
+ console.log(` Permission: ${formatPermissionLevel(options.permission)}`);
394
+ if (options.status)
395
+ console.log(` Status: ${options.status}`);
396
+ console.log('');
397
+ const result = await callTypeDefinitionAPI({
398
+ auth: credentials,
399
+ method: 'update',
400
+ params,
401
+ }, token, env);
402
+ console.log(chalk_1.default.green('✓ TypeDefinition updated successfully!'));
403
+ console.log(` Document ID: ${result.id}`);
404
+ }
405
+ catch (error) {
406
+ const message = error.message;
407
+ if (message.includes('91')) {
408
+ console.error(chalk_1.default.red('\n✖ Permission denied. Super User (91+) is required for update operations.'));
409
+ }
410
+ else {
411
+ console.error(chalk_1.default.red(`\n✖ Error: ${message}`));
412
+ }
413
+ process.exit(1);
414
+ }
415
+ });
416
+ // type delete
417
+ exports.typeCommand
418
+ .command('delete <typeId>')
419
+ .description('Delete type definition')
420
+ .option('--endpoint <env>', 'Target environment (production|staging)')
421
+ .option('--type-domain <domain>', 'TypeDomain ID (default: araneaDevice)')
422
+ .option('--force', 'Skip confirmation')
423
+ .action(async (typeId, options) => {
424
+ try {
425
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
426
+ (0, config_1.checkStagingAvailability)(env, 'type delete');
427
+ (0, config_1.warnIfProduction)(env, 'type delete');
428
+ const token = await (0, auth_1.getValidToken)();
429
+ if (!token) {
430
+ console.error(chalk_1.default.red('\n✖ Not authenticated. Run "aranea-sdk auth login" first.'));
431
+ process.exit(1);
432
+ }
433
+ let credentials = await loadLacisCredentials();
434
+ if (!credentials) {
435
+ credentials = await promptLacisCredentials();
436
+ }
437
+ const typeDomainId = options.typeDomain || 'araneaDevice';
438
+ console.log(chalk_1.default.cyan('\n=== Delete TypeDefinition ===\n'));
439
+ console.log(` Environment: ${env === 'production' ? chalk_1.default.red('PRODUCTION') : chalk_1.default.yellow('staging')}`);
440
+ console.log(` TypeDomain: ${typeDomainId}`);
441
+ console.log(` TypeId: ${typeId}`);
442
+ if (!options.force) {
443
+ console.log(chalk_1.default.yellow('\n⚠ This will permanently delete the type definition.'));
444
+ console.log(' Existing devices of this type will remain but may have issues.');
445
+ console.log('\nUse --force to confirm deletion.');
446
+ process.exit(1);
447
+ }
448
+ const result = await callTypeDefinitionAPI({
449
+ auth: credentials,
450
+ method: 'delete',
451
+ params: { typeDomainId, typeId },
452
+ }, token, env);
453
+ console.log(chalk_1.default.green('\n✓ TypeDefinition deleted.'));
454
+ console.log(` Document ID: ${result.id}`);
455
+ }
456
+ catch (error) {
457
+ const message = error.message;
458
+ if (message.includes('reserved')) {
459
+ console.error(chalk_1.default.red(`\n✖ Cannot delete: ${message}`));
460
+ }
461
+ else if (message.includes('91')) {
462
+ console.error(chalk_1.default.red('\n✖ Permission denied. Super User (91+) is required for delete operations.'));
463
+ }
464
+ else {
465
+ console.error(chalk_1.default.red(`\n✖ Error: ${message}`));
466
+ }
467
+ process.exit(1);
468
+ }
469
+ });
package/dist/index.js CHANGED
@@ -63,6 +63,8 @@ const auth_1 = require("./commands/auth");
63
63
  const backlog_1 = require("./commands/backlog");
64
64
  const registry_1 = require("./commands/registry");
65
65
  const control_1 = require("./commands/control");
66
+ const permission_1 = require("./commands/permission");
67
+ const type_1 = require("./commands/type");
66
68
  // package.json からバージョンを動的に取得
67
69
  const packageJsonPath = path.resolve(__dirname, '../package.json');
68
70
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
@@ -99,4 +101,8 @@ program.addCommand(registry_1.registryCommand);
99
101
  // control コマンド (v0.4.1) - Control型管理(安全機構付き)
100
102
  // @see doc/APPS/araneaSDK/headDesign/59_METATRON_CONTROL_SUGGESTION.md Section 8
101
103
  program.addCommand(control_1.controlCommand);
104
+ // permission コマンド (v0.5.4) - TypeDefaultPermissions管理
105
+ program.addCommand(permission_1.permissionCommand);
106
+ // type コマンド (v0.5.5) - UserTypeDefinitions管理
107
+ program.addCommand(type_1.typeCommand);
102
108
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aranea-sdk-cli",
3
- "version": "0.5.2",
3
+ "version": "0.5.5",
4
4
  "description": "AraneaSDK CLI - ESP32 IoTデバイス開発支援ツール",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",