h1v3 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -101,9 +101,9 @@ This allows you to, in the browser, do:
101
101
  const meta = import("/store_meta") with { type: "json" }
102
102
  ```
103
103
 
104
- ## Vendor the client-side libraries
104
+ ## Client-side libraries
105
105
 
106
- You can install (free) dependencies and client files for the library using npx
106
+ You can vendor the (free) dependencies and client files for the library using npx
107
107
 
108
108
  ```bash
109
109
  npx h1v3 vendor-deps
@@ -118,7 +118,7 @@ You will also need to provide a vendored library of WebAwesome Pro:
118
118
 
119
119
  - `/public/vendor/webawesome-pro` - for now this is an explicit dependency although you can symlink it to your current version of webawesome-pro. The system expects the `dist` folder to be available at `/public/vendor/webawesome-pro/dist`.
120
120
 
121
- # Usage patterns
121
+ # Usage patterns - Client-side
122
122
 
123
123
  ## Importing the library
124
124
 
@@ -132,6 +132,143 @@ export { styled } from "/vendor/h1v3@0.7.6/client/components/partials/wa-utils.j
132
132
  export * from "/vendor/h1v3@0.7.6/client/system.js";
133
133
  ```
134
134
 
135
+ ## Firebase configuration
136
+
137
+ The system expects you to expose your (public) firebase config in an ESM module at `/firebase.config.js`. For example:
138
+
139
+ ```javascript
140
+ export default {
141
+ apiKey: "AIzaSyCV6FjdJwU50TUZVRcoFCWqQItjhhQKbXQ",
142
+ authDomain: "ixion-c9e0e.firebaseapp.com",
143
+ databaseURL: "https://ixion-c9e0e-default-rtdb.europe-west1.firebasedatabase.app",
144
+ projectId: "ixion-c9e0e",
145
+ appId: "1:28699144755:web:2ab262d02ccba70979e946"
146
+ };
147
+ ```
148
+
149
+ # Usage Patterns - Firebase functions
150
+
151
+ ## Basic routes
152
+
153
+ Configure at least the following four event stores:
154
+ - user_profile - in which a user can maintain details of their profile (as determined by the referenced schema)
155
+ - user_teams - where the system will maintain a quick lookup list of a user's teams
156
+ - team_membership - where the system records the master list of users' membership of teams, and their role (member or admin)
157
+ - team_details - where any admin of a team can maintain details of the team they administer (as determined by the referenced schema).
158
+
159
+
160
+ ```javascript
161
+ import { onValueWritten } from "firebase-functions/database";
162
+
163
+ import * as h1v3 from "h1v3";
164
+
165
+ import paths from "./h1v3.paths.js";
166
+ import userProfileSchema from "./schemas/user-profile-schema.js";
167
+ import teamDetailsSchema from "./schemas/team-details-schema.js";
168
+ import { observe } from "./o11y-provider.js";
169
+ import { region, rtdbInstance } from "./firebase.config.js";
170
+
171
+
172
+ const configureEventStore = h1v3.configureEventStore.inject({
173
+ region,
174
+ onValueWritten,
175
+ instance: rtdbInstance,
176
+ paths,
177
+ observe,
178
+ });
179
+
180
+ export const user_profile = configureEventStore(h1v3.userProfile.store, userProfileSchema);
181
+ export const user_teams = configureEventStore(h1v3.userTeams.store);
182
+ export const team_membership = configureEventStore(h1v3.teamMembership.store);
183
+ export const team_details = configureEventStore(h1v3.teamDetails.store, teamDetailsSchema);
184
+ ```
185
+
186
+ ### Defining schemas
187
+
188
+ Schemas for the two built-in event stores user_profile and team_details expect a schema defined using a javascript prototype as shown below. Note that there is no required constraint. Instead the schema is a white-list of keys along with the expected type for the associated value.
189
+
190
+ ```javascript
191
+ export default {
192
+ name: String,
193
+ age: Number,
194
+ favourite: {
195
+ color: String
196
+ }
197
+ };
198
+ ```
199
+
200
+ ## Observability provider
201
+
202
+ h1v3 has a built-in observability provider, but it must be initialised using external logging and trace facilities. An example implementation is shown below. This illustrates initialising the provider with (1) emulated versions of tracing and logging and (2) Google Cloud versions:
203
+
204
+ ```javascript
205
+ import { Logging } from "@google-cloud/logging";
206
+ import { google } from "googleapis";
207
+
208
+ import * as h1v3 from "h1v3";
209
+
210
+ import { projectId, serviceName } from "./firebase.config.js";
211
+
212
+ const [trace, log] = process.env.FUNCTIONS_EMULATOR === "true" ? buildEmulated() : buildReal();
213
+
214
+ export const observe = h1v3.o11y.provider({
215
+ trace,
216
+ log,
217
+ projectId,
218
+ serviceName
219
+ });
220
+
221
+ function buildReal() {
222
+
223
+ const scopes = [
224
+ "https://www.googleapis.com/auth/trace.append",
225
+ "https://www.googleapis.com/auth/cloud-platform"
226
+ ];
227
+
228
+ google.auth.getClient({ scopes }).then(auth => google.options({ auth })); // we can't await this as firebase will complain
229
+
230
+ return [
231
+ google.cloudtrace("v2"),
232
+ new Logging().log(serviceName)
233
+ ];
234
+
235
+ }
236
+
237
+ function buildEmulated() {
238
+
239
+ return [
240
+ {
241
+ projects: {
242
+ traces: {
243
+ spans: {
244
+ createSpan(...args) {
245
+
246
+ console.log("[TRACE]", JSON.stringify(args));
247
+
248
+ }
249
+ }
250
+ }
251
+ }
252
+ },
253
+ {
254
+ entry: (...args) => args,
255
+ write(entry) {
256
+
257
+ console.log("[LOG]", JSON.stringify(entry));
258
+
259
+ }
260
+ }
261
+ ];
262
+
263
+ }
264
+ ```
265
+
266
+
267
+
268
+
269
+
270
+
271
+
135
272
 
136
273
  # Implicit Google API dependencies
137
274
 
@@ -20,14 +20,13 @@ function defaultHandleError(err) {
20
20
 
21
21
  }
22
22
 
23
- export async function inject({ database, authentication, metaURL, handleError = defaultHandleError }) {
23
+ export async function inject({ database, authentication, metaURL, meta, handleError = defaultHandleError }) {
24
24
 
25
25
  if (!database) throw new Error("Missing database");
26
- if (!metaURL) throw new Error("Missing metaURL");
26
+ if (!(metaURL || meta)) throw new Error("Missing metaURL");
27
27
  if (!authentication) throw new Error("Missing authentication");
28
28
 
29
- // const meta = await fetch(metaURL).then(resp => resp.json())
30
- const { default: meta } = await import(metaURL, { with: { type: "json" } });
29
+ meta = meta || await import(metaURL, { with: { type: "json" } });
31
30
 
32
31
  const log = logger(database, authentication, meta.o11y.path);
33
32
  const teamMembershipStoreFactory = ({ tid }) => eventStore(database, authentication, populateParameters({ tid }, meta.team.membership.path));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "h1v3",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "author": "",
@@ -35,4 +35,9 @@ export function configureEventStore({ ref, projections, ...rest }, { onValueWrit
35
35
  );
36
36
 
37
37
  }
38
- configureEventStore.inject = ({ onValueWritten, observe, paths, region, instance }) => (eventStoreFactory, ...args) => configureEventStore(eventStoreFactory(paths, ...args), { onValueWritten, observe, region, instance });
38
+
39
+ configureEventStore.inject = ({ onValueWritten, observe, paths, region, instance }) =>
40
+
41
+ (eventStoreFactory, ...args) =>
42
+
43
+ configureEventStore(eventStoreFactory(paths, ...args), { onValueWritten, observe, region, instance });