h1v3 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +3 -0
- package/dist/browser/client/auth.js +128 -0
- package/dist/browser/client/bus.js +1 -0
- package/{src/client/web-ui → dist/browser/client}/components/login.js +11 -2
- package/dist/browser/client/components/notification.html.js +25 -0
- package/dist/browser/client/components/notification.js +27 -0
- package/{src/client/web-ui → dist/browser/client}/components/partials/wa-utils.js +1 -0
- package/dist/browser/client/context.js +98 -0
- package/dist/browser/{event-store/modular.js → client/event-store.js} +22 -14
- package/dist/browser/{web → client}/events.js +5 -1
- package/{src/client/web/system.js → dist/browser/client/firebase.js} +1 -7
- package/dist/browser/client/id.js +37 -0
- package/dist/browser/client/logger.js +60 -0
- package/dist/browser/client/notifications.js +50 -0
- package/dist/browser/{web-ui → client}/system.js +10 -4
- package/dist/browser/client/team/invites.js +119 -0
- package/dist/browser/client/team/team.js +143 -0
- package/dist/browser/client/team/user.js +62 -0
- package/package.json +2 -7
- package/src/client/context.js +58 -0
- package/src/client/index.js +2 -4
- package/src/client/node.js +2 -2
- package/src/commands/generate-rules.js +56 -39
- package/src/commands/vendor.js +86 -23
- package/src/configuration.js +106 -0
- package/src/event-store/{initialise.js → configuration.js} +15 -4
- package/src/event-store/projections.js +40 -11
- package/src/exec-eventstore.js +48 -14
- package/src/index.js +20 -4
- package/src/load-configuration.js +17 -3
- package/src/membership/index.js +5 -3
- package/src/membership/team-details/events.js +5 -0
- package/src/membership/team-details/projections/current.js +9 -0
- package/src/membership/team-details/store.js +30 -0
- package/src/membership/team-details/verify-store-paths.js +8 -0
- package/src/membership/team-membership/events.js +17 -0
- package/src/membership/team-membership/projections/_shared.js +55 -0
- package/src/membership/team-membership/projections/details.js +105 -0
- package/src/membership/team-membership/projections/inviteToEmail.js +25 -0
- package/src/membership/team-membership/projections/members.js +68 -0
- package/src/membership/team-membership/store.js +56 -0
- package/src/membership/user-profile/events.js +6 -0
- package/src/membership/user-profile/projections/current.js +9 -0
- package/src/membership/user-profile/store.js +28 -0
- package/src/membership/user-teams/events.js +5 -0
- package/src/membership/{user-teams-store.js → user-teams/projections/current.js} +2 -24
- package/src/membership/user-teams/store.js +27 -0
- package/src/membership/userInvites/events.js +12 -0
- package/src/membership/userInvites/projections/pending.js +45 -0
- package/src/membership/userInvites/store.js +46 -0
- package/src/paths.js +5 -0
- package/src/rules.js +153 -0
- package/src/schema.js +91 -1
- package/src/system/main.js +1 -1
- package/dist/browser/team/team.js +0 -25
- package/dist/browser/web/login.js +0 -48
- package/dist/browser/web/system.js +0 -67
- package/dist/browser/web-ui/components/login.js +0 -74
- package/dist/browser/web-ui/components/notification.html.js +0 -12
- package/dist/browser/web-ui/components/notification.js +0 -25
- package/dist/browser/web-ui/components/partials/wa-utils.js +0 -17
- package/dist/browser/web-ui/errors.js +0 -23
- package/scripts/dist-client.js +0 -32
- package/src/client/modular.js +0 -81
- package/src/client/team-node.js +0 -28
- package/src/client/team.js +0 -38
- package/src/client/web/events.js +0 -7
- package/src/client/web/login.js +0 -48
- package/src/client/web-ui/components/login.html.js +0 -44
- package/src/client/web-ui/components/notification.html.js +0 -12
- package/src/client/web-ui/components/notification.js +0 -25
- package/src/client/web-ui/errors.js +0 -23
- package/src/client/web-ui/system.js +0 -20
- package/src/membership/membership-store.js +0 -131
- package/src/membership/user-profile-store.js +0 -42
- /package/dist/browser/{web-ui → client}/components/login.html.js +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const ADDED_TO_TEAM = "ADDED_TO_TEAM";
|
|
2
|
+
const ACCEPTED_INVITATION = "ACCEPTED_INVITATION";
|
|
3
|
+
const REJECTED_INVITATION = "REJECTED_INVITATION";
|
|
4
|
+
const INVITE_ACCEPTED = "INVITE_ACCEPTED";
|
|
5
|
+
const INVITE_REJECTED = "INVITE_REJECTED";
|
|
6
|
+
|
|
7
|
+
export function userInvites({ email, uid, teamMembershipStoreFactory, userTeamsStore, userInvitesStore, handleErrors = console.error.bind(console) }) {
|
|
8
|
+
|
|
9
|
+
if (!email) throw new Error("Missing email");
|
|
10
|
+
if (!uid) throw new Error("Missing uid");
|
|
11
|
+
if (!teamMembershipStoreFactory) throw new Error("Missing teamMembershipStoreFactory");
|
|
12
|
+
if (!userInvitesStore) throw new Error("Missing userInvitesStore");
|
|
13
|
+
if (!userTeamsStore) throw new Error("Missing userTeamsStore");
|
|
14
|
+
|
|
15
|
+
let unsubscribe = userInvitesStore.onProjectionValue("pending", handleUserInvitesUpdated);
|
|
16
|
+
let lastUserInvites;
|
|
17
|
+
const onInvitesCallbacks = [];
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
|
|
21
|
+
async getInvites() {
|
|
22
|
+
|
|
23
|
+
return userInvitesStore.getProjection("pending");
|
|
24
|
+
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
async rejectInvite({ id, name = "" }) {
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
|
|
31
|
+
await respondToInvite({ id, name, invitesEvent: REJECTED_INVITATION, teamMembershipEvent: INVITE_REJECTED });
|
|
32
|
+
|
|
33
|
+
} catch(err) {
|
|
34
|
+
|
|
35
|
+
handleErrors(err);
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
async acceptInvite({ id, name = "" }) {
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
|
|
45
|
+
const { tid } = await respondToInvite({ id, name, invitesEvent: ACCEPTED_INVITATION, teamMembershipEvent: INVITE_ACCEPTED });
|
|
46
|
+
await userTeamsStore.record(ADDED_TO_TEAM, { id, tid });
|
|
47
|
+
|
|
48
|
+
} catch(err) {
|
|
49
|
+
|
|
50
|
+
handleErrors(err);
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
onInvites(callback) {
|
|
57
|
+
|
|
58
|
+
onInvitesCallbacks.push(callback);
|
|
59
|
+
callback(lastUserInvites);
|
|
60
|
+
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
offInvites(callback) {
|
|
64
|
+
|
|
65
|
+
while(onInvitesCallbacks.includes(callback)) {
|
|
66
|
+
|
|
67
|
+
onInvitesCallbacks.splice(onInvitesCallbacks.indexOf(callback), 1);
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
dispose() {
|
|
74
|
+
|
|
75
|
+
if (!unsubscribe) return;
|
|
76
|
+
unsubscribe();
|
|
77
|
+
unsubscribe = null;
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
function handleUserInvitesUpdated(snap) {
|
|
84
|
+
|
|
85
|
+
lastUserInvites = snap.val();
|
|
86
|
+
dispatchInvitesCallbacks();
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function dispatchInvitesCallbacks() {
|
|
91
|
+
|
|
92
|
+
onInvitesCallbacks.forEach(x => x(lastUserInvites));
|
|
93
|
+
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function respondToInvite({ id, name, invitesEvent, teamMembershipEvent }) {
|
|
97
|
+
|
|
98
|
+
const invitations = await userInvitesStore.getProjection("pending");
|
|
99
|
+
const invite = invitations.invites?.[id];
|
|
100
|
+
if (!invite) throw new Error("Invitation not found");
|
|
101
|
+
|
|
102
|
+
const { tid } = invite;
|
|
103
|
+
if (!tid) throw new Error("Event info invalid: missing tid");
|
|
104
|
+
|
|
105
|
+
const teamMembershipStore = teamMembershipStoreFactory({ tid });
|
|
106
|
+
|
|
107
|
+
// record acceptance/rejection in the user invites store - only if my email matches the accepted invite
|
|
108
|
+
await userInvitesStore.record(invitesEvent, { id });
|
|
109
|
+
|
|
110
|
+
// record acceptance in the team membership store - only if email matches inviteUser's email and uid matches me
|
|
111
|
+
await teamMembershipStore.record(teamMembershipEvent, { id, email, uid, name });
|
|
112
|
+
|
|
113
|
+
return { tid };
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export const BECAME_MEMBER = "BECAME_MEMBER";
|
|
2
|
+
export const BECAME_ADMIN = "BECAME_ADMIN";
|
|
3
|
+
export const ADDED_TO_TEAM = "ADDED_TO_TEAM";
|
|
4
|
+
export const MEMBER_INVITED = "MEMBER_INVITED";
|
|
5
|
+
export const ADMIN_INVITED = "ADMIN_INVITED";
|
|
6
|
+
export const DETAILS_UPDATED = "DETAILS_UPDATED";
|
|
7
|
+
|
|
8
|
+
const notSupportedFactory = strategy => () => {
|
|
9
|
+
|
|
10
|
+
throw new Error(`Not supported ${strategy}`);
|
|
11
|
+
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function bufferedSubscription(store, projectionName, handleError) {
|
|
15
|
+
|
|
16
|
+
store.onProjectionValue(projectionName, onChange, handleError);
|
|
17
|
+
|
|
18
|
+
const callbacks = [];
|
|
19
|
+
let lastProjectionValue;
|
|
20
|
+
|
|
21
|
+
function onChange(snap) {
|
|
22
|
+
|
|
23
|
+
lastProjectionValue = snap.val();
|
|
24
|
+
for(const callback of callbacks)
|
|
25
|
+
callback(lastProjectionValue);
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
|
|
31
|
+
onChange(callback) {
|
|
32
|
+
|
|
33
|
+
callbacks.push(callback);
|
|
34
|
+
if(lastProjectionValue) callback(lastProjectionValue);
|
|
35
|
+
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
offChange(callback) {
|
|
39
|
+
|
|
40
|
+
while(callbacks.includes(callback)) {
|
|
41
|
+
|
|
42
|
+
callbacks.splice(callbacks.indexOf(callback), 1);
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function team({
|
|
53
|
+
teamMembershipStore,
|
|
54
|
+
userInvitesStoreFactory,
|
|
55
|
+
teamDetailsStore,
|
|
56
|
+
userTeamsStoreFactory = notSupportedFactory("Build user teams event store"),
|
|
57
|
+
handleError = console.error.bind(console)
|
|
58
|
+
}) {
|
|
59
|
+
|
|
60
|
+
if (!teamMembershipStore) throw new Error(`Missing teamMembershipStore`);
|
|
61
|
+
if (!teamDetailsStore) throw new Error(`Missing teamDetailsStore`);
|
|
62
|
+
if (!userInvitesStoreFactory) throw new Error(`Missing userInvitesStoreFactory`);
|
|
63
|
+
|
|
64
|
+
const teamPathPattern = /\/teams\/([^\/]*)/g.exec(teamMembershipStore?.path);
|
|
65
|
+
if (!teamPathPattern?.[1]) throw new Error(`Invalid team path: ${teamMembershipStore?.path}`);
|
|
66
|
+
const tid = teamPathPattern[1];
|
|
67
|
+
|
|
68
|
+
const { onChange: onMembershipDetails, offChange: offMembershipDetails } = bufferedSubscription(teamMembershipStore, "details", handleError);
|
|
69
|
+
const { onChange: onDetails, offChange: offDetails } = bufferedSubscription(teamDetailsStore, "current", handleError);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
|
|
73
|
+
async addAdmin({ uid, name, ...rest }) {
|
|
74
|
+
|
|
75
|
+
await recordMembership({ uid, name, eventType: BECAME_ADMIN, rest });
|
|
76
|
+
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
async addMember({ uid, name, ...rest }) {
|
|
80
|
+
|
|
81
|
+
await recordMembership({ uid, name, eventType: BECAME_MEMBER, rest });
|
|
82
|
+
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
onMembershipDetails,
|
|
86
|
+
|
|
87
|
+
offMembershipDetails,
|
|
88
|
+
|
|
89
|
+
onDetails,
|
|
90
|
+
|
|
91
|
+
offDetails,
|
|
92
|
+
|
|
93
|
+
async inviteMember({ email, name, createdBy }) {
|
|
94
|
+
|
|
95
|
+
if (!email) throw new Error("Missing email");
|
|
96
|
+
if (!createdBy) throw new Error("Missing createdBy");
|
|
97
|
+
await recordInvitation({ eventType: MEMBER_INVITED, email, name, createdBy, role: "Member" });
|
|
98
|
+
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
async inviteAdmin({ email, name, createdBy }) {
|
|
102
|
+
|
|
103
|
+
if (!email) throw new Error("Missing email");
|
|
104
|
+
if (!createdBy) throw new Error("Missing createdBy");
|
|
105
|
+
await recordInvitation({ eventType: ADMIN_INVITED, email, name, createdBy, role: "Administrator" });
|
|
106
|
+
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
async setDetails(details) {
|
|
110
|
+
|
|
111
|
+
await teamDetailsStore.record(DETAILS_UPDATED, details);
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
async function recordMembership({ uid, name, eventType, rest }) {
|
|
118
|
+
|
|
119
|
+
if (!uid) throw new Error("Missing uid");
|
|
120
|
+
if (!name) throw new Error("Missing name");
|
|
121
|
+
await teamMembershipStore.record(eventType, { uid, name, ...rest });
|
|
122
|
+
const userTeamsStore = userTeamsStoreFactory({ uid });
|
|
123
|
+
await userTeamsStore.record(ADDED_TO_TEAM, { tid });
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function recordInvitation({ eventType, email, name, createdBy, role }) {
|
|
128
|
+
|
|
129
|
+
if (!email) throw new Error("Missing email");
|
|
130
|
+
if (!createdBy) throw new Error("Missing createdBy");
|
|
131
|
+
if (!name) throw new Error("Missing name");
|
|
132
|
+
if (!role) throw new Error("Missing role");
|
|
133
|
+
|
|
134
|
+
const id = crypto.randomUUID().replaceAll("-", "");
|
|
135
|
+
|
|
136
|
+
const team = await teamDetailsStore.getProjection("current");
|
|
137
|
+
await teamMembershipStore.record(eventType, { email, name, createdBy, id });
|
|
138
|
+
const userInvitesStore = userInvitesStoreFactory({ emailId: btoa(email) });
|
|
139
|
+
await userInvitesStore.record("INVITED_TO_TEAM", { email, name, tid, role, team, id });
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export const DETAILS_UPDATED = "DETAILS_UPDATED";
|
|
2
|
+
|
|
3
|
+
export function user({ userTeamsStore, userProfileStore }) {
|
|
4
|
+
|
|
5
|
+
if (!userTeamsStore) throw new Error("Missing userTeamsStore");
|
|
6
|
+
if (!userProfileStore) throw new Error("Missing userProfileStore");
|
|
7
|
+
|
|
8
|
+
userTeamsStore.onProjectionValue("current", handleTeamsCurrentChanged);
|
|
9
|
+
|
|
10
|
+
const onTeamsCallback = [];
|
|
11
|
+
let lastProjectionValue;
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
|
|
15
|
+
async setDetails(details) {
|
|
16
|
+
|
|
17
|
+
await userProfileStore.record(DETAILS_UPDATED, details);
|
|
18
|
+
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
onTeams(callback) {
|
|
22
|
+
|
|
23
|
+
onTeamsCallback.push(callback);
|
|
24
|
+
if(lastProjectionValue) callback(lastProjectionValue);
|
|
25
|
+
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
offTeams(callback) {
|
|
29
|
+
|
|
30
|
+
while(onTeamsCallback.includes(callback)) {
|
|
31
|
+
|
|
32
|
+
onTeamsCallback.splice(onTeamsCallback.indexOf(callback), 1);
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function handleTeamsCurrentChanged(snap) {
|
|
41
|
+
|
|
42
|
+
lastProjectionValue = await enumerateTeams(snap);
|
|
43
|
+
for(const callback of onTeamsCallback)
|
|
44
|
+
callback(lastProjectionValue);
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
async function enumerateTeams(myTeamsSnap) {
|
|
50
|
+
|
|
51
|
+
const val = myTeamsSnap.val();
|
|
52
|
+
const teams = val?.teams;
|
|
53
|
+
if (!teams) return null;
|
|
54
|
+
return Object.entries(teams).map(([key, val]) => ({
|
|
55
|
+
id: key,
|
|
56
|
+
name: key,
|
|
57
|
+
since: new Date(val)
|
|
58
|
+
}));
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
}
|
package/package.json
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "h1v3",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": "./src/index.js",
|
|
10
|
-
"./
|
|
11
|
-
"./client": "./src/client/index.js",
|
|
12
|
-
"./membership": "./src/membership/index.js"
|
|
10
|
+
"./client": "./src/client/index.js"
|
|
13
11
|
},
|
|
14
12
|
"bin": {
|
|
15
13
|
"eventstore": "./src/exec-eventstore.js"
|
|
16
14
|
},
|
|
17
15
|
"dependencies": {
|
|
18
16
|
"minimist": "^1.2.8"
|
|
19
|
-
},
|
|
20
|
-
"scripts": {
|
|
21
|
-
"dist:client": "node ./scripts/dist-client.js"
|
|
22
17
|
}
|
|
23
18
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { eventStoreFromConfig as defaultEventStoreFromConfig } from "./node.js";
|
|
2
|
+
import { team } from "../../dist/browser/client/team/team.js";
|
|
3
|
+
import { user } from "../../dist/browser/client/team/user.js";
|
|
4
|
+
|
|
5
|
+
export function inject({
|
|
6
|
+
db,
|
|
7
|
+
teamMembershipConfig,
|
|
8
|
+
userTeamsConfig,
|
|
9
|
+
userInvitesConfig,
|
|
10
|
+
teamDetailsConfig,
|
|
11
|
+
userProfileConfig,
|
|
12
|
+
eventStoreFromConfig = defaultEventStoreFromConfig
|
|
13
|
+
}) {
|
|
14
|
+
|
|
15
|
+
if (!teamMembershipConfig) throw new Error("Missing: teamMembershipConfig");
|
|
16
|
+
if (!userInvitesConfig) throw new Error("Missing: userInvitesConfig");
|
|
17
|
+
if (!teamDetailsConfig) throw new Error("Missing: teamDetailsConfig");
|
|
18
|
+
if (!userProfileConfig) throw new Error("Missing: userProfileConfig");
|
|
19
|
+
if (!db) throw new Error("Missing: db");
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
|
|
23
|
+
team({ tid }) {
|
|
24
|
+
|
|
25
|
+
const teamMembershipStore = eventStoreFromConfig(db, teamMembershipConfig, { tid });
|
|
26
|
+
const teamDetailsStore = eventStoreFromConfig(db, teamDetailsConfig, { tid });
|
|
27
|
+
return team({
|
|
28
|
+
teamMembershipStore,
|
|
29
|
+
teamDetailsStore,
|
|
30
|
+
userInvitesStoreFactory,
|
|
31
|
+
userTeamsStoreFactory,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
userProfile({ uid }) {
|
|
37
|
+
|
|
38
|
+
const userTeamsStore = eventStoreFromConfig(db, userTeamsConfig, { uid });
|
|
39
|
+
const userProfileStore = eventStoreFromConfig(db, userProfileConfig, { uid });
|
|
40
|
+
return user({ userTeamsStore, userProfileStore });
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function userTeamsStoreFactory({ uid }) {
|
|
47
|
+
|
|
48
|
+
return eventStoreFromConfig(db, userTeamsConfig, { uid });
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function userInvitesStoreFactory({ emailId }) {
|
|
53
|
+
|
|
54
|
+
return eventStoreFromConfig(db, userInvitesConfig, { emailId });
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
}
|
package/src/client/index.js
CHANGED
package/src/client/node.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { EVENT_STORE_META } from "../event-store/
|
|
2
|
-
import { eventStore as eventStoreModular } from "
|
|
1
|
+
import { EVENT_STORE_META } from "../event-store/configuration.js";
|
|
2
|
+
import { eventStore as eventStoreModular } from "../../dist/browser/client/event-store.js";
|
|
3
3
|
|
|
4
4
|
function adapter(db) {
|
|
5
5
|
|
|
@@ -1,32 +1,56 @@
|
|
|
1
|
-
|
|
1
|
+
import { EVENTS, PROJECTIONS } from "../../dist/browser/client/event-store.js";
|
|
2
|
+
import { explodePathVars } from "../index.js";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
function writeConditions(config) {
|
|
5
|
+
|
|
6
|
+
if (config.write === false) return false;
|
|
7
|
+
let expr = "auth.uid != null && !data.exists()";
|
|
6
8
|
if (config?.write)
|
|
7
|
-
expr += " && (" + config.write + ")"
|
|
9
|
+
expr += " && (" + explodePathVars(config.write) + ")"
|
|
8
10
|
return expr;
|
|
9
11
|
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
function
|
|
14
|
+
function readConditions(config) {
|
|
13
15
|
|
|
14
|
-
return config.read
|
|
16
|
+
return config.read === false
|
|
17
|
+
? false
|
|
18
|
+
: config.read
|
|
19
|
+
? explodePathVars(config.read)
|
|
20
|
+
: true;
|
|
15
21
|
|
|
16
22
|
}
|
|
17
23
|
|
|
24
|
+
function eventValidation(config) {
|
|
25
|
+
|
|
26
|
+
const requireType = "newData.child('type').isString()";
|
|
27
|
+
if (!Array.isArray(config?.eventTypes)) return requireType;
|
|
28
|
+
return [
|
|
29
|
+
requireType,
|
|
30
|
+
`newData.child('type').val().matches(/^(${config.eventTypes.join("|")})$/)`
|
|
31
|
+
].join(" && ");
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const rawRules = config => ({
|
|
36
|
+
".read": readConditions(config),
|
|
37
|
+
".write": writeConditions(config)
|
|
38
|
+
});
|
|
39
|
+
|
|
18
40
|
const eventStoreRules = config => ({
|
|
19
41
|
".read": false,
|
|
20
42
|
".write": false,
|
|
21
|
-
|
|
22
|
-
"$eid":
|
|
23
|
-
".write":
|
|
24
|
-
|
|
25
|
-
|
|
43
|
+
[EVENTS]: {
|
|
44
|
+
"$eid": config?.write === false
|
|
45
|
+
? { ".write": false }
|
|
46
|
+
: {
|
|
47
|
+
".write": writeConditions(config),
|
|
48
|
+
".validate": eventValidation(config)
|
|
49
|
+
}
|
|
26
50
|
},
|
|
27
|
-
|
|
51
|
+
[PROJECTIONS]: {
|
|
28
52
|
"$pid": {
|
|
29
|
-
".read":
|
|
53
|
+
".read": readConditions(config)
|
|
30
54
|
}
|
|
31
55
|
}
|
|
32
56
|
});
|
|
@@ -36,6 +60,11 @@ const splitPathIntoSegments = path =>
|
|
|
36
60
|
.split("/")
|
|
37
61
|
.filter(x => x);
|
|
38
62
|
|
|
63
|
+
const rules = config =>
|
|
64
|
+
config.raw
|
|
65
|
+
? rawRules(config)
|
|
66
|
+
: eventStoreRules(config);
|
|
67
|
+
|
|
39
68
|
const addRulesForPath = (existingRules, [
|
|
40
69
|
[
|
|
41
70
|
nextSegment,
|
|
@@ -55,7 +84,7 @@ const addRulesForPath = (existingRules, [
|
|
|
55
84
|
)
|
|
56
85
|
}
|
|
57
86
|
// stick the rules here
|
|
58
|
-
:
|
|
87
|
+
: rules(config);
|
|
59
88
|
|
|
60
89
|
const parseConfig = ([_name, config]) => [
|
|
61
90
|
// 0: the path
|
|
@@ -64,30 +93,18 @@ const parseConfig = ([_name, config]) => [
|
|
|
64
93
|
config
|
|
65
94
|
];
|
|
66
95
|
|
|
67
|
-
function
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const json = JSON.stringify(
|
|
81
|
-
stores
|
|
82
|
-
// parse the path
|
|
83
|
-
.map(parseConfig)
|
|
84
|
-
// build the map
|
|
85
|
-
.reduce(addRulesForPath, {}),
|
|
86
|
-
null, 4);
|
|
87
|
-
if(argv.snippet)
|
|
88
|
-
console.log(json.slice(1,-1));
|
|
89
|
-
else
|
|
90
|
-
console.log(json);
|
|
96
|
+
export function generateRules(_argv, eventStores, rawStores) {
|
|
97
|
+
|
|
98
|
+
console.log(
|
|
99
|
+
JSON.stringify(
|
|
100
|
+
{
|
|
101
|
+
rules: [
|
|
102
|
+
...eventStores.map(parseConfig),
|
|
103
|
+
...rawStores.map(parseConfig)
|
|
104
|
+
].reduce(addRulesForPath, {})
|
|
105
|
+
},
|
|
106
|
+
null, 4)
|
|
107
|
+
);
|
|
91
108
|
|
|
92
109
|
}
|
|
93
110
|
|