@auth/drizzle-adapter 0.3.16 → 0.3.17

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/lib/pg.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../src/lib/pg.ts"],"names":[],"mappings":"AACA,OAAO,EAML,SAAS,EACT,UAAU,EACX,MAAM,qBAAqB,CAAA;AAE5B,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,qBAAqB,CAAA;AAElE,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoD9C;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAA;AAE3D,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,YAAY,CAAC,OAAO,UAAU,CAAC,EACvC,OAAO,uBAAmB,GACzB,OAAO,CAgKT"}
1
+ {"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../src/lib/pg.ts"],"names":[],"mappings":"AACA,OAAO,EAML,SAAS,EACT,UAAU,EACX,MAAM,qBAAqB,CAAA;AAE5B,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,qBAAqB,CAAA;AAGlE,wBAAgB,YAAY,CAAC,OAAO,EAAE,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoD9C;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAA;AAE3D,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,YAAY,CAAC,OAAO,UAAU,CAAC,EACvC,OAAO,uBAAmB,GACzB,OAAO,CA+IT"}
package/lib/pg.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { and, eq } from "drizzle-orm";
2
2
  import { timestamp, pgTable as defaultPgTableFn, text, primaryKey, integer, } from "drizzle-orm/pg-core";
3
+ import { stripUndefined } from "./utils";
3
4
  export function createTables(pgTable) {
4
5
  const users = pgTable("user", {
5
6
  id: text("id").notNull().primaryKey(),
@@ -103,24 +104,11 @@ export function pgDrizzleAdapter(client, tableFn = defaultPgTableFn) {
103
104
  .then((res) => res[0]);
104
105
  },
105
106
  async linkAccount(rawAccount) {
106
- const updatedAccount = await client
107
+ return stripUndefined(await client
107
108
  .insert(accounts)
108
109
  .values(rawAccount)
109
110
  .returning()
110
- .then((res) => res[0]);
111
- // Drizzle will return `null` for fields that are not defined.
112
- // However, the return type is expecting `undefined`.
113
- const account = {
114
- ...updatedAccount,
115
- access_token: updatedAccount.access_token ?? undefined,
116
- token_type: updatedAccount.token_type ?? undefined,
117
- id_token: updatedAccount.id_token ?? undefined,
118
- refresh_token: updatedAccount.refresh_token ?? undefined,
119
- scope: updatedAccount.scope ?? undefined,
120
- expires_at: updatedAccount.expires_at ?? undefined,
121
- session_state: updatedAccount.session_state ?? undefined,
122
- };
123
- return account;
111
+ .then((res) => res[0]));
124
112
  },
125
113
  async getUserByAccount(account) {
126
114
  const dbAccount = (await client
@@ -129,10 +117,7 @@ export function pgDrizzleAdapter(client, tableFn = defaultPgTableFn) {
129
117
  .where(and(eq(accounts.providerAccountId, account.providerAccountId), eq(accounts.provider, account.provider)))
130
118
  .leftJoin(users, eq(accounts.userId, users.id))
131
119
  .then((res) => res[0])) ?? null;
132
- if (!dbAccount) {
133
- return null;
134
- }
135
- return dbAccount.user;
120
+ return dbAccount?.user ?? null;
136
121
  },
137
122
  async deleteSession(sessionToken) {
138
123
  const session = await client
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../src/lib/sqlite.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,kBAAkB,EAClB,aAAa,EACd,MAAM,yBAAyB,CAAA;AAEhC,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,qBAAqB,CAAA;AAElE,wBAAgB,YAAY,CAAC,WAAW,EAAE,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoDtD;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAA;AAE3D,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,YAAY,CAAC,OAAO,kBAAkB,CAAC,EAC/C,OAAO,2BAAuB,GAC7B,OAAO,CA6JT"}
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../src/lib/sqlite.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,kBAAkB,EAClB,aAAa,EACd,MAAM,yBAAyB,CAAA;AAGhC,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,qBAAqB,CAAA;AAElE,wBAAgB,YAAY,CAAC,WAAW,EAAE,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoDtD;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAA;AAE3D,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,YAAY,CAAC,OAAO,kBAAkB,CAAC,EAC/C,OAAO,2BAAuB,GAC7B,OAAO,CA0IT"}
package/lib/sqlite.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { eq, and } from "drizzle-orm";
2
2
  import { integer, sqliteTable as defaultSqliteTableFn, text, primaryKey, } from "drizzle-orm/sqlite-core";
3
+ import { stripUndefined } from "./utils";
3
4
  export function createTables(sqliteTable) {
4
5
  const users = sqliteTable("user", {
5
6
  id: text("id").notNull().primaryKey(),
@@ -101,23 +102,7 @@ export function SQLiteDrizzleAdapter(client, tableFn = defaultSqliteTableFn) {
101
102
  return result ?? null;
102
103
  },
103
104
  async linkAccount(rawAccount) {
104
- const updatedAccount = await client
105
- .insert(accounts)
106
- .values(rawAccount)
107
- .returning()
108
- .get();
109
- const account = {
110
- ...updatedAccount,
111
- type: updatedAccount.type,
112
- access_token: updatedAccount.access_token ?? undefined,
113
- token_type: updatedAccount.token_type ?? undefined,
114
- id_token: updatedAccount.id_token ?? undefined,
115
- refresh_token: updatedAccount.refresh_token ?? undefined,
116
- scope: updatedAccount.scope ?? undefined,
117
- expires_at: updatedAccount.expires_at ?? undefined,
118
- session_state: updatedAccount.session_state ?? undefined,
119
- };
120
- return account;
105
+ return stripUndefined(await client.insert(accounts).values(rawAccount).returning().get());
121
106
  },
122
107
  async getUserByAccount(account) {
123
108
  const results = await client
@@ -173,7 +158,6 @@ export function SQLiteDrizzleAdapter(client, tableFn = defaultSqliteTableFn) {
173
158
  .delete(accounts)
174
159
  .where(and(eq(accounts.providerAccountId, account.providerAccountId), eq(accounts.provider, account.provider)))
175
160
  .run();
176
- return undefined;
177
161
  },
178
162
  };
179
163
  }
package/lib/utils.d.ts CHANGED
@@ -18,4 +18,9 @@ export interface MinimumSchema {
18
18
  export type SqlFlavorOptions = AnyMySqlDatabase | AnyPgDatabase | AnySQLiteDatabase;
19
19
  export type ClientFlavors<Flavor> = Flavor extends AnyMySqlDatabase ? MinimumSchema["mysql"] : Flavor extends AnyPgDatabase ? MinimumSchema["pg"] : Flavor extends AnySQLiteDatabase ? MinimumSchema["sqlite"] : never;
20
20
  export type TableFn<Flavor> = Flavor extends AnyMySqlDatabase ? MySqlTableFn : Flavor extends AnyPgDatabase ? PgTableFn : Flavor extends AnySQLiteDatabase ? SQLiteTableFn : AnySQLiteTable;
21
+ type NonNullableProps<T> = {
22
+ [P in keyof T]: null extends T[P] ? never : P;
23
+ }[keyof T];
24
+ export declare function stripUndefined<T>(obj: T): Pick<T, NonNullableProps<T>>;
25
+ export {};
21
26
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAC5E,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,SAAS,CAAA;AACxD,OAAO,KAAK,EAAE,aAAa,IAAI,WAAW,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,KAAK,EAAE,aAAa,IAAI,YAAY,EAAE,MAAM,aAAa,CAAA;AAEhE,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AACtD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AACrD,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AAEtE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAClD,EAAE,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACzC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;CACtD;AAED,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,aAAa,GACb,iBAAiB,CAAA;AAErB,MAAM,MAAM,aAAa,CAAC,MAAM,IAAI,MAAM,SAAS,gBAAgB,GAC/D,aAAa,CAAC,OAAO,CAAC,GACtB,MAAM,SAAS,aAAa,GAC1B,aAAa,CAAC,IAAI,CAAC,GACnB,MAAM,SAAS,iBAAiB,GAC9B,aAAa,CAAC,QAAQ,CAAC,GACvB,KAAK,CAAA;AAEb,MAAM,MAAM,OAAO,CAAC,MAAM,IAAI,MAAM,SAAS,gBAAgB,GACzD,YAAY,GACZ,MAAM,SAAS,aAAa,GAC1B,SAAS,GACT,MAAM,SAAS,iBAAiB,GAC9B,aAAa,GACb,cAAc,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAC5E,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,SAAS,CAAA;AACxD,OAAO,KAAK,EAAE,aAAa,IAAI,WAAW,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,KAAK,EAAE,aAAa,IAAI,YAAY,EAAE,MAAM,aAAa,CAAA;AAEhE,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AACtD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AACrD,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AAEtE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAClD,EAAE,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACzC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;CACtD;AAED,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,aAAa,GACb,iBAAiB,CAAA;AAErB,MAAM,MAAM,aAAa,CAAC,MAAM,IAAI,MAAM,SAAS,gBAAgB,GAC/D,aAAa,CAAC,OAAO,CAAC,GACtB,MAAM,SAAS,aAAa,GAC1B,aAAa,CAAC,IAAI,CAAC,GACnB,MAAM,SAAS,iBAAiB,GAC9B,aAAa,CAAC,QAAQ,CAAC,GACvB,KAAK,CAAA;AAEb,MAAM,MAAM,OAAO,CAAC,MAAM,IAAI,MAAM,SAAS,gBAAgB,GACzD,YAAY,GACZ,MAAM,SAAS,aAAa,GAC1B,SAAS,GACT,MAAM,SAAS,iBAAiB,GAC9B,aAAa,GACb,cAAc,CAAA;AAEtB,KAAK,gBAAgB,CAAC,CAAC,IAAI;KACxB,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC;CAC9C,CAAC,MAAM,CAAC,CAAC,CAAA;AAEV,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAItE"}
package/lib/utils.js CHANGED
@@ -1 +1,7 @@
1
- export {};
1
+ export function stripUndefined(obj) {
2
+ const result = {};
3
+ for (const key in obj)
4
+ if (obj[key] !== undefined)
5
+ result[key] = obj[key];
6
+ return result;
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@auth/drizzle-adapter",
3
- "version": "0.3.16",
3
+ "version": "0.3.17",
4
4
  "description": "Drizzle adapter for Auth.js.",
5
5
  "homepage": "https://authjs.dev",
6
6
  "repository": "https://github.com/nextauthjs/next-auth",
@@ -36,7 +36,7 @@
36
36
  "access": "public"
37
37
  },
38
38
  "dependencies": {
39
- "@auth/core": "0.22.0"
39
+ "@auth/core": "0.23.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@libsql/client": "0.4.0-pre.5",
package/src/lib/pg.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  } from "drizzle-orm/pg-core"
11
11
 
12
12
  import type { Adapter, AdapterAccount } from "@auth/core/adapters"
13
+ import { stripUndefined } from "./utils"
13
14
 
14
15
  export function createTables(pgTable: PgTableFn) {
15
16
  const users = pgTable("user", {
@@ -135,26 +136,13 @@ export function pgDrizzleAdapter(
135
136
  .then((res) => res[0])
136
137
  },
137
138
  async linkAccount(rawAccount) {
138
- const updatedAccount = await client
139
- .insert(accounts)
140
- .values(rawAccount)
141
- .returning()
142
- .then((res) => res[0])
143
-
144
- // Drizzle will return `null` for fields that are not defined.
145
- // However, the return type is expecting `undefined`.
146
- const account = {
147
- ...updatedAccount,
148
- access_token: updatedAccount.access_token ?? undefined,
149
- token_type: updatedAccount.token_type ?? undefined,
150
- id_token: updatedAccount.id_token ?? undefined,
151
- refresh_token: updatedAccount.refresh_token ?? undefined,
152
- scope: updatedAccount.scope ?? undefined,
153
- expires_at: updatedAccount.expires_at ?? undefined,
154
- session_state: updatedAccount.session_state ?? undefined,
155
- }
156
-
157
- return account
139
+ return stripUndefined(
140
+ await client
141
+ .insert(accounts)
142
+ .values(rawAccount)
143
+ .returning()
144
+ .then((res) => res[0])
145
+ )
158
146
  },
159
147
  async getUserByAccount(account) {
160
148
  const dbAccount =
@@ -170,11 +158,7 @@ export function pgDrizzleAdapter(
170
158
  .leftJoin(users, eq(accounts.userId, users.id))
171
159
  .then((res) => res[0])) ?? null
172
160
 
173
- if (!dbAccount) {
174
- return null
175
- }
176
-
177
- return dbAccount.user
161
+ return dbAccount?.user ?? null
178
162
  },
179
163
  async deleteSession(sessionToken) {
180
164
  const session = await client
package/src/lib/sqlite.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  BaseSQLiteDatabase,
8
8
  SQLiteTableFn,
9
9
  } from "drizzle-orm/sqlite-core"
10
+ import { stripUndefined } from "./utils"
10
11
 
11
12
  import type { Adapter, AdapterAccount } from "@auth/core/adapters"
12
13
 
@@ -132,25 +133,9 @@ export function SQLiteDrizzleAdapter(
132
133
  return result ?? null
133
134
  },
134
135
  async linkAccount(rawAccount) {
135
- const updatedAccount = await client
136
- .insert(accounts)
137
- .values(rawAccount)
138
- .returning()
139
- .get()
140
-
141
- const account: AdapterAccount = {
142
- ...updatedAccount,
143
- type: updatedAccount.type,
144
- access_token: updatedAccount.access_token ?? undefined,
145
- token_type: updatedAccount.token_type ?? undefined,
146
- id_token: updatedAccount.id_token ?? undefined,
147
- refresh_token: updatedAccount.refresh_token ?? undefined,
148
- scope: updatedAccount.scope ?? undefined,
149
- expires_at: updatedAccount.expires_at ?? undefined,
150
- session_state: updatedAccount.session_state ?? undefined,
151
- }
152
-
153
- return account
136
+ return stripUndefined(
137
+ await client.insert(accounts).values(rawAccount).returning().get()
138
+ )
154
139
  },
155
140
  async getUserByAccount(account) {
156
141
  const results = await client
@@ -166,10 +151,9 @@ export function SQLiteDrizzleAdapter(
166
151
  .get()
167
152
 
168
153
  if (!results) {
169
- return null;
154
+ return null
170
155
  }
171
156
  return Promise.resolve(results).then((results) => results.user)
172
-
173
157
  },
174
158
  async deleteSession(sessionToken) {
175
159
  const result = await client
@@ -222,8 +206,6 @@ export function SQLiteDrizzleAdapter(
222
206
  )
223
207
  )
224
208
  .run()
225
-
226
- return undefined
227
209
  },
228
210
  }
229
211
  }
package/src/lib/utils.ts CHANGED
@@ -39,3 +39,13 @@ export type TableFn<Flavor> = Flavor extends AnyMySqlDatabase
39
39
  : Flavor extends AnySQLiteDatabase
40
40
  ? SQLiteTableFn
41
41
  : AnySQLiteTable
42
+
43
+ type NonNullableProps<T> = {
44
+ [P in keyof T]: null extends T[P] ? never : P
45
+ }[keyof T]
46
+
47
+ export function stripUndefined<T>(obj: T): Pick<T, NonNullableProps<T>> {
48
+ const result = {} as T
49
+ for (const key in obj) if (obj[key] !== undefined) result[key] = obj[key]
50
+ return result
51
+ }