This repository has been archived by the owner on Jan 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 478
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update README.md Update startAsync.ts lint fix fixup tests Split up Publish API Refactor API Refactor Update getPublishExpConfigAsync.ts
- Loading branch information
Showing
53 changed files
with
1,150 additions
and
1,010 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
# api [![CircleCI](https://circleci.com/gh/expo/api.svg?style=svg)](https://circleci.com/gh/expo/api) | ||
# @expo/api | ||
|
||
A module for interacting with the expo.io API. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import { fs } from 'memfs'; | ||
module.exports = fs; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const os = jest.requireActual('os'); | ||
|
||
os.homedir = jest.fn(() => '/home'); | ||
|
||
module.exports = os; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
jest.mock('fs'); | ||
jest.mock('os'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import FormData from 'form-data'; | ||
|
||
import ApiV2, { ApiV2ClientOptions } from './ApiV2'; | ||
|
||
export type S3AssetMetadata = | ||
| { | ||
exists: true; | ||
lastModified: Date; | ||
contentLength: number; | ||
contentType: string; | ||
} | ||
| { | ||
exists: false; | ||
}; | ||
|
||
export async function getMetadataAsync( | ||
user: ApiV2ClientOptions, | ||
{ keys }: { keys: string[] } | ||
): Promise<Record<string, S3AssetMetadata>> { | ||
const { metadata } = await ApiV2.clientForUser(user).postAsync('assets/metadata', { | ||
keys, | ||
}); | ||
return metadata; | ||
} | ||
|
||
export async function uploadAsync(user: ApiV2ClientOptions, data: FormData): Promise<unknown> { | ||
return await ApiV2.clientForUser(user).uploadFormDataAsync('assets/upload', data); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
import assert from 'assert'; | ||
|
||
import ApiV2, { ApiV2ClientOptions } from './ApiV2'; | ||
import { AuthError } from './utils/errors'; | ||
|
||
export type User = { | ||
kind: 'user'; | ||
// required | ||
username: string; | ||
nickname: string; | ||
userId: string; | ||
picture: string; | ||
// optional | ||
email?: string; | ||
emailVerified?: boolean; | ||
givenName?: string; | ||
familyName?: string; | ||
userMetadata: { | ||
onboarded: boolean; | ||
legacy?: boolean; | ||
}; | ||
// auth methods | ||
currentConnection: ConnectionType; | ||
sessionSecret?: string; | ||
accessToken?: string; | ||
}; | ||
// note: user-token isn't listed here because it's a non-persistent pre-authenticated method | ||
export type LoginType = 'user-pass' | 'facebook' | 'google' | 'github'; | ||
|
||
export type RobotUser = { | ||
kind: 'robot'; | ||
// required | ||
userId: string; | ||
username: string; // backwards compatible to show in current UI -- based on given name or placeholder | ||
// optional | ||
givenName?: string; | ||
// auth methods | ||
currentConnection: ConnectionType; | ||
sessionSecret?: never; // robot users only use accessToken -- this prevents some extraneous typecasting | ||
accessToken?: string; | ||
}; | ||
|
||
export type ConnectionType = | ||
| 'Access-Token-Authentication' | ||
| 'Username-Password-Authentication' | ||
| 'facebook' | ||
| 'google-oauth2' | ||
| 'github'; | ||
|
||
export type UserData = { | ||
developmentCodeSigningId?: string; | ||
appleId?: string; | ||
userId?: string; | ||
username?: string; | ||
currentConnection?: ConnectionType; | ||
sessionSecret?: string; | ||
}; | ||
|
||
export type LegacyUser = { | ||
kind: 'legacyUser'; | ||
username: string; | ||
userMetadata: { | ||
legacy: boolean; | ||
needsPasswordMigration: boolean; | ||
}; | ||
}; | ||
|
||
export type UserOrLegacyUser = User | LegacyUser; | ||
|
||
export type RegistrationData = { | ||
username: string; | ||
password: string; | ||
email?: string; | ||
givenName?: string; | ||
familyName?: string; | ||
}; | ||
|
||
/** | ||
* Forgot Password | ||
*/ | ||
export async function forgotPasswordAsync(usernameOrEmail: string): Promise<void> { | ||
return ApiV2.clientForUser().postAsync('auth/forgotPasswordAsync', { | ||
usernameOrEmail, | ||
}); | ||
} | ||
|
||
export async function getUserInfoAsync( | ||
user?: ApiV2ClientOptions | ||
): Promise<{ user_type: string } & any> { | ||
const results = await ApiV2.clientForUser(user).getAsync('auth/userInfo'); | ||
|
||
if (!results) { | ||
throw new Error('Unable to fetch user.'); | ||
} | ||
return results; | ||
} | ||
|
||
/** | ||
* @param user | ||
* @param props.secondFactorDeviceID UUID of the second factor device | ||
*/ | ||
export async function sendSmsOtpAsync( | ||
user: ApiV2ClientOptions | null, | ||
{ | ||
username, | ||
password, | ||
secondFactorDeviceID, | ||
}: { | ||
username: string; | ||
password: string; | ||
secondFactorDeviceID: string; | ||
} | ||
): Promise<unknown> { | ||
return await ApiV2.clientForUser(user).postAsync('auth/send-sms-otp', { | ||
username, | ||
password, | ||
secondFactorDeviceID, | ||
}); | ||
} | ||
|
||
/** | ||
* Logs in a user for a given login type. | ||
* | ||
* Valid login types are: | ||
* - "user-pass": Username and password authentication | ||
* | ||
* If the login type is "user-pass", we directly make the request to www | ||
* to login a user. | ||
*/ | ||
export async function loginAsync( | ||
loginType: LoginType, | ||
loginArgs?: { username: string; password: string; otp?: string } | ||
): Promise<string> { | ||
assert(loginType === 'user-pass', `Invalid login type provided. Must be 'user-pass'.`); | ||
assert(loginArgs, `The 'user-pass' login type requires a username and password.`); | ||
const { error, sessionSecret, error_description } = await ApiV2.clientForUser().postAsync( | ||
'auth/loginAsync', | ||
{ | ||
username: loginArgs.username, | ||
password: loginArgs.password, | ||
otp: loginArgs.otp, | ||
} | ||
); | ||
if (error) { | ||
throw new AuthError('INVALID_USERNAME_PASSWORD', error_description); | ||
} | ||
return sessionSecret; | ||
} | ||
|
||
/** | ||
* Create or update a user. | ||
*/ | ||
export async function createOrUpdateUserAsync( | ||
user: User | RobotUser | null, | ||
userData: any | ||
): Promise<User | null> { | ||
if (user?.kind === 'robot') { | ||
throw new AuthError('ROBOT_ACCOUNT_ERROR', 'This action is not available for robot users'); | ||
} | ||
|
||
const { user: updatedUser } = await ApiV2.clientForUser(user).postAsync( | ||
'auth/createOrUpdateUser', | ||
{ | ||
userData, | ||
} | ||
); | ||
|
||
return updatedUser; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { ExpoConfig } from '@expo/config-types'; | ||
import os from 'os'; | ||
import { URLSearchParams } from 'url'; | ||
|
||
import ApiV2, { ApiV2ClientOptions } from './ApiV2'; | ||
|
||
export async function notifyAliveAsync( | ||
user: ApiV2ClientOptions | null, | ||
{ | ||
exp, | ||
platform, | ||
url, | ||
description, | ||
source, | ||
openedAt, | ||
devices, | ||
}: { | ||
openedAt?: number; | ||
description?: string; | ||
exp: ExpoConfig; | ||
platform: 'native' | 'web'; | ||
url: string; | ||
source: 'desktop' | 'snack'; | ||
devices: { installationId: string }[]; | ||
} | ||
): Promise<unknown> { | ||
let queryString = ''; | ||
if (devices) { | ||
const searchParams = new URLSearchParams(); | ||
devices.forEach(device => { | ||
searchParams.append('deviceId', device.installationId); | ||
}); | ||
queryString = `?${searchParams.toString()}`; | ||
} | ||
|
||
return await ApiV2.clientForUser(user).postAsync( | ||
`development-sessions/notify-alive${queryString}`, | ||
{ | ||
data: { | ||
session: { | ||
description: description ?? `${exp.name} on ${os.hostname()}`, | ||
url, | ||
source, | ||
openedAt, | ||
// not on type | ||
hostname: os.hostname(), | ||
platform, | ||
config: { | ||
// TODO: if icons are specified, upload a url for them too so people can distinguish | ||
description: exp.description, | ||
name: exp.name, | ||
slug: exp.slug, | ||
primaryColor: exp.primaryColor, | ||
}, | ||
}, | ||
}, | ||
} | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { JSONObject } from '@expo/json-file'; | ||
|
||
import ApiV2, { ApiV2ClientOptions } from './ApiV2'; | ||
import UserManager from './User'; | ||
|
||
export async function signAsync(user: ApiV2ClientOptions, manifest: JSONObject): Promise<string> { | ||
const { signature } = await ApiV2.clientForUser(user).postAsync('manifest/eas/sign', { | ||
manifest, | ||
}); | ||
return signature; | ||
} | ||
|
||
export async function signLegacyAsync( | ||
user: ApiV2ClientOptions, | ||
manifest: JSONObject | ||
): Promise<string> { | ||
const { response } = await ApiV2.clientForUser(user).postAsync('manifest/sign', { | ||
args: { | ||
remoteUsername: manifest.owner ?? (await UserManager.getCurrentUsernameAsync()), | ||
remotePackageName: manifest.slug, | ||
}, | ||
manifest: manifest as JSONObject, | ||
}); | ||
return response; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import ApiV2, { ApiV2ClientOptions } from './ApiV2'; | ||
|
||
export async function getAsync( | ||
user: ApiV2ClientOptions, | ||
projectId: string | ||
): Promise<{ scopeKey: string }> { | ||
return await ApiV2.clientForUser(user).getAsync(`projects/${encodeURIComponent(projectId)}`); | ||
} |
Oops, something went wrong.