Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0f9c289
First pass at HTTP extension methods
jlacivita Aug 8, 2022
97ccdaf
More features
jlacivita Aug 9, 2022
1310a75
Refactor Http module to conform to Transport API
jlacivita Aug 15, 2022
54a100b
Wire up Authenticate API
jlacivita Aug 15, 2022
e784330
Remove bespoke Core code from Extensions
jlacivita Aug 15, 2022
7f55ab5
Merge branch 'main' into feature/http-methods
jlacivita Aug 15, 2022
69dedd6
Fix http macro replacement to do all occurences
jlacivita Aug 16, 2022
f29fa0c
Remove unused commented code example
jlacivita Aug 16, 2022
6005416
Move config code to template files
jlacivita Aug 16, 2022
88f78d2
Remove unneeded token API
jlacivita Aug 16, 2022
6e4e87d
Clean up Browser.js
jlacivita Aug 18, 2022
1c7a849
Update authorize signature
jlacivita Aug 18, 2022
1010d02
Merge branch 'main' into feature/http-methods
jlacivita Aug 22, 2022
bd0443b
Rationalize Transport.send options and transforms params
jlacivita Aug 22, 2022
a5482f6
Don't import any transport for `exclude-from-sdk` methods
jlacivita Aug 22, 2022
f1797da
Update index.mjs
jlacivita Aug 22, 2022
963dd4e
Fix bug w/ mock server
jlacivita Aug 23, 2022
3626bee
Add distributor to initialize()
jlacivita Aug 26, 2022
6b96020
Move distributor to it's on parameter
jlacivita Aug 26, 2022
9a36b11
Merge branch 'main' into feature/http-methods
jlacivita Aug 26, 2022
f7b9d6d
Fix MockProps for real
jlacivita Aug 26, 2022
396dcff
Merge branch 'main' into feature/http-methods
jlacivita Sep 9, 2022
eb414f1
Update index.mjs
jlacivita Sep 9, 2022
2a7c1f1
Require capability on all methods
jlacivita Oct 21, 2022
60d62cb
Merge branch 'next' into feature/http-methods
jlacivita Nov 2, 2022
2b0619e
chore: Cherry picked Tree-shaking from extensions branch
jlacivita Nov 2, 2022
c13e8fc
chore: Move HTTP Test server to src
jlacivita Nov 2, 2022
caad894
chore: Remove Browser.js from jest
jlacivita Nov 2, 2022
c4128ec
chore: Move Teardown to src
jlacivita Nov 2, 2022
1f2b299
Merge branch 'next' into feature/http-methods
jlacivita Nov 4, 2022
fa63ed1
fix: Rollback #65
jlacivita Nov 4, 2022
49107c1
fix: Remove ability for Extension SDK to set it's own host
jlacivita Nov 9, 2022
18a79ff
Merge branch 'next' into feature/http-methods
jlacivita Nov 10, 2022
dde6a6c
fix: Remove distributor from initialize
jlacivita Nov 11, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,17 @@
* JSONRPC docs for provider response has invalid format ([#61](https://github.com/rdkcentral/firebolt-openrpc/issues/61)) ([34ddeaf](https://github.com/rdkcentral/firebolt-openrpc/commit/34ddeaf7345074a894f901464d366b6eb4488e51))
* multiple provider doc headers for same module are broken ([#56](https://github.com/rdkcentral/firebolt-openrpc/issues/56)) ([e63928f](https://github.com/rdkcentral/firebolt-openrpc/commit/e63928f5160c9d4227f3207c8a7c90495245ff7a))

## 1.5.0
# 1.6.0

- Convert all unit tests to TypeScript
- Docs generation Clean-up (schemas, etc.)
- Temporal Set methods, e.g. DeveloperTools.find()
- Provider APIs
- Support for static declarations template
- Bugfix: remove unit test global object
- Bugfix: include external schemas in declarations

# 1.5.0

- Much more beautiful validation error messages
- Moved Transport Layer API out of `src/templates` and into `src/js`
Expand Down
210 changes: 112 additions & 98 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"build": "npm run validate && npm run build:docs && npm run build:sdk",
"validate": "node ./src/cli.mjs --task validate --source ./src --shared-schemas test/sharedSchemas && npm run build:openrpc && node ./src/cli.mjs --task validate --source ./build/sdk-open-rpc.json --shared-schemas test/sharedSchemas",
"build:openrpc": "node ./src/cli.mjs --task openrpc --source ./src --template ./src/template/openrpc/template.json --output ./build/sdk-open-rpc.json --shared-schemas test/sharedSchemas",
"build:sdk": "node ./src/cli.mjs --task sdk --source ./src/ --template ./src/local/template/js --output ./build/sdk/javascript/src --shared-schemas test/sharedSchemas",
"build:sdk": "node ./src/cli.mjs --task sdk --source ./src/ --template ./src/local/template/js --output ./build/sdk/javascript/src --shared-schemas test/sharedSchemas --main sdk.mjs",
"build:d": "node ./src/cli.mjs --task declarations --source ./src/ --output ./dist/lib/sdk.d.ts --shared-schemas src/schemas",
"build:docs": "node ./src/cli.mjs --task docs --source ./src/ --template ./src/template/markdown --output ./build/docs/markdown --shared-schemas test/sharedSchemas --as-path",
"build:wiki": "node ./src/cli.mjs --task docs --source ./src/ --template ./src/template/markdown --output ./build/docs/wiki --shared-schemas test/sharedSchemas",
Expand Down Expand Up @@ -57,6 +57,7 @@
"mkdirp": "^0.5.6",
"node-fetch": "^3.2.10",
"nopt": "^5.0.0",
"text-decoding": "^1.0.0",
"util": "^0.12.4"
}
}
3 changes: 2 additions & 1 deletion src/cli.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ const knownOpts = {
'output': [path],
'shared-schemas': [path],
'as-path': Boolean,
'static-modules': String
'static-modules': String,
'main': String
}
const shortHands = {
't': '--task',
Expand Down
94 changes: 94 additions & 0 deletions src/js/http/Server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import http from 'http'
import dns from 'dns'

const lookup = dns.lookup

const config = (await import(process.env.npm_package_json, { assert: {type: "json" }})).default
const name = 'firebolt-' + config.name.split('/').pop().split('-').shift()
const rpcPath = process.env.npm_config_local_prefix + '/dist/' + name + '-open-rpc.json'
const rpc = (await import(rpcPath, {assert: { type: "json" }})).default
const endpoint = "http://localhost/"
const domain = new URL(endpoint).hostname
const port = parseInt(new URL(endpoint).port) || 80
const httpTag = m => m.tags && m.tags.find(t => t.name === 'http')
const httpPath = m => httpTag(m) && httpTag(m)['x-http-path']

console.log(`endpoint: ${endpoint}`)
console.log(`domain: ${domain}`)
console.log(`port: ${port}`)

dns.lookup = function (...args) {
if (args[0] === domain) {
console.log(`spoofing domain ${domain} to localhost`)
return args.pop()(null, '127.0.0.1', 4)
}
else {
return lookup(...args)
}
}

async function setup() {
return new Promise((resolve, reject) => {

const process = async (request, response) => {
const requestPath = request.url.split(endpoint).pop()
const method = rpc.methods.find(m => {
const tag = httpTag(m)
let path = tag && httpPath(m)

if (path && path.endsWith('/')) {
path = path.substr(0, path.length-1)
}

return path && requestPath.startsWith(path.split("$")[0])
})

let body

if (request.method === 'POST') {
const buffers = [];

for await (const chunk of request) {
buffers.push(chunk);
}

body = Buffer.concat(buffers).toString();
}

response.setHeader("Content-Type", "application/json")
response.writeHead(200)

if (method) {
response.write(JSON.stringify(method.examples[0].result.value))
}
else if (request.url.endsWith('/account/authenticate')) {
response.write(JSON.stringify({
oat: "OAT",
bearerToken: "BEARER",
d: "D"
}))
}
else {
response.write('{}')
}
response.end()
}

const server = http.createServer(process);

global.__firebolt__shutdown__ = () => {
server.close()
}

server.listen(port, () => {
console.log("Firebolt Server Started")
resolve()
});
})
}


export default async function(globalConfig, projectConfig) {
await setup()
return
}
4 changes: 4 additions & 0 deletions src/js/http/Teardown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default async function(globalConfig, projectConfig) {
await __firebolt__shutdown__()
return
}
25 changes: 25 additions & 0 deletions src/js/shared/Configuration/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const config = {}

function set(name, value) {
// if the only argument is an object, copy all of the values in
if (name && !value && typeof name === 'object') {
Object.assign(config, name)
}
else {
config[name] = value
}
}

function get(name) {
if (!name) {
return JSON.parse(JSON.stringify(config))
}
else {
return config[name]
}
}

export default {
get,
set
}
2 changes: 1 addition & 1 deletion src/js/shared/Events/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -280,4 +280,4 @@ export default {
broadcast(event, value) {
emit(Object.entries(keys).find( ([k, v]) => v === 'app.'+event)[0], value)
},
}
}
55 changes: 55 additions & 0 deletions src/js/shared/Extensions/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import Transport from '../Transport/index.mjs'

window.__firebolt = window.__firebolt || {}
const initializers = {}
const apis = {}
const queue = {}
const initialized = []
const pending = []
const frozen = false

window.__firebolt.registerExtensionSDK = (id, initializer) => {
initializers[id] = initializer

if (queue[id]) {
initialize(id, queue[id])
delete queue[id]
}
}

// Method for handing off platform tokens to extension SDKs
registerAPI('authorize', (...args) => Transport.send('capabilities', 'authorize', {...args} ))

function initialize(id, config) {
if (!frozen) {
Object.freeze(apis)
}
Object.freeze(config)
if (initializers[id]) {
const getEndPoint = Transport.send('capabilities', 'endpoint', { id })
const init = initializers[id]
delete initializers[id]
pending.push(id)
getEndPoint.then((endpoint) => {
init(endpoint, config, apis)
initialized.push(id)
delete pending[id]
})
}
else {
queue[id] = config
}
}

function active() {
return Object.freeze(initialized.contact())
}

export function registerAPI(name, method) {
apis[name] = method
}

export default {
initialize,
active
}
100 changes: 100 additions & 0 deletions src/js/shared/Http/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
let baseUri

let authApiResolver
let authApiReady = new Promise( resolve => authApiResolver = resolve )


let proxyProvider = (resource, options) => Promise.resolve({ resource, options })

const join = (...args) => args.map(a => (''+a).split('/')).flat().filter(a => a!=='').join('/').replace(':/', '://')

function setEndpoint(endpoint) {
baseUri = endpoint
}

function onAuthorize(callback) {
if (authApiResolver) {
authApiResolver(callback)
authApiResolver = null
}
}

function getAuthorization(grants) {
return authApiReady.then(authGetter => authGetter(grants))
}


// this gets called syncrhonously by the SDK itself, if needed
export function proxy(callback) {
proxyProvider = callback
}

function send(module, method, params, http = {}) {

let path = http.path || `/${module}/${method}`
const headers = http.headers || {}
const body = params && JSON.stringify(params) || null
let query = http.parameters || ''

Object.entries(params).forEach(([name, value]) => {
const re = new RegExp('\\${param.' + name + '}', 'g')
path = path.replace(re, value)
query = query.replace(re, value)
Object.keys(headers).forEach(header => {
headers[header] = headers[header].replace(re, value)
})
})

return new Promise((resolve, reject) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be better to rewrite this as an async function, a lot of nested .thens going on

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stylistically, I agree.

However, I've been resisting the urge to use async/await because we haven't used them yet in the code. I just did a quick search and saw it's used in the new version of Lifecycle.ready() in the Core SDK. Have we tested that code on all of the browsers we care about?

const requested = http.uses.map(capability => ({ role: 'use', capability }))
.concat(http.manages.map(capability => ({ role: 'manage', capability })))
.concat(http.provides.map(capability => ({ role: 'provide', capability })))

getAuthorization(requested).then((token) => {
// TODO: this could be a bit more robust...
Object.assign(headers, {
'Authorization': token
})

const resource = join(baseUri, path) + (query ? '?' + query : '')
const options = {
method: http.method || 'GET',
headers: headers
}

if (method === 'POST' && body) {
options.body = body
}

proxyProvider(resource, options).then( ({ resource, options }) => {
console.log(`Fetch ${method} ${resource}`)
options.body && console.log(options.body)

fetch(resource, options).then(response => {
if (response.ok) {
response.json().then(json => {
Comment thread
jlacivita marked this conversation as resolved.
resolve(json)
}, error => {
reject(error)
})
}
else {
reject(new Error(response.status + ': ' + response.statusText))
}
}).catch(error => {
reject(error)
})
}).catch(error => {
reject(error)
})
}).catch(error => {
reject(error)
})
})
}

export default {
send,
setEndpoint,
onAuthorize
}
10 changes: 5 additions & 5 deletions src/js/shared/Prop/MockProps.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import Mock from "../Transport/MockTransport.mjs"

const mocks = {}

function mock(module, method, args, def) {
function mock(module, method, params, def) {
const fullMethod = `${module}.${method}`
if ((args == null) || args.length === 0 || (Object.values(args[0]).length === 0)) {
if ((params == null) || (Object.values(params).length === 0)) {
// get
const rv = mocks[fullMethod] && (mocks[fullMethod].value != null) ? mocks[fullMethod].value : def
return rv
Expand All @@ -17,11 +17,11 @@ function mock(module, method, args, def) {
}
}
mocks[fullMethod] = mockMethod
mockMethod.value = args[0].value
mockMethod.value = params.value
Mock.event(module, method + 'Changed', {
value: args[0].value
value: params[0].value
})
return {}
return null
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/js/shared/TemporalSet/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function start(module, method, addName, removeName, params, add, remove, transfo
module: module,
method: method,
params: params,
transforms: transforms
options: { transforms }
}
]

Expand All @@ -63,7 +63,7 @@ function start(module, method, addName, removeName, params, add, remove, transfo
params: {
listen: true
},
transforms: transforms
options: { transforms }
})

if (remove) {
Expand All @@ -73,7 +73,7 @@ function start(module, method, addName, removeName, params, add, remove, transfo
params: {
listen: true
},
transforms: transforms
options: { transforms }
})
}

Expand Down
Loading