expo-http-server 0.1.0

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/.eslintrc.js ADDED
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ root: true,
3
+ extends: ["universe/native", "universe/web"],
4
+ ignorePatterns: ["build"],
5
+ };
package/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # expo-http-server
2
+
3
+ HTTP local server for expo apps (not finished and untested)
4
+
5
+ TODO: Documentation
@@ -0,0 +1,94 @@
1
+ apply plugin: 'com.android.library'
2
+ apply plugin: 'kotlin-android'
3
+ apply plugin: 'maven-publish'
4
+
5
+ group = 'expo.modules.httpserver'
6
+ version = '0.1.0'
7
+
8
+ buildscript {
9
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
10
+ if (expoModulesCorePlugin.exists()) {
11
+ apply from: expoModulesCorePlugin
12
+ applyKotlinExpoModulesCorePlugin()
13
+ }
14
+
15
+ // Simple helper that allows the root project to override versions declared by this library.
16
+ ext.safeExtGet = { prop, fallback ->
17
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
18
+ }
19
+
20
+ // Ensures backward compatibility
21
+ ext.getKotlinVersion = {
22
+ if (ext.has("kotlinVersion")) {
23
+ ext.kotlinVersion()
24
+ } else {
25
+ ext.safeExtGet("kotlinVersion", "1.8.10")
26
+ }
27
+ }
28
+
29
+ repositories {
30
+ mavenCentral()
31
+ }
32
+
33
+ dependencies {
34
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
35
+ }
36
+ }
37
+
38
+ afterEvaluate {
39
+ publishing {
40
+ publications {
41
+ release(MavenPublication) {
42
+ from components.release
43
+ }
44
+ }
45
+ repositories {
46
+ maven {
47
+ url = mavenLocal().url
48
+ }
49
+ }
50
+ }
51
+ }
52
+
53
+ android {
54
+ compileSdkVersion safeExtGet("compileSdkVersion", 33)
55
+
56
+ def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
57
+ if (agpVersion.tokenize('.')[0].toInteger() < 8) {
58
+ compileOptions {
59
+ sourceCompatibility JavaVersion.VERSION_11
60
+ targetCompatibility JavaVersion.VERSION_11
61
+ }
62
+
63
+ kotlinOptions {
64
+ jvmTarget = JavaVersion.VERSION_11.majorVersion
65
+ }
66
+ }
67
+
68
+ namespace "expo.modules.httpserver"
69
+ defaultConfig {
70
+ minSdkVersion safeExtGet("minSdkVersion", 21)
71
+ targetSdkVersion safeExtGet("targetSdkVersion", 34)
72
+ versionCode 1
73
+ versionName "0.1.0"
74
+ }
75
+ lintOptions {
76
+ abortOnError false
77
+ }
78
+ publishing {
79
+ singleVariant("release") {
80
+ withSourcesJar()
81
+ }
82
+ }
83
+ }
84
+
85
+ repositories {
86
+ mavenCentral()
87
+ }
88
+
89
+ dependencies {
90
+ implementation project(':expo-modules-core')
91
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
92
+ implementation 'com.github.fengzhizi715.AndroidServer:core:1.3.3'
93
+ implementation 'com.github.fengzhizi715.AndroidServer:gson:1.3.3'
94
+ }
@@ -0,0 +1,2 @@
1
+ <manifest>
2
+ </manifest>
@@ -0,0 +1,81 @@
1
+ package expo.modules.httpserver
2
+
3
+ import androidx.core.os.bundleOf
4
+ import expo.modules.kotlin.modules.Module
5
+ import expo.modules.kotlin.modules.ModuleDefinition
6
+ import com.safframework.server.core.AndroidServer
7
+ import com.safframework.server.core.RequestHandler
8
+ import com.safframework.server.core.Server
9
+ import com.safframework.server.core.http.HttpMethod
10
+ import com.safframework.server.core.http.Request
11
+ import com.safframework.server.core.http.Response
12
+ import org.json.JSONObject
13
+ import java.util.UUID
14
+
15
+ class ExpoHttpServerModule : Module() {
16
+ class SimpleHttpResponse(val statusCode: Int,
17
+ val contentType: String,
18
+ val body: String)
19
+
20
+ private lateinit var server: Server
21
+ private val responses = HashMap<String, SimpleHttpResponse>()
22
+
23
+ private val requestHandler: RequestHandler = { request: Request, response: Response ->
24
+ val uuid = UUID.randomUUID().toString()
25
+ val headers: Map<String, String> = request.headers()
26
+ val params: Map<String, String> = request.params()
27
+ val cookies: Map<String, String> = request.cookies().associate { it.name() to it.value() }
28
+ sendEvent("onRequest", bundleOf(
29
+ "uuid" to uuid,
30
+ "method" to request.method().name,
31
+ "path" to request.url(),
32
+ "content" to request.content(),
33
+ "headersJson" to JSONObject(headers).toString(),
34
+ "paramsJson" to JSONObject(params).toString(),
35
+ "cookiesJson" to JSONObject(cookies).toString(),
36
+ ))
37
+ while (!responses.containsKey(uuid)) {
38
+ Thread.sleep(10)
39
+ }
40
+ val res = responses[uuid]!!
41
+ responses.remove(uuid);
42
+ response.setBodyText(res.body)
43
+ response.setStatus(res.statusCode)
44
+ response.addHeader("Content-Length", "" + res.body.length)
45
+ response.addHeader("Content-Type", res.contentType)
46
+ }
47
+
48
+ override fun definition() = ModuleDefinition {
49
+
50
+ Name("ExpoHttpServer")
51
+
52
+ Events("onRequest")
53
+
54
+ Function("setup") { port: Int ->
55
+ server = AndroidServer.Builder{
56
+ port {
57
+ port
58
+ }
59
+ }.build()
60
+ }
61
+
62
+ Function("route") { path: String, method: String ->
63
+ server = server.request(HttpMethod.getMethod(method), path, requestHandler);
64
+ }
65
+
66
+ Function("start") {
67
+ server.start()
68
+ }
69
+
70
+ Function("respond") { uuid: String,
71
+ statusCode: Int,
72
+ contentType: String,
73
+ body: String ->
74
+ responses[uuid] = SimpleHttpResponse(statusCode, contentType, body);
75
+ }
76
+
77
+ Function("stop") {
78
+ server.close()
79
+ }
80
+ }
81
+ }
@@ -0,0 +1,3 @@
1
+ declare const _default: any;
2
+ export default _default;
3
+ //# sourceMappingURL=ExpoHttpServerModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoHttpServerModule.d.ts","sourceRoot":"","sources":["../src/ExpoHttpServerModule.ts"],"names":[],"mappings":";AAEA,wBAAqD"}
@@ -0,0 +1,3 @@
1
+ import { requireNativeModule } from "expo-modules-core";
2
+ export default requireNativeModule("ExpoHttpServer");
3
+ //# sourceMappingURL=ExpoHttpServerModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoHttpServerModule.js","sourceRoot":"","sources":["../src/ExpoHttpServerModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,eAAe,mBAAmB,CAAC,gBAAgB,CAAC,CAAC","sourcesContent":["import { requireNativeModule } from \"expo-modules-core\";\n\nexport default requireNativeModule(\"ExpoHttpServer\");\n"]}
@@ -0,0 +1,25 @@
1
+ export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
2
+ export interface RequestEvent {
3
+ uuid: string;
4
+ method: string;
5
+ path: string;
6
+ content: string;
7
+ headersJson: string;
8
+ paramsJson: string;
9
+ cookiesJson: string;
10
+ }
11
+ export interface Response {
12
+ statusCode?: number;
13
+ contentType?: string;
14
+ body?: string;
15
+ }
16
+ export interface Callback {
17
+ method: string;
18
+ path: string;
19
+ callback: (request: RequestEvent) => Promise<Response>;
20
+ }
21
+ export declare const start: () => void;
22
+ export declare const route: (path: string, method: HttpMethod, callback: (request: RequestEvent) => Promise<Response>) => void;
23
+ export declare const setup: (port: number) => any;
24
+ export declare const stop: () => any;
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE3D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACxD;AAED,eAAO,MAAM,KAAK,YAyBjB,CAAC;AAEF,eAAO,MAAM,KAAK,SACV,MAAM,UACJ,UAAU,sBACE,YAAY,KAAK,QAAQ,QAAQ,CAAC,SAQvD,CAAC;AAEF,eAAO,MAAM,KAAK,SAAU,MAAM,QAAqC,CAAC;AACxE,eAAO,MAAM,IAAI,WAAoC,CAAC"}
package/build/index.js ADDED
@@ -0,0 +1,29 @@
1
+ import { EventEmitter } from "expo-modules-core";
2
+ import ExpoHttpServerModule from "./ExpoHttpServerModule";
3
+ const emitter = new EventEmitter(ExpoHttpServerModule);
4
+ const requestCallbacks = [];
5
+ export const start = () => {
6
+ ExpoHttpServerModule.start();
7
+ emitter.addListener("onRequest", async (event) => {
8
+ const callbacks = requestCallbacks.filter((c) => event.path === c.path && event.method === c.method);
9
+ if (!callbacks.length) {
10
+ ExpoHttpServerModule.respond(event.uuid, 200, "No callback", "No callback");
11
+ return;
12
+ }
13
+ for (const c of callbacks) {
14
+ const response = await c.callback(event);
15
+ ExpoHttpServerModule.respond(event.uuid, response.statusCode || 200, response.contentType || "application/json", response.body || "{}");
16
+ }
17
+ });
18
+ };
19
+ export const route = (path, method, callback) => {
20
+ requestCallbacks.push({
21
+ method,
22
+ path,
23
+ callback,
24
+ });
25
+ ExpoHttpServerModule.route(path, method);
26
+ };
27
+ export const setup = (port) => ExpoHttpServerModule.setup(port);
28
+ export const stop = () => ExpoHttpServerModule.stop();
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,oBAAoB,MAAM,wBAAwB,CAAC;AAE1D,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,oBAAoB,CAAC,CAAC;AACvD,MAAM,gBAAgB,GAAe,EAAE,CAAC;AA0BxC,MAAM,CAAC,MAAM,KAAK,GAAG,GAAG,EAAE;IACxB,oBAAoB,CAAC,KAAK,EAAE,CAAC;IAC7B,OAAO,CAAC,WAAW,CAAe,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QAC7D,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,CACvC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,CAC1D,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YACtB,oBAAoB,CAAC,OAAO,CAC1B,KAAK,CAAC,IAAI,EACV,GAAG,EACH,aAAa,EACb,aAAa,CACd,CAAC;YACF,OAAO;QACT,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACzC,oBAAoB,CAAC,OAAO,CAC1B,KAAK,CAAC,IAAI,EACV,QAAQ,CAAC,UAAU,IAAI,GAAG,EAC1B,QAAQ,CAAC,WAAW,IAAI,kBAAkB,EAC1C,QAAQ,CAAC,IAAI,IAAI,IAAI,CACtB,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,IAAY,EACZ,MAAkB,EAClB,QAAsD,EACtD,EAAE;IACF,gBAAgB,CAAC,IAAI,CAAC;QACpB,MAAM;QACN,IAAI;QACJ,QAAQ;KACT,CAAC,CAAC;IACH,oBAAoB,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACxE,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC","sourcesContent":["import { EventEmitter } from \"expo-modules-core\";\n\nimport ExpoHttpServerModule from \"./ExpoHttpServerModule\";\n\nconst emitter = new EventEmitter(ExpoHttpServerModule);\nconst requestCallbacks: Callback[] = [];\n\nexport type HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n\nexport interface RequestEvent {\n uuid: string;\n method: string;\n path: string;\n content: string;\n headersJson: string;\n paramsJson: string;\n cookiesJson: string;\n}\n\nexport interface Response {\n statusCode?: number;\n contentType?: string;\n body?: string;\n}\n\nexport interface Callback {\n method: string;\n path: string;\n callback: (request: RequestEvent) => Promise<Response>;\n}\n\nexport const start = () => {\n ExpoHttpServerModule.start();\n emitter.addListener<RequestEvent>(\"onRequest\", async (event) => {\n const callbacks = requestCallbacks.filter(\n (c) => event.path === c.path && event.method === c.method,\n );\n if (!callbacks.length) {\n ExpoHttpServerModule.respond(\n event.uuid,\n 200,\n \"No callback\",\n \"No callback\",\n );\n return;\n }\n for (const c of callbacks) {\n const response = await c.callback(event);\n ExpoHttpServerModule.respond(\n event.uuid,\n response.statusCode || 200,\n response.contentType || \"application/json\",\n response.body || \"{}\",\n );\n }\n });\n};\n\nexport const route = (\n path: string,\n method: HttpMethod,\n callback: (request: RequestEvent) => Promise<Response>,\n) => {\n requestCallbacks.push({\n method,\n path,\n callback,\n });\n ExpoHttpServerModule.route(path, method);\n};\n\nexport const setup = (port: number) => ExpoHttpServerModule.setup(port);\nexport const stop = () => ExpoHttpServerModule.stop();\n"]}
@@ -0,0 +1,9 @@
1
+ {
2
+ "platforms": ["ios", "android"],
3
+ "ios": {
4
+ "modules": ["ExpoHttpServerModule"]
5
+ },
6
+ "android": {
7
+ "modules": ["expo.modules.httpserver.ExpoHttpServerModule"]
8
+ }
9
+ }
@@ -0,0 +1,29 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'ExpoHttpServer'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.description = package['description']
10
+ s.license = package['license']
11
+ s.author = package['author']
12
+ s.homepage = package['homepage']
13
+ s.platform = :ios, '13.4'
14
+ s.swift_version = '5.4'
15
+ s.source = { git: 'https://github.com/simonsturge/expo-http-server' }
16
+ s.static_framework = true
17
+
18
+ s.dependency 'ExpoModulesCore'
19
+ s.dependency 'Criollo'
20
+ s.dependency 'CocoaAsyncSocket'
21
+
22
+ # Swift/Objective-C compatibility
23
+ s.pod_target_xcconfig = {
24
+ 'DEFINES_MODULE' => 'YES',
25
+ 'SWIFT_COMPILATION_MODE' => 'wholemodule'
26
+ }
27
+
28
+ s.source_files = "**/*.{h,m,swift}"
29
+ end
@@ -0,0 +1,132 @@
1
+ import ExpoModulesCore
2
+ import Criollo
3
+
4
+ public class ExpoHttpServerModule: Module {
5
+ private let server = CRHTTPServer()
6
+ private var port: Int?
7
+ private var responses = [String: CRResponse]()
8
+ private var bgTaskIdentifier = UIBackgroundTaskIdentifier.invalid
9
+
10
+ public func definition() -> ModuleDefinition {
11
+ Name("ExpoHttpServer")
12
+
13
+ Events("onRequest")
14
+
15
+ Function("setup", setupHandler)
16
+ Function("start", startHandler)
17
+ Function("route", routeHandler)
18
+ Function("respond", respondHandler)
19
+ Function("stop", stopHandler)
20
+ }
21
+
22
+ private func setupHandler(port: Int) {
23
+ NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { [unowned self] notification in
24
+ if (self.server.isListening) {
25
+ self.endBackgroundTask()
26
+ self.beginBackgroundTask()
27
+ }
28
+ }
29
+ self.port = port;
30
+ }
31
+
32
+ private func startHandler() {
33
+ if (server.isListening) { return }
34
+ beginBackgroundTask()
35
+ var error: NSError?
36
+ if let port = port {
37
+ server.startListening(&error, portNumber: UInt(port))
38
+ } else {
39
+ server.startListening(&error)
40
+ }
41
+ }
42
+
43
+ private func routeHandler(path: String, method: String) {
44
+ server.add(path, block: { [weak self] (req, res, next) in
45
+ let uuid = UUID().uuidString
46
+ self?.sendEvent("onRequest", [
47
+ "uuid": uuid,
48
+ "method": req.method.toString(),
49
+ "path": path,
50
+ "body": req.body,
51
+ "headersJson": req.allHTTPHeaderFields.jsonString,
52
+ "paramsJson": req.query.jsonString,
53
+ "cookiesJson": req.cookies?.jsonString ?? "{}"
54
+ ])
55
+ self?.responses[uuid] = res
56
+ }, recursive: false, method: CRHTTPMethod.fromString(method))
57
+ }
58
+
59
+ private func respondHandler(udid: String,
60
+ statusCode: Int,
61
+ contentType: String,
62
+ body: String) {
63
+ if let response = responses[udid] {
64
+ response.setStatusCode(UInt(statusCode), description: "Success")
65
+ response.setValue(contentType, forHTTPHeaderField: "Content-type")
66
+ response.setValue("\(body.count)", forHTTPHeaderField: "Content-Length")
67
+ response.send(body);
68
+ responses[udid] = nil;
69
+ }
70
+ }
71
+
72
+ private func stopHandler() {
73
+ if (server.isListening) {
74
+ server.stopListening()
75
+ endBackgroundTask()
76
+ }
77
+ }
78
+
79
+ private func beginBackgroundTask() {
80
+ if (bgTaskIdentifier == UIBackgroundTaskIdentifier.invalid) {
81
+ self.bgTaskIdentifier = UIApplication.shared.beginBackgroundTask(withName: "BgTask", expirationHandler: {
82
+ self.endBackgroundTask()
83
+ })
84
+ }
85
+ }
86
+
87
+ private func endBackgroundTask() {
88
+ if (bgTaskIdentifier != UIBackgroundTaskIdentifier.invalid) {
89
+ UIApplication.shared.endBackgroundTask(bgTaskIdentifier)
90
+ bgTaskIdentifier = UIBackgroundTaskIdentifier.invalid
91
+ }
92
+ }
93
+ }
94
+
95
+ extension Dictionary {
96
+ var jsonString: String {
97
+ guard let data = try? JSONSerialization.data(withJSONObject: self) else {
98
+ return "{}";
99
+ }
100
+ return String(data: data, encoding: .utf8) ?? "{}"
101
+ }
102
+ }
103
+
104
+ extension CRHTTPMethod {
105
+ func toString() -> String {
106
+ switch self {
107
+ case .post:
108
+ return "POST"
109
+ case .put:
110
+ return "PUT"
111
+ case .delete:
112
+ return "DELETE"
113
+ default:
114
+ return "GET"
115
+ }
116
+ }
117
+
118
+ static func fromString(_ string: String) -> Self {
119
+ var httpMethod: CRHTTPMethod
120
+ switch (string) {
121
+ case "POST":
122
+ httpMethod = .post
123
+ case "PUT":
124
+ httpMethod = .put
125
+ case "DELETE":
126
+ httpMethod = .delete
127
+ default:
128
+ httpMethod = .get
129
+ }
130
+ return httpMethod
131
+ }
132
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "expo-http-server",
3
+ "version": "0.1.0",
4
+ "description": "A simple HTTP server expo module (iOS/Android)",
5
+ "main": "build/index.js",
6
+ "types": "build/index.d.ts",
7
+ "scripts": {
8
+ "build": "expo-module build",
9
+ "clean": "expo-module clean",
10
+ "lint": "expo-module lint",
11
+ "test": "expo-module test",
12
+ "prepare": "expo-module prepare",
13
+ "prepublishOnly": "expo-module prepublishOnly",
14
+ "expo-module": "expo-module",
15
+ "open:ios": "open -a \"Xcode\" example/ios",
16
+ "open:android": "open -a \"Android Studio\" example/android"
17
+ },
18
+ "keywords": [
19
+ "react-native",
20
+ "expo",
21
+ "expo-http-server",
22
+ "ExpoHttpServer"
23
+ ],
24
+ "repository": "https://github.com/simonsturge/expo-http-server",
25
+ "bugs": {
26
+ "url": "https://github.com/simonsturge/expo-http-server/issues"
27
+ },
28
+ "author": "Simon <development@simonsturge.com> (https://github.com/simonsturge)",
29
+ "license": "MIT",
30
+ "homepage": "https://github.com/simonsturge/expo-http-server#readme",
31
+ "dependencies": {},
32
+ "devDependencies": {
33
+ "@types/react": "^18.0.25",
34
+ "expo-module-scripts": "^3.4.0",
35
+ "expo-modules-core": "^1.11.8"
36
+ },
37
+ "peerDependencies": {
38
+ "expo": "*",
39
+ "react": "*",
40
+ "react-native": "*"
41
+ }
42
+ }
@@ -0,0 +1,3 @@
1
+ import { requireNativeModule } from "expo-modules-core";
2
+
3
+ export default requireNativeModule("ExpoHttpServer");
package/src/index.ts ADDED
@@ -0,0 +1,73 @@
1
+ import { EventEmitter } from "expo-modules-core";
2
+
3
+ import ExpoHttpServerModule from "./ExpoHttpServerModule";
4
+
5
+ const emitter = new EventEmitter(ExpoHttpServerModule);
6
+ const requestCallbacks: Callback[] = [];
7
+
8
+ export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
9
+
10
+ export interface RequestEvent {
11
+ uuid: string;
12
+ method: string;
13
+ path: string;
14
+ content: string;
15
+ headersJson: string;
16
+ paramsJson: string;
17
+ cookiesJson: string;
18
+ }
19
+
20
+ export interface Response {
21
+ statusCode?: number;
22
+ contentType?: string;
23
+ body?: string;
24
+ }
25
+
26
+ export interface Callback {
27
+ method: string;
28
+ path: string;
29
+ callback: (request: RequestEvent) => Promise<Response>;
30
+ }
31
+
32
+ export const start = () => {
33
+ ExpoHttpServerModule.start();
34
+ emitter.addListener<RequestEvent>("onRequest", async (event) => {
35
+ const callbacks = requestCallbacks.filter(
36
+ (c) => event.path === c.path && event.method === c.method,
37
+ );
38
+ if (!callbacks.length) {
39
+ ExpoHttpServerModule.respond(
40
+ event.uuid,
41
+ 200,
42
+ "No callback",
43
+ "No callback",
44
+ );
45
+ return;
46
+ }
47
+ for (const c of callbacks) {
48
+ const response = await c.callback(event);
49
+ ExpoHttpServerModule.respond(
50
+ event.uuid,
51
+ response.statusCode || 200,
52
+ response.contentType || "application/json",
53
+ response.body || "{}",
54
+ );
55
+ }
56
+ });
57
+ };
58
+
59
+ export const route = (
60
+ path: string,
61
+ method: HttpMethod,
62
+ callback: (request: RequestEvent) => Promise<Response>,
63
+ ) => {
64
+ requestCallbacks.push({
65
+ method,
66
+ path,
67
+ callback,
68
+ });
69
+ ExpoHttpServerModule.route(path, method);
70
+ };
71
+
72
+ export const setup = (port: number) => ExpoHttpServerModule.setup(port);
73
+ export const stop = () => ExpoHttpServerModule.stop();
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ // @generated by expo-module-scripts
2
+ {
3
+ "extends": "expo-module-scripts/tsconfig.base",
4
+ "compilerOptions": {
5
+ "outDir": "./build"
6
+ },
7
+ "include": ["./src"],
8
+ "exclude": ["**/__mocks__/*", "**/__tests__/*"]
9
+ }