@niledatabase/server 4.0.0-alpha.1 → 4.0.0-alpha.11

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
@@ -1,39 +1,83 @@
1
- # @niledatabase/server
1
+ <p align="center">
2
+ <img width="1434" alt="Screen Shot 2024-09-18 at 9 20 04 AM" src="https://github.com/user-attachments/assets/20585883-5cdc-4f15-93d3-dc150e87bc11">
3
+ </p>
2
4
 
3
- Consolidates the API and DB for working with Nile.
5
+ ---
4
6
 
5
- ## Usage
7
+ # Nile's Server-Side SDK
6
8
 
7
- ### With configuration object
9
+ This package (`@niledatabase/server`) is part of [Nile's Javascript SDK](https://github.com/niledatabase/nile-js/tree/main).
8
10
 
9
- ```ts
10
- import Nile from '@niledatabase/server';
11
+ Nile's server-side Javascript package provides:
11
12
 
12
- const nile = await Nile({
13
- user: 'username',
14
- password: 'password',
15
- });
13
+ - 🔐 Methods for working with Nile's user and tenant APIs
14
+ - 🔑 Generated routes for authentication
15
+ - 🔍 SQL query execution with tenant and user context management
16
16
 
17
- await nile.api.createTenant({ name: 'name' });
17
+ **Nile is a Postgres platform that decouples storage from compute, virtualizes tenants, and supports vertical and horizontal scaling globally to ship B2B applications fast while being safe with limitless scale.** All B2B applications are multi-tenant. A tenant/customer is primarily a company, an organization, or a workspace in your product that contains a group of users. A B2B application provides services to multiple tenants. Tenant is the basic building block of all B2B applications.
18
18
 
19
- await nile.db.query('select * from todo');
19
+ ## Usage
20
+
21
+ ### Installation
22
+
23
+ ```ts
24
+ npm install @niledatabase/server
20
25
  ```
21
26
 
22
- ### With env vars
27
+ ### Initialize SDK with env vars
28
+
29
+ The recommended way to initialize Nile SDK is with `.env` file. You can copy the environment variables from [Nile console](https://console.thenile.dev). It should look similar to this:
23
30
 
24
31
  ```bash
25
32
  NILEDB_USER=username
26
33
  NILEDB_PASSWORD=password
34
+ NILEDB_API_URL=https://us-west-2.api.thenile.dev/v2/databases/DBID
35
+ NILEDB_POSTGRES_URL=postgres://us-west-2.db.thenile.dev:5432/dbname
27
36
  ```
28
37
 
29
38
  ```ts
30
39
  import Nile from '@niledatabase/server';
31
40
 
32
41
  const nile = await Nile();
42
+ ```
43
+
44
+ ### Initialize SDK with configuration object
33
45
 
34
- await nile.api.createTenant({ name: 'name' });
46
+ ```ts
47
+ import Nile from '@niledatabase/server';
48
+
49
+ const nile = await Nile({
50
+ user: 'username',
51
+ password: 'password',
52
+ debug: true
53
+ });
54
+ ```
35
55
 
36
- await nile.db.query('select * from todo');
56
+ ### Call Nile APIs
57
+
58
+ ```typescript
59
+ const tenant = await nile.api.tenants.createTenant(tenantName);
60
+ if (tenant instanceof Response) {
61
+ const err = await tenant.text()
62
+ console.log("ERROR creating tenant: ", tenant, err);
63
+ return { message: "Error creating tenant" };
64
+ }
65
+ nile.tenant_id = tenant.id // set context
66
+ // Get tenant name doesn't need any input parameters
67
+ // because it uses the tenant ID and user token from the context
68
+ const checkTenant = await tenantNile.api.tenants.getTenant();
69
+ ```
70
+
71
+ ### Query the database
72
+
73
+ ```typescript
74
+ nile.tenant_id = tenant.id // set context
75
+
76
+ const todos = await nile.db
77
+ .query("select * from todos order by title")
78
+ .catch((e: Error) => {
79
+ console.error(e);
80
+ }); // no need for where clause if you previously set Nile context
37
81
  ```
38
82
 
39
83
  ## Initialization
@@ -59,3 +103,9 @@ Configuration passed to `Server` takes precedence over `.env` vars.
59
103
  | api.cookieKey | `string` | | Key for API cookie. Default is `token`. |
60
104
  | api.token | `string` | NILEDB_TOKEN | Token for API authentication. Mostly for debugging. |
61
105
  | debug | `boolean` | | Flag for enabling debug logging. |
106
+
107
+ ## Learn more
108
+
109
+ - You can learn more about Nile and the SDK in [https://thenile.dev/docs]
110
+ - You can find detailed code examples in [our main repo](https://github.com/niledatabase/niledatabase)
111
+ - Nile SDK interacts with APIs in Nile Auth service. You can learn more about it in the [repository](https://github.com/niledatabase/nile-auth) and the [docs](https://thenile.dev/docs/auth)
package/dist/index.d.mts CHANGED
@@ -1,34 +1,47 @@
1
1
  import pg, { PoolConfig, PoolClient } from 'pg';
2
2
 
3
- type ConfigRoutes = {
4
- SIGNIN?: string;
5
- SESSION?: string;
6
- PROVIDERS?: string;
7
- CSRF?: string;
8
- CALLBACK?: string;
9
- SIGNOUT?: string;
10
- ME?: string;
11
- ERROR?: string;
12
- TENANTS?: string;
13
- TENANT_USERS?: string;
14
- USERS?: string;
3
+ type Routes = {
4
+ SIGNIN: string;
5
+ SESSION: string;
6
+ PROVIDERS: string;
7
+ CSRF: string;
8
+ CALLBACK: string;
9
+ SIGNOUT: string;
10
+ ERROR: string;
11
+ ME: string;
12
+ USERS: string;
13
+ TENANTS: string;
14
+ TENANT: string;
15
+ TENANT_USER: string;
16
+ TENANT_USERS: string;
17
+ SIGNUP: string;
18
+ VERIFY_REQUEST: string;
19
+ PASSWORD_RESET: string;
20
+ LOG: string;
15
21
  };
22
+
16
23
  type ApiParams = {
17
24
  basePath?: string | undefined;
18
25
  cookieKey?: string;
19
26
  token?: string | undefined;
20
27
  callbackUrl?: string | undefined;
28
+ routes?: Partial<Routes>;
29
+ routePrefix?: string | undefined;
30
+ secureCookies?: boolean;
21
31
  };
22
32
  declare class ApiConfig {
23
33
  cookieKey?: string;
24
34
  basePath?: string | undefined;
35
+ routes?: Partial<Routes>;
36
+ routePrefix?: string;
37
+ secureCookies?: boolean;
25
38
  /**
26
39
  * The client side callback url. Defaults to nothing (so nile.origin will be it), but in the cases of x-origin, you want to set this explicitly to be sure nile-auth does the right thing
27
40
  * If this is set, any `callbackUrl` from the client will be ignored.
28
41
  */
29
42
  callbackUrl?: string;
30
43
  private _token?;
31
- constructor({ basePath, cookieKey, token, callbackUrl }: ApiParams);
44
+ constructor(config?: ServerConfig, logger?: string);
32
45
  get token(): string | undefined;
33
46
  set token(value: string | undefined);
34
47
  }
@@ -37,10 +50,7 @@ declare class Config {
37
50
  password: string;
38
51
  databaseId: string;
39
52
  databaseName: string;
40
- routePrefix?: string;
41
- routes?: ConfigRoutes;
42
53
  logger?: LoggerType;
43
- secureCookies?: boolean | undefined;
44
54
  debug: boolean;
45
55
  db: NilePoolConfig;
46
56
  api: ApiConfig;
@@ -76,7 +86,6 @@ type ServerConfig = {
76
86
  userId?: string | null | undefined;
77
87
  debug?: boolean;
78
88
  configureUrl?: string;
79
- secureCookies?: boolean;
80
89
  db?: NilePoolConfig;
81
90
  api?: ApiParams;
82
91
  logger?: LoggerType;
@@ -157,26 +166,6 @@ type ActiveSession = {
157
166
  };
158
167
  };
159
168
 
160
- type Routes = {
161
- SIGNIN: string;
162
- SESSION: string;
163
- PROVIDERS: string;
164
- CSRF: string;
165
- CALLBACK: string;
166
- SIGNOUT: string;
167
- ERROR: string;
168
- ME: string;
169
- USERS: string;
170
- TENANTS: string;
171
- TENANT: string;
172
- TENANT_USER: string;
173
- TENANT_USERS: string;
174
- SIGNUP: string;
175
- VERIFY_REQUEST: string;
176
- PASSWORD_RESET: string;
177
- LOG: string;
178
- };
179
-
180
169
  interface NileBody<R, B> {
181
170
  readonly body: ReadableStream<Uint8Array> | null | B;
182
171
  readonly bodyUsed: boolean;
package/dist/index.d.ts CHANGED
@@ -1,34 +1,47 @@
1
1
  import pg, { PoolConfig, PoolClient } from 'pg';
2
2
 
3
- type ConfigRoutes = {
4
- SIGNIN?: string;
5
- SESSION?: string;
6
- PROVIDERS?: string;
7
- CSRF?: string;
8
- CALLBACK?: string;
9
- SIGNOUT?: string;
10
- ME?: string;
11
- ERROR?: string;
12
- TENANTS?: string;
13
- TENANT_USERS?: string;
14
- USERS?: string;
3
+ type Routes = {
4
+ SIGNIN: string;
5
+ SESSION: string;
6
+ PROVIDERS: string;
7
+ CSRF: string;
8
+ CALLBACK: string;
9
+ SIGNOUT: string;
10
+ ERROR: string;
11
+ ME: string;
12
+ USERS: string;
13
+ TENANTS: string;
14
+ TENANT: string;
15
+ TENANT_USER: string;
16
+ TENANT_USERS: string;
17
+ SIGNUP: string;
18
+ VERIFY_REQUEST: string;
19
+ PASSWORD_RESET: string;
20
+ LOG: string;
15
21
  };
22
+
16
23
  type ApiParams = {
17
24
  basePath?: string | undefined;
18
25
  cookieKey?: string;
19
26
  token?: string | undefined;
20
27
  callbackUrl?: string | undefined;
28
+ routes?: Partial<Routes>;
29
+ routePrefix?: string | undefined;
30
+ secureCookies?: boolean;
21
31
  };
22
32
  declare class ApiConfig {
23
33
  cookieKey?: string;
24
34
  basePath?: string | undefined;
35
+ routes?: Partial<Routes>;
36
+ routePrefix?: string;
37
+ secureCookies?: boolean;
25
38
  /**
26
39
  * The client side callback url. Defaults to nothing (so nile.origin will be it), but in the cases of x-origin, you want to set this explicitly to be sure nile-auth does the right thing
27
40
  * If this is set, any `callbackUrl` from the client will be ignored.
28
41
  */
29
42
  callbackUrl?: string;
30
43
  private _token?;
31
- constructor({ basePath, cookieKey, token, callbackUrl }: ApiParams);
44
+ constructor(config?: ServerConfig, logger?: string);
32
45
  get token(): string | undefined;
33
46
  set token(value: string | undefined);
34
47
  }
@@ -37,10 +50,7 @@ declare class Config {
37
50
  password: string;
38
51
  databaseId: string;
39
52
  databaseName: string;
40
- routePrefix?: string;
41
- routes?: ConfigRoutes;
42
53
  logger?: LoggerType;
43
- secureCookies?: boolean | undefined;
44
54
  debug: boolean;
45
55
  db: NilePoolConfig;
46
56
  api: ApiConfig;
@@ -76,7 +86,6 @@ type ServerConfig = {
76
86
  userId?: string | null | undefined;
77
87
  debug?: boolean;
78
88
  configureUrl?: string;
79
- secureCookies?: boolean;
80
89
  db?: NilePoolConfig;
81
90
  api?: ApiParams;
82
91
  logger?: LoggerType;
@@ -157,26 +166,6 @@ type ActiveSession = {
157
166
  };
158
167
  };
159
168
 
160
- type Routes = {
161
- SIGNIN: string;
162
- SESSION: string;
163
- PROVIDERS: string;
164
- CSRF: string;
165
- CALLBACK: string;
166
- SIGNOUT: string;
167
- ERROR: string;
168
- ME: string;
169
- USERS: string;
170
- TENANTS: string;
171
- TENANT: string;
172
- TENANT_USER: string;
173
- TENANT_USERS: string;
174
- SIGNUP: string;
175
- VERIFY_REQUEST: string;
176
- PASSWORD_RESET: string;
177
- LOG: string;
178
- };
179
-
180
169
  interface NileBody<R, B> {
181
170
  readonly body: ReadableStream<Uint8Array> | null | B;
182
171
  readonly bodyUsed: boolean;
package/dist/index.js CHANGED
@@ -92,8 +92,8 @@ async function request(url, _init, config) {
92
92
  String(request2.headers.get(X_NILE_TENANT))
93
93
  );
94
94
  }
95
- if ("secureCookies" in config && config.secureCookies != null) {
96
- updatedHeaders.set(X_NILE_SECURECOOKIES, String(config.secureCookies));
95
+ if (config.api.secureCookies != null) {
96
+ updatedHeaders.set(X_NILE_SECURECOOKIES, String(config.api.secureCookies));
97
97
  }
98
98
  updatedHeaders.set("host", requestUrl.host);
99
99
  if (config.api.callbackUrl) {
@@ -184,7 +184,7 @@ var getSecureCookies = (cfg) => {
184
184
  if (stringCheck(process.env.NILEDB_SECURECOOKIES)) {
185
185
  return Boolean(process.env.NILEDB_SECURECOOKIES);
186
186
  }
187
- return config?.secureCookies;
187
+ return config?.api?.secureCookies;
188
188
  };
189
189
  var getDatabaseId = (cfg) => {
190
190
  const { config, logger } = cfg;
@@ -308,6 +308,19 @@ var getTenantId = (cfg) => {
308
308
  }
309
309
  return null;
310
310
  };
311
+ var getCookieKey = (cfg) => {
312
+ const { config, logger } = cfg;
313
+ const { info } = Logger(config, "[cookieKey]");
314
+ if (stringCheck(config?.api?.cookieKey)) {
315
+ logger && info(`${logger}[config] ${config?.api?.cookieKey}`);
316
+ return String(config?.api?.cookieKey);
317
+ }
318
+ if (stringCheck(process.env.NILEDB_COOKIE_KEY)) {
319
+ logger && info(`${logger}[NILEDB_COOKIE_KEY] ${process.env.NILEDB_COOKIE_KEY}`);
320
+ return String(process.env.NILEDB_COOKIE_KEY);
321
+ }
322
+ return "token";
323
+ };
311
324
  var getBasePath = (cfg) => {
312
325
  const { config, logger } = cfg;
313
326
  const { warn, info, error } = Logger(config, "[basePath]");
@@ -410,17 +423,24 @@ var stringCheck = (str) => {
410
423
  var ApiConfig = class {
411
424
  cookieKey;
412
425
  basePath;
426
+ routes;
427
+ routePrefix;
428
+ secureCookies;
413
429
  /**
414
430
  * The client side callback url. Defaults to nothing (so nile.origin will be it), but in the cases of x-origin, you want to set this explicitly to be sure nile-auth does the right thing
415
431
  * If this is set, any `callbackUrl` from the client will be ignored.
416
432
  */
417
433
  callbackUrl;
418
434
  _token;
419
- constructor({ basePath, cookieKey, token, callbackUrl }) {
420
- this.basePath = basePath;
421
- this.cookieKey = cookieKey;
422
- this.callbackUrl = callbackUrl;
423
- this._token = token;
435
+ constructor(config, logger) {
436
+ const envVarConfig = { config, logger };
437
+ this.cookieKey = getCookieKey(envVarConfig);
438
+ this._token = getToken(envVarConfig);
439
+ this.callbackUrl = getCallbackUrl(envVarConfig);
440
+ this.secureCookies = getSecureCookies(envVarConfig);
441
+ this.basePath = getBasePath(envVarConfig);
442
+ this.routes = config?.api?.routes;
443
+ this.routePrefix = config?.api?.routePrefix;
424
444
  }
425
445
  get token() {
426
446
  return this._token;
@@ -434,10 +454,7 @@ var Config = class {
434
454
  password;
435
455
  databaseId;
436
456
  databaseName;
437
- routePrefix;
438
- routes;
439
457
  logger;
440
- secureCookies;
441
458
  debug;
442
459
  db;
443
460
  api;
@@ -472,23 +489,15 @@ var Config = class {
472
489
  );
473
490
  }
474
491
  }
475
- this.secureCookies = getSecureCookies(envVarConfig);
476
492
  this.databaseId = getDatabaseId(envVarConfig);
477
493
  this.databaseName = getDatabaseName(envVarConfig);
478
494
  this._tenantId = getTenantId(envVarConfig);
479
495
  this.debug = Boolean(config?.debug);
480
496
  this._userId = config?.userId;
481
- const callbackUrl = config?.api?.callbackUrl ?? getCallbackUrl(envVarConfig);
482
- const basePath = getBasePath(envVarConfig);
483
497
  const { host, port, ...dbConfig } = config?.db ?? {};
484
498
  const configuredHost = host ?? getDbHost(envVarConfig);
485
499
  const configuredPort = port ?? getDbPort(envVarConfig);
486
- this.api = new ApiConfig({
487
- basePath,
488
- cookieKey: config?.api?.cookieKey ?? "token",
489
- token: getToken({ config }),
490
- callbackUrl
491
- });
500
+ this.api = new ApiConfig(config, logger);
492
501
  this.db = {
493
502
  user: this.user,
494
503
  password: this.password,
@@ -506,18 +515,12 @@ var Config = class {
506
515
  config
507
516
  };
508
517
  const { host, port, ...dbConfig } = config.db ?? {};
509
- const callbackUrl = config?.api?.callbackUrl ?? getCallbackUrl(envVarConfig);
510
518
  let configuredHost = host ?? getDbHost(envVarConfig);
511
519
  const configuredPort = port ?? getDbPort(envVarConfig);
512
520
  let basePath = getBasePath(envVarConfig);
513
521
  if (configuredHost && this.databaseName && this.databaseId && basePath) {
514
522
  info("Already configured, aborting fetch");
515
- this.api = new ApiConfig({
516
- basePath,
517
- cookieKey: config?.api?.cookieKey ?? "token",
518
- token: getToken({ config }),
519
- callbackUrl
520
- });
523
+ this.api = new ApiConfig(config);
521
524
  this.db = {
522
525
  user: this.user,
523
526
  password: this.password,
@@ -602,12 +605,7 @@ var Config = class {
602
605
  configuredHost = dburl.hostname;
603
606
  }
604
607
  }
605
- this.api = new ApiConfig({
606
- basePath,
607
- cookieKey: config?.api?.cookieKey ?? "token",
608
- token: getToken({ config }),
609
- callbackUrl
610
- });
608
+ this.api = new ApiConfig(config);
611
609
  this.db = {
612
610
  user: this.user,
613
611
  password: this.password,
@@ -1008,8 +1006,8 @@ function makeBasicHeaders(config, opts) {
1008
1006
  headers.set("Authorization", `Bearer ${getToken({ config })}`);
1009
1007
  }
1010
1008
  }
1011
- if ("secureCookies" in config && config.secureCookies != null) {
1012
- headers.set(X_NILE_SECURECOOKIES, String(config.secureCookies));
1009
+ if (config && config.api.secureCookies != null) {
1010
+ headers.set(X_NILE_SECURECOOKIES, String(config.api.secureCookies));
1013
1011
  }
1014
1012
  return headers;
1015
1013
  }
@@ -1536,11 +1534,7 @@ function matches12(configRoutes, request2) {
1536
1534
  // src/api/routes/auth/password-reset.ts
1537
1535
  var key10 = "PASSWORD_RESET";
1538
1536
  async function route13(req, config) {
1539
- let url = proxyRoutes(config)[key10];
1540
- const { searchParams } = new URL(req.url);
1541
- if (searchParams.size > 0) {
1542
- url = `${url}?${searchParams.toString()}`;
1543
- }
1537
+ const url = proxyRoutes(config)[key10];
1544
1538
  const res = await request(
1545
1539
  url,
1546
1540
  {
@@ -1892,7 +1886,7 @@ var Requester = class extends Config {
1892
1886
  var ORIGIN = "https://us-west-2.api.dev.thenile.dev";
1893
1887
  function serverLogin(config, handlers) {
1894
1888
  const { info, error, debug } = Logger(config, "[server side login]");
1895
- const routes = appRoutes(config.routePrefix);
1889
+ const routes = appRoutes(config.api.routePrefix);
1896
1890
  return async function login({
1897
1891
  email,
1898
1892
  password
@@ -2226,8 +2220,8 @@ var Api = class {
2226
2220
  this.users = new Users(config);
2227
2221
  this.tenants = new Tenants(config);
2228
2222
  this.routes = {
2229
- ...appRoutes(config?.routePrefix),
2230
- ...config?.routes
2223
+ ...appRoutes(config?.api.routePrefix),
2224
+ ...config?.api.routes
2231
2225
  };
2232
2226
  this.handlers = Handlers(this.routes, config);
2233
2227
  this.paths = {