tina4-nodejs 3.12.1 → 3.12.2

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/CLAUDE.md CHANGED
@@ -1,4 +1,4 @@
1
- # CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.11.0)
1
+ # CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.12.2)
2
2
 
3
3
  > This file helps AI assistants (Claude, Copilot, Cursor, etc.) understand and work on this codebase effectively.
4
4
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
 
5
5
 
6
- "version": "3.12.1",
6
+ "version": "3.12.2",
7
7
 
8
8
  "type": "module",
9
9
  "description": "Tina4 for Node.js/TypeScript — 54 built-in features, zero dependencies",
@@ -23,6 +23,66 @@ function requireFirebird(): any {
23
23
  }
24
24
  }
25
25
 
26
+ // Detects a Windows drive-letter prefix like "C:/" or "C:\". The leading-slash
27
+ // variant ("/C:/...") shows up after URL parsing strips one slash off
28
+ // "firebird://host:port/C:/...".
29
+ const WIN_DRIVE_RE = /^\/?[A-Za-z]:[/\\]/;
30
+
31
+ /**
32
+ * Turn a URL path component into a Firebird database identifier.
33
+ *
34
+ * Firebird is the awkward one — it needs either an absolute file path on the
35
+ * server, a Windows drive-letter path, or an alias name. The classic URI form
36
+ * uses a double-slash to keep the leading "/" of an absolute path through
37
+ * URL parsing:
38
+ *
39
+ * firebird://host:port//firebird/data/app.fdb -> /firebird/data/app.fdb
40
+ *
41
+ * But that double slash is unintuitive to anyone used to the way
42
+ * postgres / mysql / mssql encode the database name. We accept five
43
+ * equivalent forms and normalise all of them:
44
+ *
45
+ * - `//abs/path/db.fdb` -> `/abs/path/db.fdb` (classic double-slash)
46
+ * - `/abs/path/db.fdb` -> `/abs/path/db.fdb` (single-slash, what most people type)
47
+ * - `/C:/Data/db.fdb` -> `C:/Data/db.fdb` (Windows, leading URL slash dropped)
48
+ * - `/C%3A/Data/db.fdb` -> `C:/Data/db.fdb` (Windows with URL-encoded colon)
49
+ * - `/employee` -> `employee` (alias — single token)
50
+ *
51
+ * Aliases are detected as the leftover case: a single token with no
52
+ * slashes. Anything path-like is kept as a path.
53
+ */
54
+ export function normalizeFirebirdDbIdentifier(rawPath: string): string {
55
+ let decoded = decodeURIComponent(rawPath);
56
+
57
+ // Classic double-slash form: //abs/path -> /abs/path
58
+ if (decoded.startsWith("//")) {
59
+ decoded = decoded.slice(1);
60
+ }
61
+
62
+ // Windows drive-letter — drop the URL-introduced leading slash.
63
+ // /C:/Data/db.fdb -> C:/Data/db.fdb
64
+ if (WIN_DRIVE_RE.test(decoded)) {
65
+ if (decoded.startsWith("/")) {
66
+ decoded = decoded.slice(1);
67
+ }
68
+ return decoded;
69
+ }
70
+
71
+ // Look at the content after stripping the leading slash. If it's a single
72
+ // token with no separators, it's a Firebird alias — return WITHOUT the
73
+ // leading slash (the alias name itself is the identifier).
74
+ const body = decoded.startsWith("/") ? decoded.slice(1) : decoded;
75
+ if (body && !body.includes("/") && !body.includes("\\")) {
76
+ return body;
77
+ }
78
+
79
+ // Otherwise it's a file path. If it already has a leading slash, keep it.
80
+ // If it's a relative-looking path (slash-separated but no leading "/")
81
+ // promote it to absolute — Firebird needs absolute paths and we don't know
82
+ // the server's CWD anyway.
83
+ return decoded.startsWith("/") ? decoded : "/" + decoded;
84
+ }
85
+
26
86
  export interface FirebirdConfig {
27
87
  host?: string;
28
88
  port?: number;
@@ -69,6 +129,21 @@ export class FirebirdAdapter implements DatabaseAdapter {
69
129
  };
70
130
  }
71
131
 
132
+ // Firebird database identifier resolution — two layers:
133
+ //
134
+ // 1. `TINA4_DATABASE_FIREBIRD_PATH` env override wins if set. Useful for
135
+ // Windows users with raw backslash paths (no URL encoding required)
136
+ // and for ops setups that keep server URL and DB location in separate
137
+ // config layers.
138
+ // 2. Otherwise normalise whatever the URL or config supplied — accepts
139
+ // every sensible variant (single/double slash, drive letter, alias).
140
+ const envOverride = process.env.TINA4_DATABASE_FIREBIRD_PATH;
141
+ if (envOverride && envOverride.length > 0) {
142
+ fbConfig.database = envOverride;
143
+ } else if (typeof fbConfig.database === "string" && fbConfig.database.length > 0) {
144
+ fbConfig.database = normalizeFirebirdDbIdentifier(fbConfig.database);
145
+ }
146
+
72
147
  await new Promise<void>((resolve, reject) => {
73
148
  fb.attach(fbConfig, (err: Error | null, db: any) => {
74
149
  if (err) reject(err);
@@ -82,6 +157,8 @@ export class FirebirdAdapter implements DatabaseAdapter {
82
157
 
83
158
  private parseUrl(url: string): { host?: string; port?: number; user?: string; password?: string; database?: string } {
84
159
  // firebird://user:pass@host:port/path/to/db.fdb
160
+ // The path part after the host is normalised by normalizeFirebirdDbIdentifier()
161
+ // in connect(); here we just preserve it (with the leading "/" the regex strips).
85
162
  const match = url.match(/firebird:\/\/(?:([^:]+):([^@]+)@)?([^:/]+)(?::(\d+))?\/(.*)/);
86
163
  if (match) {
87
164
  return {
@@ -54,7 +54,7 @@ export { MysqlAdapter } from "./adapters/mysql.js";
54
54
  export type { MysqlConfig } from "./adapters/mysql.js";
55
55
  export { MssqlAdapter } from "./adapters/mssql.js";
56
56
  export type { MssqlConfig } from "./adapters/mssql.js";
57
- export { FirebirdAdapter } from "./adapters/firebird.js";
57
+ export { FirebirdAdapter, normalizeFirebirdDbIdentifier } from "./adapters/firebird.js";
58
58
  export type { FirebirdConfig } from "./adapters/firebird.js";
59
59
  export { MongodbAdapter } from "./adapters/mongodb.js";
60
60
  export type { MongoConfig } from "./adapters/mongodb.js";