nucleus-core-ts 0.9.960 → 0.9.962

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.
@@ -1816,7 +1816,7 @@ export declare const SYSTEM_TABLES: readonly [{
1816
1816
  }, {
1817
1817
  readonly name: "expires_at";
1818
1818
  readonly type: "timestamptz";
1819
- readonly notNull: true;
1819
+ readonly notNull: false;
1820
1820
  }, {
1821
1821
  readonly name: "revoked_at";
1822
1822
  readonly type: "timestamptz";
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Make "sessions that never expire" possible in the database, not just in code.
3
+ *
4
+ * A never-expiring session is a row with no expiry — that is what the words
5
+ * mean. `user_sessions.expires_at NOT NULL` refuses that row, so an install
6
+ * configured for it did not degrade: login returned 500 and nobody could sign
7
+ * in at all. The config said one thing and the schema made it impossible.
8
+ *
9
+ * This is not left to the schema push. drizzle-kit's model has carried this
10
+ * column as nullable for a long time while live databases carried NOT NULL, and
11
+ * the push reported "the database already matches the model" every boot — it
12
+ * does not reconcile nullability. A statement nobody generates is a statement
13
+ * nobody can allow.
14
+ *
15
+ * So it is asked for explicitly, and only by installs that need it:
16
+ *
17
+ * - Runs ONLY when the configured session lifetime resolves to `never`. An
18
+ * install with a normal lifetime keeps its NOT NULL, and should — the
19
+ * constraint is right for them.
20
+ * - Checks before it writes, so an install already relaxed does nothing and
21
+ * logs nothing on every subsequent boot.
22
+ * - Loosens, never tightens. It cannot lose a row or a value: every existing
23
+ * session keeps the expiry it has, the column simply stops refusing absence
24
+ * in future writes.
25
+ * - Never takes the app down. If it cannot run — no permission, no table — it
26
+ * says so and boot continues; the failure then shows up as the 500 it was
27
+ * meant to prevent, which is honest, rather than as a dead process.
28
+ */
29
+ type MinimalDb = {
30
+ execute: (query: unknown) => Promise<unknown>;
31
+ };
32
+ /** Only the two calls this makes, so any app logger satisfies it. */
33
+ type MinimalLogger = {
34
+ info: (message: string) => void;
35
+ warn: (message: string) => void;
36
+ };
37
+ export type RelaxSessionExpiryResult = {
38
+ action: 'skipped';
39
+ reason: 'lifetime-is-bounded' | 'unsafe-identifier';
40
+ } | {
41
+ action: 'already-nullable';
42
+ } | {
43
+ action: 'relaxed';
44
+ } | {
45
+ action: 'failed';
46
+ reason: string;
47
+ };
48
+ export declare function relaxSessionExpiryIfNever(params: {
49
+ db: MinimalDb;
50
+ sql: ((strings: TemplateStringsArray, ...values: unknown[]) => unknown) & {
51
+ raw: (query: string) => unknown;
52
+ };
53
+ schemaName: string;
54
+ tableName?: string;
55
+ /** Seconds, or `null` for a session that never expires. */
56
+ lifetimeSeconds: number | null;
57
+ logger?: MinimalLogger;
58
+ }): Promise<RelaxSessionExpiryResult>;
59
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nucleus-core-ts",
3
- "version": "0.9.960",
3
+ "version": "0.9.962",
4
4
  "description": "Production-ready, enterprise-grade TypeScript framework for building multi-tenant APIs",
5
5
  "author": "Hidayet Can Özcan <hidayetcan@gmail.com>",
6
6
  "license": "SEE LICENSE IN LICENSE",