@nlabs/metropolisjs 0.3.4 → 0.3.6
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/.github/copilot-instructions.md +55 -167
- package/AGENTS.md +52 -10
- package/README.md +52 -2
- package/docs/ACTIONS.md +84 -22
- package/docs/assets/metropolisjs-logo.png +0 -0
- package/examples/factory-pattern-usage.ts +15 -10
- package/lex.config.mjs +5 -8
- package/lib/actions/appActions/appActions.d.ts.map +1 -1
- package/lib/actions/appActions/appActions.js +77 -6
- package/lib/actions/awsRumActions/awsRumActions.d.ts +34 -0
- package/lib/actions/awsRumActions/awsRumActions.d.ts.map +1 -0
- package/lib/actions/awsRumActions/awsRumActions.js +183 -0
- package/lib/actions/crmActions/crmActions.d.ts +87 -0
- package/lib/actions/crmActions/crmActions.d.ts.map +1 -0
- package/lib/actions/crmActions/crmActions.js +338 -0
- package/lib/actions/index.d.ts +3 -0
- package/lib/actions/index.d.ts.map +1 -1
- package/lib/actions/index.js +4 -1
- package/lib/actions/restActions/restActions.d.ts +19 -0
- package/lib/actions/restActions/restActions.d.ts.map +1 -0
- package/lib/actions/restActions/restActions.js +40 -0
- package/lib/actions/userActions/userActions.d.ts +12 -0
- package/lib/actions/userActions/userActions.d.ts.map +1 -1
- package/lib/actions/userActions/userActions.js +20 -4
- package/lib/adapters/appAdapter/appAdapter.d.ts +2 -2
- package/lib/adapters/appAdapter/appAdapter.d.ts.map +1 -1
- package/lib/adapters/arangoAdapter/arangoAdapter.d.ts +2 -2
- package/lib/adapters/arangoAdapter/arangoAdapter.d.ts.map +1 -1
- package/lib/adapters/contentAdapter/contentAdapter.d.ts +2 -2
- package/lib/adapters/contentAdapter/contentAdapter.d.ts.map +1 -1
- package/lib/adapters/conversationAdapter/conversationAdapter.d.ts +2 -2
- package/lib/adapters/conversationAdapter/conversationAdapter.d.ts.map +1 -1
- package/lib/adapters/eventAdapter/eventAdapter.d.ts +2 -2
- package/lib/adapters/eventAdapter/eventAdapter.d.ts.map +1 -1
- package/lib/adapters/fileAdapter/fileAdapter.d.ts +2 -2
- package/lib/adapters/fileAdapter/fileAdapter.d.ts.map +1 -1
- package/lib/adapters/groupAdapter/groupAdapter.d.ts +2 -2
- package/lib/adapters/groupAdapter/groupAdapter.d.ts.map +1 -1
- package/lib/adapters/imageAdapter/imageAdapter.d.ts +2 -2
- package/lib/adapters/imageAdapter/imageAdapter.d.ts.map +1 -1
- package/lib/adapters/locationAdapter/locationAdapter.d.ts +2 -2
- package/lib/adapters/locationAdapter/locationAdapter.d.ts.map +1 -1
- package/lib/adapters/messageAdapter/messageAdapter.d.ts +2 -2
- package/lib/adapters/messageAdapter/messageAdapter.d.ts.map +1 -1
- package/lib/adapters/permissionAdapter/permissionAdapter.d.ts +2 -2
- package/lib/adapters/permissionAdapter/permissionAdapter.d.ts.map +1 -1
- package/lib/adapters/personaAdapter/personaAdapter.d.ts +2 -2
- package/lib/adapters/personaAdapter/personaAdapter.d.ts.map +1 -1
- package/lib/adapters/postAdapter/postAdapter.d.ts +2 -2
- package/lib/adapters/postAdapter/postAdapter.d.ts.map +1 -1
- package/lib/adapters/reactionAdapter/reactionAdapter.d.ts +2 -2
- package/lib/adapters/reactionAdapter/reactionAdapter.d.ts.map +1 -1
- package/lib/adapters/reaktorAdapter/reaktorAdapter.d.ts +2 -2
- package/lib/adapters/reaktorAdapter/reaktorAdapter.d.ts.map +1 -1
- package/lib/adapters/sessionAdapter/sessionAdapter.d.ts +2 -2
- package/lib/adapters/sessionAdapter/sessionAdapter.d.ts.map +1 -1
- package/lib/adapters/tagAdapter/tagAdapter.d.ts +2 -2
- package/lib/adapters/tagAdapter/tagAdapter.d.ts.map +1 -1
- package/lib/adapters/translationAdapter/translationAdapter.d.ts +2 -2
- package/lib/adapters/translationAdapter/translationAdapter.d.ts.map +1 -1
- package/lib/adapters/userAdapter/userAdapter.d.ts +2 -2
- package/lib/adapters/userAdapter/userAdapter.d.ts.map +1 -1
- package/lib/adapters/videoAdapter/videoAdapter.d.ts +2 -2
- package/lib/adapters/videoAdapter/videoAdapter.d.ts.map +1 -1
- package/lib/config/index.d.ts +9 -0
- package/lib/config/index.d.ts.map +1 -1
- package/lib/config/index.js +1 -1
- package/lib/constants/Collections.d.ts +16 -0
- package/lib/constants/Collections.d.ts.map +1 -1
- package/lib/constants/Collections.js +17 -1
- package/lib/index.d.ts +6 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +6 -3
- package/lib/stores/appStore.d.ts +10 -0
- package/lib/stores/appStore.d.ts.map +1 -1
- package/lib/stores/appStore.js +12 -2
- package/lib/tests/actionTestScenarios.d.ts +20 -0
- package/lib/tests/actionTestScenarios.d.ts.map +1 -0
- package/lib/tests/actionTestScenarios.js +851 -0
- package/lib/tests/testGraphQLServer.d.ts.map +1 -0
- package/lib/tests/testGraphQLServer.js +197 -0
- package/lib/tests/testGraphQLServerSimple.d.ts.map +1 -0
- package/lib/tests/testGraphQLServerSimple.js +52 -0
- package/lib/types/crm.types.d.ts +100 -0
- package/lib/types/crm.types.d.ts.map +1 -0
- package/lib/types/crm.types.js +6 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +2 -1
- package/lib/utils/MetropolisProvider.d.ts +1 -1
- package/lib/utils/MetropolisProvider.d.ts.map +1 -1
- package/lib/utils/actionFactory.d.ts +7 -4
- package/lib/utils/actionFactory.d.ts.map +1 -1
- package/lib/utils/actionFactory.js +13 -1
- package/lib/utils/api.d.ts +15 -2
- package/lib/utils/api.d.ts.map +1 -1
- package/lib/utils/api.js +120 -32
- package/lib/utils/baseActionFactory.d.ts +2 -2
- package/lib/utils/dateUtils.d.ts +1 -1
- package/lib/utils/dateUtils.d.ts.map +1 -1
- package/lib/utils/index.d.ts +2 -2
- package/lib/utils/index.d.ts.map +1 -1
- package/lib/utils/index.js +3 -3
- package/lib/utils/location.d.ts +1 -1
- package/lib/utils/location.d.ts.map +1 -1
- package/lib/utils/requestCache.d.ts +1 -1
- package/lib/utils/requestCache.d.ts.map +1 -1
- package/lib/utils/useMetropolis.d.ts +3 -0
- package/lib/utils/useMetropolis.d.ts.map +1 -1
- package/lib/utils/useMetropolis.js +39 -6
- package/lib/utils/validatorFactory.d.ts +1 -1
- package/lib/utils/validatorFactory.d.ts.map +1 -1
- package/package.json +12 -12
- package/tsconfig.lint.json +2 -2
- package/tsconfig.test.json +3 -2
- package/jest.config.mjs +0 -28
- package/lib/__tests__/e2e/helpers/testGraphQLServer.d.ts.map +0 -1
- package/lib/__tests__/e2e/helpers/testGraphQLServer.js +0 -197
- package/lib/__tests__/e2e/helpers/testGraphQLServerSimple.d.ts.map +0 -1
- package/lib/__tests__/e2e/helpers/testGraphQLServerSimple.js +0 -52
- /package/lib/{__tests__/e2e/helpers → tests}/testGraphQLServer.d.ts +0 -0
- /package/lib/{__tests__/e2e/helpers → tests}/testGraphQLServerSimple.d.ts +0 -0
|
@@ -1,167 +1,55 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
##
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// ...
|
|
57
|
-
});
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Development Workflow
|
|
61
|
-
|
|
62
|
-
### Build Commands
|
|
63
|
-
- `npm run build` - Compile TypeScript to `lib/` using @nlabs/lex
|
|
64
|
-
- `npm run dev` - Development build with watch mode
|
|
65
|
-
- `npm run test` - Run Jest tests with @nlabs/lex configuration
|
|
66
|
-
- `npm run lint` - ESLint with auto-fix using @nlabs/lex
|
|
67
|
-
|
|
68
|
-
### Testing Setup
|
|
69
|
-
- Uses Jest with jsdom environment
|
|
70
|
-
- Tests located in `__tests__/` directories alongside source
|
|
71
|
-
- Mock setup in `__mocks__/` for external dependencies
|
|
72
|
-
|
|
73
|
-
### TypeScript Configuration
|
|
74
|
-
- Strict mode disabled (`"strict": false`)
|
|
75
|
-
- ESNext modules with bundler resolution
|
|
76
|
-
- Declaration files emitted to `lib/` directory
|
|
77
|
-
|
|
78
|
-
## Coding Conventions
|
|
79
|
-
|
|
80
|
-
### Comments
|
|
81
|
-
- Do not write comments in code except for TODOs, copyrights, and lint disables
|
|
82
|
-
- Variables and code should be self-explanatory with clear, descriptive names
|
|
83
|
-
- Use meaningful variable names that explain their purpose
|
|
84
|
-
- Structure code to be readable without additional comments
|
|
85
|
-
|
|
86
|
-
## Integration Points
|
|
87
|
-
|
|
88
|
-
### External Dependencies
|
|
89
|
-
- **@nlabs/arkhamjs**: State management framework
|
|
90
|
-
- **@nlabs/arkhamjs-utils-react**: React hooks for ArkhamJS
|
|
91
|
-
- **i18next**: Internationalization
|
|
92
|
-
- **sockette**: WebSocket client
|
|
93
|
-
- **zod**: Schema validation
|
|
94
|
-
|
|
95
|
-
### Real-time Features
|
|
96
|
-
- WebSocket connections via `websocketStore`
|
|
97
|
-
- Server-Sent Events (SSE) for notifications
|
|
98
|
-
- Automatic reconnection and state synchronization
|
|
99
|
-
|
|
100
|
-
### Authentication Flow
|
|
101
|
-
- Session management through `user.session` state
|
|
102
|
-
- Token refresh via `refreshSession()` API calls
|
|
103
|
-
- Environment-specific auth checks via config
|
|
104
|
-
|
|
105
|
-
## Code Organization
|
|
106
|
-
|
|
107
|
-
### Directory Structure
|
|
108
|
-
```
|
|
109
|
-
src/
|
|
110
|
-
├── actions/ # Factory-based action creators
|
|
111
|
-
├── adapters/ # Data parsing and validation
|
|
112
|
-
├── stores/ # ArkhamJS store definitions
|
|
113
|
-
├── config/ # Environment configuration
|
|
114
|
-
├── utils/ # Shared utilities (API, i18n, etc.)
|
|
115
|
-
└── constants/ # Application constants
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### File Naming
|
|
119
|
-
- Actions: `userActions.ts`, `postActions.ts`
|
|
120
|
-
- Stores: `userStore.ts`, `postStore.ts`
|
|
121
|
-
- Adapters: `userAdapter.ts`, `postAdapter.ts`
|
|
122
|
-
- Tests: `userActions.test.ts` alongside implementation
|
|
123
|
-
|
|
124
|
-
## Common Patterns
|
|
125
|
-
|
|
126
|
-
### Error Handling
|
|
127
|
-
```typescript
|
|
128
|
-
try {
|
|
129
|
-
const result = await userActions.signIn({username, password});
|
|
130
|
-
// Handle success
|
|
131
|
-
} catch (error) {
|
|
132
|
-
// Error dispatched to store with *_ERROR constant
|
|
133
|
-
console.error('Sign in failed:', error);
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### State Access
|
|
138
|
-
```typescript
|
|
139
|
-
import {useFlux} from '@nlabs/arkhamjs-utils-react';
|
|
140
|
-
|
|
141
|
-
const MyComponent = () => {
|
|
142
|
-
const flux = useFlux();
|
|
143
|
-
const user = flux.getState('user.item', {});
|
|
144
|
-
// ...
|
|
145
|
-
};
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Custom Adapters
|
|
149
|
-
```typescript
|
|
150
|
-
const customUserAdapter = (input: unknown) => {
|
|
151
|
-
const user = parseUser(input); // Use default parser first
|
|
152
|
-
// Add custom business logic
|
|
153
|
-
return {...user, computedField: 'value'};
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const userActions = createUserActions(flux, {
|
|
157
|
-
userAdapter: customUserAdapter
|
|
158
|
-
});
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
## Key Files to Reference
|
|
162
|
-
- `src/index.tsx` - Main library exports and Metropolis component
|
|
163
|
-
- `src/stores/index.ts` - All store exports
|
|
164
|
-
- `src/actions/index.ts` - All action exports
|
|
165
|
-
- `src/adapters/index.ts` - All adapter exports
|
|
166
|
-
- `src/utils/api.ts` - GraphQL API utilities
|
|
167
|
-
- `factoryPatternGuide.md` - Detailed factory pattern documentation
|
|
1
|
+
# AI Coding Assistant Instructions
|
|
2
|
+
|
|
3
|
+
## Shared NLabs Stack
|
|
4
|
+
- Use Lex (`@nlabs/lex`) for CLI workflows, building, compiling, deploying, and testing projects.
|
|
5
|
+
- Use Vitest for unit and integration tests.
|
|
6
|
+
- Use Playwright for end-to-end tests.
|
|
7
|
+
- Use GothamJS (`@nlabs/gothamjs`) for the presentation layer. Obtain components, views, routing, Tailwind setup, and default styles from GothamJS before creating custom project-level components.
|
|
8
|
+
- Use React v19 for frontend work.
|
|
9
|
+
- Use Tailwind v4 for CSS styles.
|
|
10
|
+
- Use MetropolisJS (`@nlabs/metropolisjs`) as the starting point for all frontend API integration. Create custom data types, actions, queries, or mutations only after MetropolisJS has been exhausted.
|
|
11
|
+
- Use Rip-Hunter to access API endpoints.
|
|
12
|
+
- Use `fetch` through Rip-Hunter rather than direct project-level `fetch` calls.
|
|
13
|
+
- Use ArkhamJS (`@nlabs/arkhamjs`) as the frontend data store. Store data, including session-storage-backed data, through Flux actions and event listeners.
|
|
14
|
+
- Prefer listening for Flux events over chaining `.then(...)` to Flux action promises.
|
|
15
|
+
- Flux actions update the data store before dispatching their events.
|
|
16
|
+
- Multiple listeners may listen for the same Flux action event.
|
|
17
|
+
- Read persistent data from the data store, and read event-specific data directly from the Flux action event when appropriate.
|
|
18
|
+
- Send all data as JSON.
|
|
19
|
+
- Use Reaktor (`@nlabs/reaktor`) for actions that interact with the ArangoDB database.
|
|
20
|
+
|
|
21
|
+
## Database
|
|
22
|
+
- All projects use the ArangoDB instance at `https://db.reaktor.io:8529`.
|
|
23
|
+
- ArangoDB is a document NoSQL database with SQL-style query and graph database features.
|
|
24
|
+
- When adding or deleting documents, check whether associated graph edges also need to be added or deleted.
|
|
25
|
+
|
|
26
|
+
## Project Structure
|
|
27
|
+
- Web apps should contain at least one microsite.
|
|
28
|
+
- Web apps should include a `src/ui` folder.
|
|
29
|
+
- Web apps with a backend should include a `src/api` folder or microsite.
|
|
30
|
+
- Library projects may use a root source folder without `src/ui` or `src/api`.
|
|
31
|
+
- Shared utility/helper functions should live in a shared file when used in more than one place.
|
|
32
|
+
- Keep one component per file.
|
|
33
|
+
- Each component should have a sibling test file named `MyComponent.test.ts` or `MyComponent.test.tsx`.
|
|
34
|
+
- Group components by component folder, for example `src/ui/components/MyComponent/MyComponent.tsx`.
|
|
35
|
+
|
|
36
|
+
## Package Scripts
|
|
37
|
+
- All projects should have at least `start`, `test`, and `update` scripts.
|
|
38
|
+
- If a project includes both `api` and `ui` workspaces, use `concurrently` in `start`:
|
|
39
|
+
`"start": "concurrently \"npm run start -w api\" \"npm run start -w ui\""`
|
|
40
|
+
- Use this workspace test script:
|
|
41
|
+
`"test": "npm run test --workspaces --ignore-scripts"`
|
|
42
|
+
- Use this workspace update script:
|
|
43
|
+
`"update": "npm run update --workspaces"`
|
|
44
|
+
|
|
45
|
+
## Testing
|
|
46
|
+
- Maintain at least 90% unit test coverage.
|
|
47
|
+
- Components that require other components should have integration tests.
|
|
48
|
+
- Provide at least one Playwright e2e test for each happy path.
|
|
49
|
+
|
|
50
|
+
## Code Style
|
|
51
|
+
- Use arrow functions for functions.
|
|
52
|
+
- Correctly type all variables, props, and arguments unless TypeScript inference already provides the correct type.
|
|
53
|
+
- Sort props and object keys alphabetically.
|
|
54
|
+
- Check and fix all ESLint errors and warnings.
|
|
55
|
+
- Use `eslint-config-styleguide` for linting rules.
|
package/AGENTS.md
CHANGED
|
@@ -1,13 +1,55 @@
|
|
|
1
|
-
#
|
|
1
|
+
# AI Coding Assistant Instructions
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
-
|
|
5
|
-
-
|
|
3
|
+
## Shared NLabs Stack
|
|
4
|
+
- Use Lex (`@nlabs/lex`) for CLI workflows, building, compiling, deploying, and testing projects.
|
|
5
|
+
- Use Vitest for unit and integration tests.
|
|
6
|
+
- Use Playwright for end-to-end tests.
|
|
7
|
+
- Use GothamJS (`@nlabs/gothamjs`) for the presentation layer. Obtain components, views, routing, Tailwind setup, and default styles from GothamJS before creating custom project-level components.
|
|
8
|
+
- Use React v19 for frontend work.
|
|
9
|
+
- Use Tailwind v4 for CSS styles.
|
|
10
|
+
- Use MetropolisJS (`@nlabs/metropolisjs`) as the starting point for all frontend API integration. Create custom data types, actions, queries, or mutations only after MetropolisJS has been exhausted.
|
|
11
|
+
- Use Rip-Hunter to access API endpoints.
|
|
12
|
+
- Use `fetch` through Rip-Hunter rather than direct project-level `fetch` calls.
|
|
13
|
+
- Use ArkhamJS (`@nlabs/arkhamjs`) as the frontend data store. Store data, including session-storage-backed data, through Flux actions and event listeners.
|
|
14
|
+
- Prefer listening for Flux events over chaining `.then(...)` to Flux action promises.
|
|
15
|
+
- Flux actions update the data store before dispatching their events.
|
|
16
|
+
- Multiple listeners may listen for the same Flux action event.
|
|
17
|
+
- Read persistent data from the data store, and read event-specific data directly from the Flux action event when appropriate.
|
|
18
|
+
- Send all data as JSON.
|
|
19
|
+
- Use Reaktor (`@nlabs/reaktor`) for actions that interact with the ArangoDB database.
|
|
6
20
|
|
|
7
|
-
##
|
|
8
|
-
-
|
|
9
|
-
-
|
|
21
|
+
## Database
|
|
22
|
+
- All projects use the ArangoDB instance at `https://db.reaktor.io:8529`.
|
|
23
|
+
- ArangoDB is a document NoSQL database with SQL-style query and graph database features.
|
|
24
|
+
- When adding or deleting documents, check whether associated graph edges also need to be added or deleted.
|
|
10
25
|
|
|
11
|
-
##
|
|
12
|
-
-
|
|
13
|
-
-
|
|
26
|
+
## Project Structure
|
|
27
|
+
- Web apps should contain at least one microsite.
|
|
28
|
+
- Web apps should include a `src/ui` folder.
|
|
29
|
+
- Web apps with a backend should include a `src/api` folder or microsite.
|
|
30
|
+
- Library projects may use a root source folder without `src/ui` or `src/api`.
|
|
31
|
+
- Shared utility/helper functions should live in a shared file when used in more than one place.
|
|
32
|
+
- Keep one component per file.
|
|
33
|
+
- Each component should have a sibling test file named `MyComponent.test.ts` or `MyComponent.test.tsx`.
|
|
34
|
+
- Group components by component folder, for example `src/ui/components/MyComponent/MyComponent.tsx`.
|
|
35
|
+
|
|
36
|
+
## Package Scripts
|
|
37
|
+
- All projects should have at least `start`, `test`, and `update` scripts.
|
|
38
|
+
- If a project includes both `api` and `ui` workspaces, use `concurrently` in `start`:
|
|
39
|
+
`"start": "concurrently \"npm run start -w api\" \"npm run start -w ui\""`
|
|
40
|
+
- Use this workspace test script:
|
|
41
|
+
`"test": "npm run test --workspaces --ignore-scripts"`
|
|
42
|
+
- Use this workspace update script:
|
|
43
|
+
`"update": "npm run update --workspaces"`
|
|
44
|
+
|
|
45
|
+
## Testing
|
|
46
|
+
- Maintain at least 90% unit test coverage.
|
|
47
|
+
- Components that require other components should have integration tests.
|
|
48
|
+
- Provide at least one Playwright e2e test for each happy path.
|
|
49
|
+
|
|
50
|
+
## Code Style
|
|
51
|
+
- Use arrow functions for functions.
|
|
52
|
+
- Correctly type all variables, props, and arguments unless TypeScript inference already provides the correct type.
|
|
53
|
+
- Sort props and object keys alphabetically.
|
|
54
|
+
- Check and fix all ESLint errors and warnings.
|
|
55
|
+
- Use `eslint-config-styleguide` for linting rules.
|
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# MetropolisJS: Seamless Frontend-Backend Integration Framework
|
|
2
2
|
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="docs/assets/metropolisjs-logo.png" alt="MetropolisJS logo" width="432">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
3
7
|
> **The Ultimate Frontend Integration Library for Modern Web Applications**
|
|
4
8
|
|
|
5
9
|
[](https://www.npmjs.com/package/@nlabs/metropolisjs)
|
|
@@ -53,7 +57,7 @@ npm install @nlabs/metropolisjs @nlabs/arkhamjs @nlabs/arkhamjs-utils-react
|
|
|
53
57
|
### Basic Setup
|
|
54
58
|
|
|
55
59
|
```tsx
|
|
56
|
-
import {Metropolis, useUserActions, useMessageActions, useWebsocketActions} from '@nlabs/metropolisjs';
|
|
60
|
+
import {Metropolis, useUserActions, useMessageActions, useRestActions, useWebsocketActions} from '@nlabs/metropolisjs';
|
|
57
61
|
|
|
58
62
|
const App = () => {
|
|
59
63
|
return (
|
|
@@ -92,14 +96,59 @@ MetropolisJS provides multiple ways to access actions:
|
|
|
92
96
|
// Option 1: Specialized hooks (recommended - best performance)
|
|
93
97
|
const userActions = useUserActions();
|
|
94
98
|
const postActions = usePostActions();
|
|
99
|
+
const restActions = useRestActions();
|
|
95
100
|
|
|
96
101
|
// Option 2: Selective creation
|
|
97
|
-
const {userActions, postActions} = useMetropolis(['user', 'post']);
|
|
102
|
+
const {userActions, postActions, restActions} = useMetropolis(['user', 'post', 'rest']);
|
|
98
103
|
|
|
99
104
|
// Option 3: All actions (default behavior)
|
|
100
105
|
const {userActions, postActions, messageActions} = useMetropolis();
|
|
101
106
|
```
|
|
102
107
|
|
|
108
|
+
### External REST Endpoints
|
|
109
|
+
|
|
110
|
+
MetropolisJS includes a `rest` action group for APIs that are not part of Reaktor. It delegates to `@nlabs/rip-hunter`, so app code can keep using Metropolis actions instead of importing rip-hunter directly.
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
<Metropolis
|
|
114
|
+
config={{
|
|
115
|
+
development: {
|
|
116
|
+
app: {
|
|
117
|
+
api: {
|
|
118
|
+
endpoints: {
|
|
119
|
+
weather: 'https://api.example.com/weather'
|
|
120
|
+
},
|
|
121
|
+
public: 'http://localhost:3000/public',
|
|
122
|
+
url: 'http://localhost:3000/app'
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
<YourApp />
|
|
129
|
+
</Metropolis>
|
|
130
|
+
|
|
131
|
+
const WeatherPanel = () => {
|
|
132
|
+
const restActions = useRestActions();
|
|
133
|
+
|
|
134
|
+
const loadWeather = async () => {
|
|
135
|
+
const weather = await restActions.get('weather', {zip: '60601'}, {cache: true});
|
|
136
|
+
return weather;
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Use `authenticate: true` when an external endpoint should receive the current Metropolis session token:
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
const profile = await restActions.request(
|
|
145
|
+
'https://api.example.com/profile',
|
|
146
|
+
'PATCH',
|
|
147
|
+
{displayName: 'Ada'},
|
|
148
|
+
{authenticate: true}
|
|
149
|
+
);
|
|
150
|
+
```
|
|
151
|
+
|
|
103
152
|
## Configuration
|
|
104
153
|
|
|
105
154
|
The `Metropolis` component accepts three main props: `config`, `adapters`, and `translations`. Here's how to configure each:
|
|
@@ -165,6 +214,7 @@ The `config` prop accepts a `MetropolisConfiguration` object that supports envir
|
|
|
165
214
|
- `environment`: `'development' | 'production' | 'test' | 'local'` - Current environment
|
|
166
215
|
- `app`: Application-specific configuration
|
|
167
216
|
- `api`: API endpoint configuration
|
|
217
|
+
- `endpoints`: Named external REST endpoints for `restActions`
|
|
168
218
|
- `url`: Main API endpoint
|
|
169
219
|
- `public`: Public API endpoint
|
|
170
220
|
- `uploadImage`: Image upload endpoint
|
package/docs/ACTIONS.md
CHANGED
|
@@ -7,20 +7,22 @@ This reference documents every action family exposed by MetropolisJS, how to acc
|
|
|
7
7
|
Use specialized hooks in React components:
|
|
8
8
|
|
|
9
9
|
```tsx
|
|
10
|
-
import {useUserActions, usePostActions, useMessageActions} from '@nlabs/metropolisjs';
|
|
10
|
+
import {useUserActions, usePostActions, useMessageActions, useRestActions} from '@nlabs/metropolisjs';
|
|
11
11
|
|
|
12
12
|
const userActions = useUserActions();
|
|
13
13
|
const postActions = usePostActions();
|
|
14
14
|
const messageActions = useMessageActions();
|
|
15
|
+
const restActions = useRestActions();
|
|
15
16
|
```
|
|
16
17
|
|
|
17
18
|
Or create actions directly with a Flux instance:
|
|
18
19
|
|
|
19
20
|
```ts
|
|
20
|
-
import {createUserActions, createPostActions} from '@nlabs/metropolisjs';
|
|
21
|
+
import {createUserActions, createPostActions, createRestActions} from '@nlabs/metropolisjs';
|
|
21
22
|
|
|
22
23
|
const userActions = createUserActions(flux);
|
|
23
24
|
const postActions = createPostActions(flux);
|
|
25
|
+
const restActions = createRestActions(flux);
|
|
24
26
|
```
|
|
25
27
|
|
|
26
28
|
## Action Families
|
|
@@ -30,27 +32,87 @@ Each row links to:
|
|
|
30
32
|
- hook exposure (`src/utils/useMetropolis.ts`)
|
|
31
33
|
- common method names (full signatures live in the interface in each source file)
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
### Hook and Factory Actions
|
|
36
|
+
|
|
37
|
+
These action families are available through specialized hooks when present, `useMetropolis([...])`, `createAction(...)`, `createActions(...)`, and direct creators.
|
|
38
|
+
|
|
39
|
+
| Family | Hook | Factory Key | Creator | Typical Methods | Source |
|
|
34
40
|
| --- | --- | --- | --- | --- |
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
|
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
| Tag | `useTagActions` | `createTagActions` | `addTag`, `addTagToItem`, `getTags`, `updateTag`, `deleteTag`, `deleteTagFromItem` | [tagActions.ts](../src/actions/tagActions/tagActions.ts) |
|
|
50
|
-
| Translation | `useTranslationActions` | `createTranslationActions` | `addTranslations`, `getTranslation`, `getTranslations`, `hasTranslation`, `queueTranslationKey`, `processPendingTranslations` | [translationActions.ts](../src/actions/translationActions/translationActions.ts) |
|
|
51
|
-
| User | `useUserActions` | `createUserActions` | `signIn`, `signUp`, `session`, `refreshSession`, `itemById`, `listByLatest`, `updateUser` | [userActions.ts](../src/actions/userActions/userActions.ts) |
|
|
52
|
-
| Video | `
|
|
53
|
-
| Websocket | `useWebsocketActions` | `createWebsocketActions` | `wsInit`, `wsSend`, `onOpen`, `onReceive`, `onClose`, `onError` | [websocketActions.ts](../src/actions/websocketActions/websocketActions.ts) |
|
|
41
|
+
| Content | `useContentActions` | `content` | `createContentActions` | `add`, `itemById`, `itemByKey`, `listByCategory`, `list`, `update`, `delete` | [contentActions.ts](../src/actions/contentActions/contentActions.ts) |
|
|
42
|
+
| CRM | `useCrmActions` | `crm` | `createCrmActions` | `mailingLists`, `createMailingList`, `createSupportTicket`, `supportTickets`, `customerOrdersByUser` | [crmActions.ts](../src/actions/crmActions/crmActions.ts) |
|
|
43
|
+
| Event | `useEventActions` | `event` | `createEventActions` | `addEvent`, `getEvent`, `getEventsByTags`, `getEventsByReactions`, `updateEvent`, `deleteEvent` | [eventActions.ts](../src/actions/eventActions/eventActions.ts) |
|
|
44
|
+
| Group | `useGroupActions` | `group` | `createGroupActions` | `add`, `itemById`, `listByLatest`, `update`, `delete` | [groupActions.ts](../src/actions/groupActions/groupActions.ts) |
|
|
45
|
+
| Image | `useImageActions` | `image` | `createImageActions` | `add`, `update`, `delete`, `upload`, `countByItem`, `listByItem`, `listByReactions` | [imageActions.ts](../src/actions/imageActions/imageActions.ts) |
|
|
46
|
+
| Location | `useLocationActions` | `location` | `createLocationActions` | `autocompleteLocation`, `add`, `getLocation`, `getCurrentLocation`, `listByItem`, `update`, `delete` | [locationActions.ts](../src/actions/locationActions/locationActions.ts) |
|
|
47
|
+
| Message | `useMessageActions` | `message` | `createMessageActions` | `sendMessage`, `getMessages`, `getConversations`, `getDirectConversation` | [messageActions.ts](../src/actions/messageActions/messageActions.ts) |
|
|
48
|
+
| Permission | `usePermissionActions` | `permission` | `createPermissionActions` | `add`, `check`, `itemById`, `list`, `listByUser`, `update`, `remove` | [permissionActions.ts](../src/actions/permissionActions/permissionActions.ts) |
|
|
49
|
+
| Post | `usePostActions` | `post` | `createPostActions` | `add`, `itemById`, `listByLatest`, `listByLocation`, `listByReactions`, `listByTags`, `update`, `delete` | [postActions.ts](../src/actions/postActions/postActions.ts) |
|
|
50
|
+
| Persona | `usePersonaActions` | `persona` | `createPersonaActions` | `addPersona`, `getPersona`, `getPersonas`, `updatePersona`, `deletePersona` | [personaActions.ts](../src/actions/personaActions/personaActions.ts) |
|
|
51
|
+
| Reaction | `useReactionActions` | `reaction` | `createReactionActions` | `addReaction`, `deleteReaction`, `getReactionCount`, `hasReaction`, `abbreviateCount` | [reactionActions.ts](../src/actions/reactionActions/reactionActions.ts) |
|
|
52
|
+
| REST | `useRestActions` | `rest` | `createRestActions` | `get`, `post`, `put`, `delete`, `request` | [restActions.ts](../src/actions/restActions/restActions.ts) |
|
|
53
|
+
| SSE | `useMetropolis(['sse'])` | `sse` | `createSSEActions` | `connect`, `disconnect`, `reconnect`, `isConnected`, `sendMessage`, `addEventListener`, `removeEventListener` | [sseActions.ts](../src/actions/sseActions/sseActions.ts) |
|
|
54
|
+
| Subscription | `useSubscriptionActions` | `subscription` | `createSubscriptionActions` | `addPlan`, `getPlanByItem`, `addSubscription`, `getSubscriptionByItem`, `getSubscriptionListByUser`, `deleteSubscription` | [subscriptionActions.ts](../src/actions/subscriptionActions/subscriptionActions.ts) |
|
|
55
|
+
| Tag | `useTagActions` | `tag` | `createTagActions` | `addTag`, `addTagToItem`, `getTags`, `updateTag`, `deleteTag`, `deleteTagFromItem` | [tagActions.ts](../src/actions/tagActions/tagActions.ts) |
|
|
56
|
+
| Translation | `useTranslationActions` | `translation` | `createTranslationActions` | `addTranslations`, `getTranslation`, `getTranslations`, `hasTranslation`, `queueTranslationKey`, `processPendingTranslations` | [translationActions.ts](../src/actions/translationActions/translationActions.ts) |
|
|
57
|
+
| User | `useUserActions` | `user` | `createUserActions` | `signIn`, `signUp`, `session`, `refreshSession`, `itemById`, `listByLatest`, `updateUser` | [userActions.ts](../src/actions/userActions/userActions.ts) |
|
|
58
|
+
| Video | `useVideoActions` | `video` | `createVideoActions` | `add`, `itemById`, `list`, `update`, `delete` | [videoActions.ts](../src/actions/videoActions/videoActions.ts) |
|
|
59
|
+
| Websocket | `useWebsocketActions` | `websocket` | `createWebsocketActions` | `wsInit`, `wsSend`, `onOpen`, `onReceive`, `onClose`, `onError` | [websocketActions.ts](../src/actions/websocketActions/websocketActions.ts) |
|
|
60
|
+
|
|
61
|
+
### Direct Creator Actions
|
|
62
|
+
|
|
63
|
+
These creators are exported directly from MetropolisJS, but are not currently part of the `createAction(...)`/`useMetropolis([...])` factory key union.
|
|
64
|
+
|
|
65
|
+
| Family | Creator | Typical Methods | Source |
|
|
66
|
+
| --- | --- | --- | --- |
|
|
67
|
+
| App | `createAppActions` | `add`, `itemById`, `list`, `update`, `delete` | [appActions.ts](../src/actions/appActions/appActions.ts) |
|
|
68
|
+
| Connection | `createConnectionActions` | `addConnection`, `getConnections`, `removeConnection` | [connectionActions.ts](../src/actions/connectionActions/connectionActions.ts) |
|
|
69
|
+
| Conversation | `createConversationActions` | `add`, `itemById`, `list`, `update`, `delete` | [conversationActions.ts](../src/actions/conversationActions/conversationActions.ts) |
|
|
70
|
+
|
|
71
|
+
## REST Actions
|
|
72
|
+
|
|
73
|
+
Use REST actions for external APIs that are not represented in Reaktor. REST actions delegate to `@nlabs/rip-hunter`, share Metropolis network/session handling, and can target either a configured endpoint key or an absolute URL.
|
|
74
|
+
|
|
75
|
+
Configure named endpoints under `app.api.endpoints`:
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
<Metropolis
|
|
79
|
+
config={{
|
|
80
|
+
development: {
|
|
81
|
+
app: {
|
|
82
|
+
api: {
|
|
83
|
+
endpoints: {
|
|
84
|
+
weather: 'https://api.example.com/weather'
|
|
85
|
+
},
|
|
86
|
+
public: 'http://localhost:3000/public',
|
|
87
|
+
url: 'http://localhost:3000/app'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}}
|
|
92
|
+
>
|
|
93
|
+
<YourApp />
|
|
94
|
+
</Metropolis>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Call the endpoint through `useRestActions()`:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const restActions = useRestActions();
|
|
101
|
+
|
|
102
|
+
const weather = await restActions.get('weather', {zip: '60601'}, {cache: true});
|
|
103
|
+
const created = await restActions.post('https://api.example.com/items', {name: 'Item'});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Pass `authenticate: true` only when the endpoint should receive the current Metropolis session token:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const profile = await restActions.request(
|
|
110
|
+
'https://api.example.com/profile',
|
|
111
|
+
'PATCH',
|
|
112
|
+
{displayName: 'Ada'},
|
|
113
|
+
{authenticate: true}
|
|
114
|
+
);
|
|
115
|
+
```
|
|
54
116
|
|
|
55
117
|
## Full Exports
|
|
56
118
|
|
|
Binary file
|
|
@@ -101,12 +101,17 @@ export const runtimeUpdates = (flux: FluxFramework) => {
|
|
|
101
101
|
// Example 4: Testing with Mock Adapters
|
|
102
102
|
export const testingExample = (flux: FluxFramework) => {
|
|
103
103
|
// Mock adapter for testing
|
|
104
|
-
const mockUserAdapter =
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
const mockUserAdapter = Object.assign((input: unknown) => {
|
|
105
|
+
mockUserAdapter.calls.push(input);
|
|
106
|
+
return {
|
|
107
|
+
...(input as Record<string, unknown>),
|
|
108
|
+
id: 'mock-user-id',
|
|
109
|
+
validated: true,
|
|
110
|
+
timestamp: new Date().toISOString()
|
|
111
|
+
};
|
|
112
|
+
}, {
|
|
113
|
+
calls: [] as unknown[]
|
|
114
|
+
});
|
|
110
115
|
|
|
111
116
|
const userActions = createAction('user', flux, {
|
|
112
117
|
userAdapter: mockUserAdapter
|
|
@@ -119,9 +124,9 @@ export const testingExample = (flux: FluxFramework) => {
|
|
|
119
124
|
email: 'test@example.com'
|
|
120
125
|
});
|
|
121
126
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
if(mockUserAdapter.calls.length === 0 || user.id !== 'mock-user-id' || user.validated !== true) {
|
|
128
|
+
throw new Error('Mock adapter validation failed');
|
|
129
|
+
}
|
|
125
130
|
};
|
|
126
131
|
|
|
127
132
|
return {userActions, testUserCreation};
|
|
@@ -280,4 +285,4 @@ export const migrationExample = (flux: FluxFramework) => {
|
|
|
280
285
|
};
|
|
281
286
|
|
|
282
287
|
return { createUser, createPost };
|
|
283
|
-
};
|
|
288
|
+
};
|
package/lex.config.mjs
CHANGED
|
@@ -12,13 +12,6 @@ export default Config.create({
|
|
|
12
12
|
minify: process.env.NODE_ENV === 'production'
|
|
13
13
|
},
|
|
14
14
|
gitUrl: 'https://github.com/nitrogenlabs/metropolisjs',
|
|
15
|
-
jest: {
|
|
16
|
-
extensionsToTreatAsEsm: ['.ts', '.tsx'],
|
|
17
|
-
moduleNameMapper: {
|
|
18
|
-
'^@nlabs/(.*)$': '<rootDir>/node_modules/@nlabs/$1'
|
|
19
|
-
},
|
|
20
|
-
testEnvironment: 'jsdom'
|
|
21
|
-
},
|
|
22
15
|
outputPath: 'lib',
|
|
23
16
|
targetEnvironment: 'web',
|
|
24
17
|
useESM: true,
|
|
@@ -53,6 +46,10 @@ export default Config.create({
|
|
|
53
46
|
lines: 90,
|
|
54
47
|
statements: 90
|
|
55
48
|
}
|
|
56
|
-
}
|
|
49
|
+
},
|
|
50
|
+
globals: true,
|
|
51
|
+
hookTimeout: 120000,
|
|
52
|
+
testEnvironment: 'jsdom',
|
|
53
|
+
testTimeout: 120000
|
|
57
54
|
}
|
|
58
55
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appActions.d.ts","sourceRoot":"","sources":["../../../src/actions/appActions/appActions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"appActions.d.ts","sourceRoot":"","sources":["../../../src/actions/appActions/appActions.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,2BAA2B,CAAC;AACvD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,6BAA6B,CAAC;AAItE,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,iBAAiB,KAAK,GAAG,CAAC;IAClE,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE;QACJ,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;CACH,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,cAAc,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACjH,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,cAAc,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxG,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,cAAc,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1G,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,cAAc,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACrH,MAAM,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,cAAc,CAAC,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChH,gBAAgB,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,iBAAiB,KAAK,GAAG,KAAK,IAAI,CAAC;IAC1F,uBAAuB,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC/D;AAKD,eAAO,MAAM,gBAAgB,GAC3B,MAAM,aAAa,EACnB,UAAU,iBAAiB,KAC1B,UAuNF,CAAC"}
|