create-astram-app 0.1.2 → 0.2.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/dist/add-frontend.js +107 -0
- package/dist/add-frontend.js.map +1 -0
- package/dist/index.js +132 -33
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/template/CLAUDE.md +51 -0
- package/template/README.md +43 -44
- package/template/_gitignore +6 -0
- package/template/frontend/FRONTEND.md +92 -0
- package/template/frontend/README.md +16 -0
- package/template/frontend/_env.example +6 -0
- package/template/frontend/_gitignore +9 -0
- package/template/frontend/eslint.config.js +71 -0
- package/template/frontend/index.html +13 -0
- package/template/frontend/package.json +52 -0
- package/template/frontend/public/astram-logo-full.png +0 -0
- package/template/frontend/public/astram-logo-white.png +0 -0
- package/template/frontend/public/favicon.png +0 -0
- package/template/frontend/src/App.jsx +167 -0
- package/template/frontend/src/auth/AuthContext.jsx +338 -0
- package/template/frontend/src/components/ConfirmDialog.jsx +92 -0
- package/template/frontend/src/components/EntityFormModal.jsx +154 -0
- package/template/frontend/src/components/EntityList.jsx +480 -0
- package/template/frontend/src/components/PageHeader.jsx +54 -0
- package/template/frontend/src/components/access/CollapsibleGroup.jsx +34 -0
- package/template/frontend/src/components/ui/alert-dialog.tsx +175 -0
- package/template/frontend/src/components/ui/alert.tsx +83 -0
- package/template/frontend/src/components/ui/avatar.tsx +51 -0
- package/template/frontend/src/components/ui/badge.tsx +56 -0
- package/template/frontend/src/components/ui/button.tsx +67 -0
- package/template/frontend/src/components/ui/card.tsx +92 -0
- package/template/frontend/src/components/ui/checkbox.tsx +30 -0
- package/template/frontend/src/components/ui/date-field.tsx +47 -0
- package/template/frontend/src/components/ui/dialog.tsx +214 -0
- package/template/frontend/src/components/ui/dropdown-menu.tsx +255 -0
- package/template/frontend/src/components/ui/input-otp.tsx +81 -0
- package/template/frontend/src/components/ui/input.tsx +21 -0
- package/template/frontend/src/components/ui/label.tsx +46 -0
- package/template/frontend/src/components/ui/searchable-select.tsx +459 -0
- package/template/frontend/src/components/ui/select.tsx +199 -0
- package/template/frontend/src/components/ui/separator.tsx +26 -0
- package/template/frontend/src/components/ui/sheet.tsx +139 -0
- package/template/frontend/src/components/ui/skeleton.tsx +13 -0
- package/template/frontend/src/components/ui/sonner.tsx +23 -0
- package/template/frontend/src/components/ui/table.tsx +181 -0
- package/template/frontend/src/components/ui/tooltip.tsx +59 -0
- package/template/frontend/src/config/branding.js +80 -0
- package/template/frontend/src/hooks/useMobile.tsx +21 -0
- package/template/frontend/src/index.css +265 -0
- package/template/frontend/src/lib/utils.js +7 -0
- package/template/frontend/src/main.jsx +27 -0
- package/template/frontend/src/pages/Dashboard.jsx +127 -0
- package/template/frontend/src/pages/ForgotPassword.jsx +104 -0
- package/template/frontend/src/pages/Login.jsx +393 -0
- package/template/frontend/src/pages/ResetPassword.jsx +159 -0
- package/template/frontend/src/pages/access/AccessForm.jsx +416 -0
- package/template/frontend/src/pages/access/AccessPage.jsx +282 -0
- package/template/frontend/src/pages/access/RoleActionsMenu.jsx +42 -0
- package/template/frontend/src/pages/account/AccountLayout.jsx +229 -0
- package/template/frontend/src/pages/account/ChangePasswordPage.jsx +235 -0
- package/template/frontend/src/pages/account/ProfilePage.jsx +122 -0
- package/template/frontend/src/pages/account/ReenrollPage.jsx +98 -0
- package/template/frontend/src/pages/account/TwoFactorPage.jsx +833 -0
- package/template/frontend/src/pages/audit/AuditPage.jsx +268 -0
- package/template/frontend/src/pages/companies/CompaniesPage.jsx +232 -0
- package/template/frontend/src/pages/companies/CompanyForm.jsx +127 -0
- package/template/frontend/src/pages/roles/RoleForm.jsx +99 -0
- package/template/frontend/src/pages/roles/RolesPage.jsx +207 -0
- package/template/frontend/src/pages/users/AssignmentsEditor.jsx +193 -0
- package/template/frontend/src/pages/users/MembershipCard.jsx +303 -0
- package/template/frontend/src/pages/users/PostingRow.jsx +264 -0
- package/template/frontend/src/pages/users/UserForm.jsx +167 -0
- package/template/frontend/src/pages/users/UsersPage.jsx +232 -0
- package/template/frontend/src/platform/httpClient.js +125 -0
- package/template/frontend/src/platform/returnPathStore.js +43 -0
- package/template/frontend/src/platform/sessionStore.js +29 -0
- package/template/frontend/src/platform/shieldTransport.js +172 -0
- package/template/frontend/src/platform/shieldTransport.test.mjs +245 -0
- package/template/frontend/src/shell/AppShell.jsx +237 -0
- package/template/frontend/src/shell/Sidebar.jsx +257 -0
- package/template/frontend/src/shell/nav.js +90 -0
- package/template/frontend/src/theme/ThemeProvider.jsx +14 -0
- package/template/frontend/src/theme/ThemeToggle.jsx +44 -0
- package/template/frontend/tsconfig.json +22 -0
- package/template/frontend/vite.config.js +30 -0
- package/template/server/_env.example +45 -0
- package/template/server/eslint.config.js +95 -0
- package/template/server/package.json +49 -0
- package/template/server/scripts/dev.mjs +51 -0
- package/template/server/scripts/sync-astram-guide.mjs +63 -0
- package/template/_env.example +0 -33
- package/template/package.json +0 -37
- /package/template/{src → server/src}/app.module.ts +0 -0
- /package/template/{src → server/src}/features/_gitkeep +0 -0
- /package/template/{src → server/src}/health/demo.controller.ts +0 -0
- /package/template/{src → server/src}/health/health.controller.ts +0 -0
- /package/template/{src → server/src}/main.ts +0 -0
- /package/template/{test → server/test}/enforcement.e2e.spec.ts +0 -0
- /package/template/{tsconfig.build.json → server/tsconfig.build.json} +0 -0
- /package/template/{tsconfig.json → server/tsconfig.json} +0 -0
- /package/template/{vitest.config.ts → server/vitest.config.ts} +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev runner — TypeScript watch + auto-restart, with CORRECT NestJS decorator
|
|
3
|
+
* metadata.
|
|
4
|
+
*
|
|
5
|
+
* WHY not `tsx watch`: tsx uses esbuild, which does NOT emit `emitDecoratorMetadata`.
|
|
6
|
+
* NestJS constructor injection (`constructor(private x: Service)`) depends on that
|
|
7
|
+
* metadata, so under tsx a controller's injected service is `undefined` at runtime
|
|
8
|
+
* (a silent 500 on the first call). `tsc` DOES emit the metadata — so this runner
|
|
9
|
+
* compiles with `tsc --watch` (→ dist/) and runs `node --watch dist/main.js`, giving
|
|
10
|
+
* hot-reload AND correct DI. Same compiler as the production build, no extra deps.
|
|
11
|
+
*
|
|
12
|
+
* `.env` is loaded by the node child via --env-file-if-exists.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { spawn } from 'node:child_process';
|
|
16
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
17
|
+
|
|
18
|
+
mkdirSync('dist', { recursive: true });
|
|
19
|
+
|
|
20
|
+
// 1) tsc in watch mode → dist/ (emits decorator metadata; the whole point).
|
|
21
|
+
const tsc = spawn(
|
|
22
|
+
process.execPath,
|
|
23
|
+
[new URL('../node_modules/typescript/bin/tsc', import.meta.url).pathname, '-w', '-p', 'tsconfig.build.json', '--preserveWatchOutput'],
|
|
24
|
+
{ stdio: 'inherit' },
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// 2) Wait for the first emit, then run node --watch on the built entry.
|
|
28
|
+
let started = false;
|
|
29
|
+
const startNode = () => {
|
|
30
|
+
if (started) return;
|
|
31
|
+
if (!existsSync('dist/main.js')) {
|
|
32
|
+
setTimeout(startNode, 300);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
started = true;
|
|
36
|
+
const node = spawn(
|
|
37
|
+
process.execPath,
|
|
38
|
+
['--env-file-if-exists=.env', '--watch', 'dist/main.js'],
|
|
39
|
+
{ stdio: 'inherit' },
|
|
40
|
+
);
|
|
41
|
+
node.on('exit', (code) => {
|
|
42
|
+
tsc.kill();
|
|
43
|
+
process.exit(code ?? 0);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
setTimeout(startNode, 800);
|
|
47
|
+
|
|
48
|
+
process.on('SIGINT', () => {
|
|
49
|
+
tsc.kill();
|
|
50
|
+
process.exit(0);
|
|
51
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sync-astram-guide — copy the framework's guide docs into `.claude/rules/` so
|
|
3
|
+
* Claude Code reads the CURRENT framework rules.
|
|
4
|
+
*
|
|
5
|
+
* WHY (ADR-0025, the two-layer AI guide): the framework ships its hard rules +
|
|
6
|
+
* capabilities in the installed `@astram/guide` package (in node_modules). Claude
|
|
7
|
+
* Code reliably reads rules from `.claude/rules/` (a documented, symlink-aware
|
|
8
|
+
* location) — but NOT from an @import that points into node_modules. So this script
|
|
9
|
+
* bridges the two: it copies the framework docs from the installed package into the
|
|
10
|
+
* app-root `.claude/rules/`, where the app's CLAUDE.md references them.
|
|
11
|
+
*
|
|
12
|
+
* It runs on `npm install` AND `npm update` (wired as a postinstall in
|
|
13
|
+
* server/package.json), so a FRAMEWORK UPGRADE automatically refreshes the rules —
|
|
14
|
+
* the whole point of the upgrade-safe design. The copied files are GITIGNORED (they
|
|
15
|
+
* are a generated mirror of the framework's version); the developer-owned
|
|
16
|
+
* `.astram/guide/` layer is separate, git-tracked, and NEVER touched by this script.
|
|
17
|
+
*
|
|
18
|
+
* The app root is the monorepo root (one level up from server/), because CLAUDE.md +
|
|
19
|
+
* .claude/ live at the app root and Claude walks UP the tree from wherever you work.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { cpSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
23
|
+
import { dirname, join, resolve } from 'node:path';
|
|
24
|
+
import { fileURLToPath } from 'node:url';
|
|
25
|
+
import { createRequire } from 'node:module';
|
|
26
|
+
|
|
27
|
+
const require = createRequire(import.meta.url);
|
|
28
|
+
const here = dirname(fileURLToPath(import.meta.url)); // server/scripts
|
|
29
|
+
const appRoot = resolve(here, '..', '..'); // monorepo root
|
|
30
|
+
const rulesDir = join(appRoot, '.claude', 'rules');
|
|
31
|
+
|
|
32
|
+
function main() {
|
|
33
|
+
let guide;
|
|
34
|
+
try {
|
|
35
|
+
guide = require('@astram/guide');
|
|
36
|
+
} catch {
|
|
37
|
+
// The framework guide package isn't installed (e.g. a partial install). Skip
|
|
38
|
+
// silently — this is a best-effort refresh, never a hard failure of the install.
|
|
39
|
+
process.stdout.write('[sync-astram-guide] @astram/guide not found — skipped.\n');
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
mkdirSync(rulesDir, { recursive: true });
|
|
44
|
+
// Copy the framework docs into .claude/rules/ (overwrite — they are the framework's
|
|
45
|
+
// to own; on upgrade the newer versions replace the older ones cleanly).
|
|
46
|
+
cpSync(guide.FRAMEWORK_RULES_PATH, join(rulesDir, 'astram-framework-rules.md'));
|
|
47
|
+
cpSync(guide.CAPABILITIES_PATH, join(rulesDir, 'astram-framework-capabilities.md'));
|
|
48
|
+
|
|
49
|
+
// Stamp the synced version so a human/AI can see which framework version's rules
|
|
50
|
+
// are present (and notice when an upgrade changed them).
|
|
51
|
+
writeFileSync(
|
|
52
|
+
join(rulesDir, '.astram-guide-version'),
|
|
53
|
+
`${guide.version}\n`,
|
|
54
|
+
'utf8',
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
process.stdout.write(
|
|
58
|
+
`[sync-astram-guide] framework rules synced (v${guide.version}) → .claude/rules/\n`,
|
|
59
|
+
);
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
process.exitCode = main();
|
package/template/_env.example
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# __APP_NAME__ — environment configuration (references only, no secrets).
|
|
2
|
-
#
|
|
3
|
-
# Every value below has a safe default, so the app boots with NO .env file at all.
|
|
4
|
-
# Copy this file to `.env` and override only what you need. `.env` is gitignored.
|
|
5
|
-
#
|
|
6
|
-
# These are read by `loadAppConfig()` from the installed @astram/guard framework.
|
|
7
|
-
|
|
8
|
-
# HTTP port the app listens on (default: 3000).
|
|
9
|
-
PORT=3000
|
|
10
|
-
|
|
11
|
-
# Runtime environment: development | production | test (default: development).
|
|
12
|
-
NODE_ENV=development
|
|
13
|
-
|
|
14
|
-
# --- ADR-0018 connection-pool budget (all optional; framework defaults apply) ---
|
|
15
|
-
# Uncomment + tune only if your deployment needs to.
|
|
16
|
-
# SHIELD_POOL_WORKERS=1
|
|
17
|
-
# SHIELD_DB_MAX_CONNECTIONS=50
|
|
18
|
-
# SHIELD_POOL_HEADROOM=5
|
|
19
|
-
# SHIELD_POOL_MAX_CORE=10
|
|
20
|
-
# SHIELD_POOL_MAX_APP_CRUD=10
|
|
21
|
-
# SHIELD_POOL_MAX_SCHEMA_SVC=5
|
|
22
|
-
|
|
23
|
-
# --- OPTIONAL: real authentication (only if you set ShieldModule.forRoot({ auth: true })) ---
|
|
24
|
-
# Auth needs a live MariaDB + Redis and a refresh-token HMAC key. These are
|
|
25
|
-
# REQUIRED once auth is enabled (the app fails closed without the HMAC key) — but
|
|
26
|
-
# irrelevant (unread) while auth is off. Point them at your MariaDB/Redis.
|
|
27
|
-
# SHIELD_DB_HOST=127.0.0.1
|
|
28
|
-
# SHIELD_DB_PORT=3306
|
|
29
|
-
# SHIELD_DB_USER=shield_core
|
|
30
|
-
# SHIELD_DB_PASSWORD=change-me
|
|
31
|
-
# SHIELD_DB_DATABASE=shield_identity
|
|
32
|
-
# SHIELD_REDIS_URL=redis://127.0.0.1:6379
|
|
33
|
-
# SHIELD_REFRESH_HMAC_KEY=change-me-to-a-long-random-secret # REQUIRED when auth is on
|
package/template/package.json
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "__APP_NAME__",
|
|
3
|
-
"version": "0.0.0",
|
|
4
|
-
"private": true,
|
|
5
|
-
"description": "An Astram consumer app. Depends on the published, immutable framework (@astram/core, @astram/guard, @astram/sdk) and declares enforcement via ShieldModule.forRoot(). Features go in src/features/.",
|
|
6
|
-
"type": "commonjs",
|
|
7
|
-
"main": "dist/main.js",
|
|
8
|
-
"scripts": {
|
|
9
|
-
"prebuild": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
10
|
-
"build": "tsc -p tsconfig.build.json",
|
|
11
|
-
"start": "node dist/main.js",
|
|
12
|
-
"dev": "tsx watch src/main.ts",
|
|
13
|
-
"test": "vitest run",
|
|
14
|
-
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\""
|
|
15
|
-
},
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"@astram/core": "^0.1.0",
|
|
18
|
-
"@astram/guard": "^0.1.1",
|
|
19
|
-
"@astram/sdk": "^0.1.0",
|
|
20
|
-
"@nestjs/common": "^11.0.0",
|
|
21
|
-
"@nestjs/core": "^11.0.0",
|
|
22
|
-
"@nestjs/platform-express": "^11.0.0",
|
|
23
|
-
"reflect-metadata": "^0.2.2",
|
|
24
|
-
"rxjs": "^7.8.1"
|
|
25
|
-
},
|
|
26
|
-
"devDependencies": {
|
|
27
|
-
"@nestjs/testing": "^11.0.0",
|
|
28
|
-
"@types/express": "^5.0.0",
|
|
29
|
-
"@types/node": "^22.0.0",
|
|
30
|
-
"@types/supertest": "^6.0.2",
|
|
31
|
-
"supertest": "^7.0.0",
|
|
32
|
-
"tsx": "^4.19.2",
|
|
33
|
-
"typescript": "^5.7.0",
|
|
34
|
-
"unplugin-swc": "^1.5.1",
|
|
35
|
-
"vitest": "^2.1.8"
|
|
36
|
-
}
|
|
37
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|