@antelopejs/interface-dms 0.10.3 → 0.10.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.10.4
4
+
5
+ [compare changes](https://github.com/AntelopeJS/dms/compare/interface-v0.10.3...v0.10.4)
6
+
7
+ ### 🔥 Performance
8
+
9
+ - **page:** Send anonymous visitors only the public pages of the site layout ([#675](https://github.com/AntelopeJS/dms/pull/675))
10
+
11
+ ### 🩹 Fixes
12
+
13
+ - **auth:** Upgrade an outdated password hash on sign-in ([#691](https://github.com/AntelopeJS/dms/pull/691))
14
+ - **dashboard:** Name the brand logo for screen readers ([#652](https://github.com/AntelopeJS/dms/pull/652))
15
+ - **onboarding:** Require a setup token to register the first owner ([#654](https://github.com/AntelopeJS/dms/pull/654))
16
+ - **tenants:** Elect one replica to provision the default tenant through a renewed lease ([#657](https://github.com/AntelopeJS/dms/pull/657))
17
+ - **layout:** Count the sidebar's installed modules like the Modules page ([#666](https://github.com/AntelopeJS/dms/pull/666))
18
+
19
+ ### 📖 Documentation
20
+
21
+ - **github:** Send questions and ideas to Discord ([#672](https://github.com/AntelopeJS/dms/pull/672))
22
+
23
+ ### 🏡 Chore
24
+
25
+ - **release:** @antelopejs/dms v0.15.0 ([c630e0e2](https://github.com/AntelopeJS/dms/commit/c630e0e2))
26
+
27
+ ### ❤️ Contributors
28
+
29
+ - Antony Rizzitelli ([@Upd4ting](http://github.com/Upd4ting))
30
+
3
31
  ## v0.10.3
4
32
 
5
33
  [compare changes](https://github.com/AntelopeJS/dms/compare/interface-v0.10.2...v0.10.3)
@@ -9,6 +9,8 @@ export type UserTimeFormat = "h23" | "h12";
9
9
  export type UserDateFormat = "numeric" | "text";
10
10
  declare const User_base: import("@antelopejs/interface-database-decorators").TableClass<Table & {
11
11
  testHash<This extends {}, F extends keyof This>(this: This, field: F, value: This[F]): unknown;
12
+ testHashAsync<This extends {}, F extends keyof This>(this: This, field: F, value: This[F]): Promise<boolean>;
13
+ isHashOutdated<This extends {}>(this: This, field: keyof This): boolean;
12
14
  }, [], object>;
13
15
  export declare class User extends User_base {
14
16
  _id: string;
@@ -5,6 +5,15 @@ export declare class Tenant extends Table {
5
5
  name: string;
6
6
  /** True while default tenant provisioning must be retried. Absent means provisioned. */
7
7
  provisioningPending?: boolean;
8
+ /** The process holding the provisioning lease. Empty means the lease is free. */
9
+ provisioningHolder?: string | null;
10
+ /**
11
+ * Replaced by every claim, renewal and release of the provisioning lease, so
12
+ * a holder that stopped is one whose token stopped changing. Undeclared
13
+ * because a first claim expects it absent, which PostgreSQL cannot tell apart
14
+ * from null on a declared column.
15
+ */
16
+ provisioningRevision?: string;
8
17
  createdAt: Date;
9
18
  updatedAt: Date;
10
19
  }
@@ -28,6 +28,10 @@ __decorate([
28
28
  (0, interface_database_decorators_1.Field)("boolean"),
29
29
  __metadata("design:type", Boolean)
30
30
  ], Tenant.prototype, "provisioningPending", void 0);
31
+ __decorate([
32
+ (0, interface_database_decorators_1.Field)("string"),
33
+ __metadata("design:type", Object)
34
+ ], Tenant.prototype, "provisioningHolder", void 0);
31
35
  __decorate([
32
36
  (0, interface_database_decorators_1.CreationTime)(),
33
37
  (0, interface_database_decorators_1.Index)(),
@@ -1 +1 @@
1
- {"version":3,"file":"tenants.table.js","sourceRoot":"","sources":["../../../src/db/tables/tenants.table.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6FAOmD;AACnD,+CAAmD;AAEtC,QAAA,gBAAgB,GAAG,SAAS,CAAC;AAGnC,IAAM,MAAM,GAAZ,MAAM,MAAO,SAAQ,qCAAK;CAoBhC,CAAA;AApBY,wBAAM;AAET;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;mCACI;AAGZ;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;oCACK;AAIb;IADP,IAAA,qCAAK,EAAC,SAAS,CAAC;;mDACqB;AAK9B;IAHP,IAAA,4CAAY,GAAE;IACd,IAAA,qCAAK,GAAE;IACP,IAAA,qCAAK,EAAC,MAAM,CAAC;8BACK,IAAI;yCAAC;AAKhB;IAHP,IAAA,0CAAU,GAAE;IACZ,IAAA,qCAAK,GAAE;IACP,IAAA,qCAAK,EAAC,MAAM,CAAC;8BACK,IAAI;yCAAC;iBAnBb,MAAM;IADlB,IAAA,6CAAa,EAAC,wBAAgB,EAAE,4BAAgB,CAAC;GACrC,MAAM,CAoBlB"}
1
+ {"version":3,"file":"tenants.table.js","sourceRoot":"","sources":["../../../src/db/tables/tenants.table.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6FAOmD;AACnD,+CAAmD;AAEtC,QAAA,gBAAgB,GAAG,SAAS,CAAC;AAGnC,IAAM,MAAM,GAAZ,MAAM,MAAO,SAAQ,qCAAK;CAgChC,CAAA;AAhCY,wBAAM;AAET;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;mCACI;AAGZ;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;oCACK;AAIb;IADP,IAAA,qCAAK,EAAC,SAAS,CAAC;;mDACqB;AAI9B;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;kDAC2B;AAanC;IAHP,IAAA,4CAAY,GAAE;IACd,IAAA,qCAAK,GAAE;IACP,IAAA,qCAAK,EAAC,MAAM,CAAC;8BACK,IAAI;yCAAC;AAKhB;IAHP,IAAA,0CAAU,GAAE;IACZ,IAAA,qCAAK,GAAE;IACP,IAAA,qCAAK,EAAC,MAAM,CAAC;8BACK,IAAI;yCAAC;iBA/Bb,MAAM;IADlB,IAAA,6CAAa,EAAC,wBAAgB,EAAE,4BAAgB,CAAC;GACrC,MAAM,CAgClB"}
package/dist/hooks.d.ts CHANGED
@@ -30,13 +30,15 @@ export declare enum Hook {
30
30
  * cleaned up along with the workspace, and make it idempotent so a retried
31
31
  * signup does not double it.
32
32
  *
33
- * It fires once per tenant, when the tenant is created, through
34
- * `ProvisionTenant` (`@antelopejs/interface-dms/tenant-provisioning`): by
35
- * the DMS for the `default` tenant, on the start that creates it, once
36
- * `DATABASE_INITIALIZED` has settled; by the signup flow of a SaaS module
37
- * for each workspace it creates. It is where a module writes the default
38
- * data a tenant starts with: written once, that data then belongs to the
39
- * tenant, and nothing writes it again on a later start.
33
+ * It fires when a tenant is created, through `ProvisionTenant`
34
+ * (`@antelopejs/interface-dms/tenant-provisioning`): by the DMS for the
35
+ * `default` tenant, once every module has started, on the replica holding its
36
+ * provisioning lease; by the signup flow of a SaaS module for each workspace
37
+ * it creates. It is where a module writes the default data a tenant starts
38
+ * with: once it succeeded, that data belongs to the tenant and nothing writes
39
+ * it again on a later start. The `default` tenant's handlers run again after
40
+ * an attempt that failed or whose process died, so a handler skips what it
41
+ * already wrote.
40
42
  */
41
43
  TENANT_BEING_PROVISIONED = "tenant:being-provisioned",
42
44
  TENANT_DELETED = "tenant:deleted",
package/dist/hooks.js CHANGED
@@ -56,13 +56,15 @@ var Hook;
56
56
  * cleaned up along with the workspace, and make it idempotent so a retried
57
57
  * signup does not double it.
58
58
  *
59
- * It fires once per tenant, when the tenant is created, through
60
- * `ProvisionTenant` (`@antelopejs/interface-dms/tenant-provisioning`): by
61
- * the DMS for the `default` tenant, on the start that creates it, once
62
- * `DATABASE_INITIALIZED` has settled; by the signup flow of a SaaS module
63
- * for each workspace it creates. It is where a module writes the default
64
- * data a tenant starts with: written once, that data then belongs to the
65
- * tenant, and nothing writes it again on a later start.
59
+ * It fires when a tenant is created, through `ProvisionTenant`
60
+ * (`@antelopejs/interface-dms/tenant-provisioning`): by the DMS for the
61
+ * `default` tenant, once every module has started, on the replica holding its
62
+ * provisioning lease; by the signup flow of a SaaS module for each workspace
63
+ * it creates. It is where a module writes the default data a tenant starts
64
+ * with: once it succeeded, that data belongs to the tenant and nothing writes
65
+ * it again on a later start. The `default` tenant's handlers run again after
66
+ * an attempt that failed or whose process died, so a handler skips what it
67
+ * already wrote.
66
68
  */
67
69
  Hook["TENANT_BEING_PROVISIONED"] = "tenant:being-provisioned";
68
70
  Hook["TENANT_DELETED"] = "tenant:deleted";
package/dist/hooks.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAyYA,oCAYC;AAMD,wCAKC;AAOD,gDASC;AAQD,kFAKC;AAED,oCAOC;AAWD,gCAgBC;AAMD,oCAGC;AAED,oCAcC;AA1fD,+DAGoC;AACpC,gEAA6D;AAM7D,oEAAgE;AAEhE,kDAAgC;AAIhC,IAAY,IA6DX;AA7DD,WAAY,IAAI;IACd;;;;;;;;;OASG;IACH,qDAA6C,CAAA;IAC7C;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,6DAAqD,CAAA;IACrD,yCAAiC,CAAA;IACjC,iDAAyC,CAAA;IACzC,qDAA6C,CAAA;IAC7C,yCAAiC,CAAA;IACjC,yCAAiC,CAAA;IACjC,iDAAyC,CAAA;IACzC;;;;OAIG;IACH,qDAA6C,CAAA;IAC7C,qCAA6B,CAAA;IAC7B,yCAAiC,CAAA;IACjC,2CAAmC,CAAA;IACnC;;;;;;;OAOG;IACH,qCAA6B,CAAA;AAC/B,CAAC,EA7DW,IAAI,oBAAJ,IAAI,QA6Df;AAqQD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkC,CAAC;AAEhE,MAAM,YAAY,GAAG,IAAI,8BAAa,EAAe,CAAC;AAEtD,SAAS,QAAQ,CAAC,IAAU;IAC1B,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,8BAAa,EAAa,CAAC;IAC7C,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,cAAc,CAAC,IAAU,EAAE,KAAqB;IACvD,iBAAO,CAAC,KAAK,CAAC,SAAS,IAAI,qBAAqB,EAAE,KAAK,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,eAAe,CAAC,IAAU;IACjC,OAAO,YAAY,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACxE,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CACrB,OAAoB,EACpB,QAAsB,EACtB,KAAyB;IAEzB,MAAM,GAAG,GAAG,KAAK,IAAI,EAAE,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,KAAK,IAAI,EAAE,CAC5B,KAAK,CAAC,CAAC,CAAC,IAAA,yCAAwB,EAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACvD,KAAK,OAAO,CAAC,OAAO,EAAE;SACnB,IAAI,CAAC,UAAU,CAAC;SAChB,KAAK,CAAC,CAAC,KAAqB,EAAE,EAAE;QAC/B,iBAAO,CAAC,KAAK,CACX,SAAS,OAAO,CAAC,IAAI,wBAAwB,KAAK,IAAI,SAAS,WAAW,EAC1E,KAAK,CACN,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,YAAY,CAC1B,IAAO,EACP,QAAwB,EACxB,OAAiC;IAEjC,MAAM,KAAK,GAAG,IAAA,qCAAoB,GAAE,CAAC;IACrC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC;QACjB,QAAQ;QACR,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,KAAK;KACrC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,OAAO;QAAE,cAAc,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAC5B,IAAO,EACP,QAAwB;IAExB,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;AAChE,CAAC;AAED;;;;GAIG;AACH,SAAgB,kBAAkB,CAChC,IAAO;IAEP,OAAO,QAAQ,CAAC,IAAI,CAAC;SAClB,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO,EAAE,KAAK,CAAC,QAAQ;KACxB,CAAC,CAAC,CAAC;AACR,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mCAAmC,CACjD,QAAgB,EAChB,OAA6C;IAE7C,YAAY,CAAC,IAAI,CAAC,kBAAkB,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC/D,CAAC;AAEM,KAAK,UAAU,YAAY,CAChC,IAAO,EACP,GAAG,IAA+B;IAElC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACI,KAAK,UAAU,UAAU,CAC9B,IAAO,EACP,GAAG,IAA+B;IAElC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAa,CAAC;IACjC,IAAI,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;IACtC,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC3B,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC;aACrB,MAAM,EAAE;aACR,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC,CAAC;IACD,YAAY,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,IAAgB;IAC3C,MAAM,SAAS,GAAG,CAAC,OAAoB,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC;IAClE,OAAO,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AACrE,CAAC;AAEM,KAAK,UAAU,YAAY,CAChC,IAAO,EACP,GAAG,IAA+B;IAElC,MAAM,OAAO,GAAkC,EAAE,CAAC;IAClD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,KAAK,GAAgC,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;YACxE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
@@ -263,7 +263,7 @@ The flip side is the usual one for a `*_BEING_*` hook: a handler that throws for
263
263
 
264
264
  `extras` is opaque by design. The DMS reads no key of it, validates nothing, and stores nothing — it carries the object from the caller of the provisioning flow to the handlers, and each handler writes what it recognises. The shape is a contract between that caller and that handler, one the DMS is deliberately not a party to, so a product can start collecting a new field without waiting on a DMS release.
265
265
 
266
- It fires once per tenant, when the tenant is created, and never again on a later start. The DMS fires it for the `default` tenant, on the start that creates it, once every `DATABASE_INITIALIZED` handler has finished, so a module's tables and settings are ready; that payload has no `userId`, since the `default` tenant has no owner until onboarding. A SaaS module such as **`dms-saas`** fires it for each workspace its signup flow creates.
266
+ It fires once per tenant, when the tenant is created, and never again on a later start once it has succeeded. The DMS fires it for the `default` tenant once every module has started, so a module's tables and settings are ready; that payload has no `userId`, since the `default` tenant has no owner until onboarding. Replicas sharing a new database elect a holder through a lease on the tenant's row, and the others serve meanwhile. A holder that stops renewing for `provisioningLease.staleAfterMs` is taken over, even if its handlers are still running. If that attempt fails, or its process dies, the next start or another replica runs every handler again, so a handler skips what it already wrote. A SaaS module such as **`dms-saas`** fires it for each workspace its signup flow creates.
267
267
 
268
268
  This is where a module writes the **default data** a tenant starts with — templates, folders, a sender, a demo history. Written once, that data belongs to the tenant: the module does not write it again on a later start, does not compare it with what members changed since, and does not wait for the tenant from `start()` or `DATABASE_INITIALIZED`.
269
269
 
@@ -79,7 +79,7 @@ export async function createUser(
79
79
  }
80
80
  ```
81
81
 
82
- To check a candidate password, call `testHash` on the loaded row. The mixin hashes the candidate with the stored salt and compares it against the stored hash.
82
+ To check a candidate password, call `testHashAsync` on the loaded row. The mixin hashes the candidate with the salt and the cost in the stored hash, on the thread pool, and compares the results.
83
83
 
84
84
  ```typescript
85
85
  import { HTTPResult } from "@antelopejs/interface-api";
@@ -93,13 +93,15 @@ export async function checkCredentials(
93
93
  password: string,
94
94
  ) {
95
95
  const user = await userModel.getByEmail(email.toLowerCase());
96
- if (!user || !user.testHash("password", password)) {
96
+ if (!user || !(await user.testHashAsync("password", password))) {
97
97
  throw new HTTPResult(UNAUTHORIZED, "error.invalid_credentials");
98
98
  }
99
99
  return user;
100
100
  }
101
101
  ```
102
102
 
103
+ A successful sign-in through `/auth/login` also writes the password again when `isHashOutdated("password")` reports an older hash on the row.
104
+
103
105
  Emails are stored trimmed and lowercased. `getByEmail` normalizes its argument itself; normalize with `normalizeEmail` (exported alongside `UserModel`) before writing one.
104
106
 
105
107
  ## Query Users with UserModel
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antelopejs/interface-dms",
3
- "version": "0.10.3",
3
+ "version": "0.10.4",
4
4
  "description": "Public AntelopeJS interfaces of the DMS: pages, components, permissions, tenancy, auth, notifications and HTML rendering.",
5
5
  "keywords": [
6
6
  "antelopejs",
@@ -52,7 +52,7 @@
52
52
  "@antelopejs/interface-core": ">=0.2.4 <1.0.0",
53
53
  "@antelopejs/interface-data-api": ">=0.5.0 <1.0.0",
54
54
  "@antelopejs/interface-database": ">=0.1.11 <1.0.0",
55
- "@antelopejs/interface-database-decorators": ">=0.1.10 <1.0.0",
55
+ "@antelopejs/interface-database-decorators": ">=0.1.12 <1.0.0",
56
56
  "@antelopejs/interface-file-storage": ">=0.1.4 <1.0.0"
57
57
  },
58
58
  "devDependencies": {
@@ -61,7 +61,7 @@
61
61
  "@antelopejs/interface-core": ">=0.2.4 <1.0.0",
62
62
  "@antelopejs/interface-data-api": ">=0.5.0 <1.0.0",
63
63
  "@antelopejs/interface-database": ">=0.1.11 <1.0.0",
64
- "@antelopejs/interface-database-decorators": ">=0.1.10 <1.0.0",
64
+ "@antelopejs/interface-database-decorators": ">=0.1.12 <1.0.0",
65
65
  "@antelopejs/interface-file-storage": ">=0.1.4 <1.0.0",
66
66
  "@types/node": "^24.0.0",
67
67
  "@types/randomstring": "^1.3.0",