@cloudbase/container 2.5.36-beta.0 → 2.5.37-alpha.1

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/src/index.ts CHANGED
@@ -2,20 +2,36 @@ import { ICloudbase } from '@cloudbase/types'
2
2
  import { ICloudbaseComponent } from '@cloudbase/types/component'
3
3
  import { ICallContainerOptions, IContianerConfig } from '@cloudbase/types/container'
4
4
  import { constants, utils, helpers } from '@cloudbase/utilities'
5
- // import brotliPromise from 'brotli-dec-wasm' // Import the default export
6
- import decompress from 'brotli/decompress'
7
-
8
- import Go from './go_wams_exec'
9
5
  import { isBuffer, parseURL, serializeRequestBody } from './utils'
10
- import { request } from './utils/request'
11
6
  import { COMPONENT_NAME } from './constants'
12
7
 
13
8
  declare const cloudbase: ICloudbase
14
-
15
9
  const { ERRORS, COMMUNITY_SITE_URL } = constants
16
10
  const { execCallback, printWarn } = utils
17
11
  const { catchErrorsDecorator } = helpers
18
12
 
13
+ /* eslint-disable */
14
+ let getExportFunction: Function = () => {
15
+ throw new Error('getExportFunction 未实现')
16
+ }
17
+ let loadJSExportFunction: Function = () => {
18
+ throw new Error('loadJSExportFunction 未实现')
19
+ }
20
+
21
+ if (globalThis.IS_MP_BUILD) {
22
+ getExportFunction = function () {
23
+ new Error('小程序不支持 wasm 加载')
24
+ }
25
+ loadJSExportFunction = function () {
26
+ new Error('小程序不支持动态 js 加载')
27
+ }
28
+ } else {
29
+ const loader = require('./utils/loader')
30
+ getExportFunction = loader.getExportFunction
31
+ loadJSExportFunction = loader.loadJSExportFunction
32
+ }
33
+ /* eslint-enable */
34
+
19
35
  class InvalieParamsError extends Error {
20
36
  code: any
21
37
  constructor(scope, message) {
@@ -51,43 +67,48 @@ function genContainerError(data, scope = COMPONENT_NAME, defaultMessage = 'call
51
67
  return error
52
68
  }
53
69
 
54
- class CloudbaseContainers {
55
- private readonly config: IContianerConfig
70
+ export class CloudbaseContainers {
71
+ private readonly config: IContianerConfig & { jsUrl?: { vender?: string; vm: string } }
56
72
  private wasm: Promise<WebAssembly.Exports>
57
73
  private containerInitPromise: /* Promise<any>*/ any | null
58
74
 
59
75
  constructor(config: IContianerConfig) {
60
76
  this.config = {
61
77
  ...config,
78
+ jsUrl:
79
+ typeof config.jsUrl === 'string'
80
+ ? {
81
+ vm: config.jsUrl,
82
+ }
83
+ : (config.jsUrl as any),
62
84
  }
63
85
 
64
- if (!this.config.wasmUrl && !this.config.jsUrl && !(window as any).cloudbase_private_link) {
86
+ if (!this.config.wasmUrl && this.config.publicKey) {
87
+ // 非 wams 且有 public key 则可使用默认的 js-sdk,无需校验
88
+ } else if (!this.config.wasmUrl && !this.config.jsUrl?.vm && !(globalThis as any).cloudbase_private_link) {
65
89
  throw new InvalieParamsError(`${COMPONENT_NAME}`, '缺少 privatelink sdk 地址')
66
90
  }
67
91
 
92
+ console.log('>>******', this.config)
93
+ debugger
94
+
68
95
  if (this.config.wasmUrl) {
69
- this.wasm = getExportFunction(this.config.wasmUrl, {
70
- utils: {
71
- info(e) {
72
- console.log(e)
73
- },
74
- request,
75
- },
76
- }).catch((e) => {
96
+ this.wasm = getExportFunction(this.config.wasmUrl).catch((e) => {
77
97
  if (this.config.jsUrl) {
78
98
  console.warn('load wams error, fall back to use js', e)
79
99
  return loadJSExportFunction(this.config.jsUrl)
80
- } if ((window as any).cloudbase_private_link) {
81
- return (window as any).cloudbase_private_link
100
+ }
101
+ if ((globalThis as any).cloudbase_private_link) {
102
+ return (globalThis as any).cloudbase_private_link
82
103
  }
83
104
  throw e
84
105
  })
85
- } else if (this.config.jsUrl) {
106
+ } else if (this.config.jsUrl || this.config.publicKey) {
86
107
  this.wasm = loadJSExportFunction(this.config.jsUrl)
87
108
  } else {
88
109
  this.wasm = Promise.resolve({
89
- initContainer: (window as any).cloudbase_private_link.initContainer,
90
- callContainer: (window as any).cloudbase_private_link.callContainer,
110
+ initContainer: (globalThis as any).cloudbase_private_link.initContainer,
111
+ callContainer: (globalThis as any).cloudbase_private_link.callContainer,
91
112
  })
92
113
  }
93
114
  }
@@ -138,36 +159,44 @@ class CloudbaseContainers {
138
159
  url,
139
160
  method,
140
161
  header,
141
- data: serializeRequestBody(header, data),
162
+ data: serializeRequestBody(header, data, method),
142
163
  timeout,
143
164
  dataType,
144
165
  responseType,
145
166
  ...restOptions,
146
167
  }
147
168
 
148
- /**
149
- * 非 buffer
150
- */
151
- if (params.data !== undefined && !isBuffer(params.data)) {
152
- if (typeof params.data !== 'string' && method === 'GET') {
153
- try {
154
- const list = Object.entries(params.data || {}).reduce(
155
- (list, [key, value]: [string, string | number | boolean]) => {
156
- list.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
157
- return list
158
- },
159
- [],
160
- )
161
- if (list.length) {
162
- params.data = list.join('&')
163
- }
164
- } catch (e) {}
169
+ if (
170
+ data
171
+ && (isBuffer(params.data) || typeof params.data === 'string')
172
+ && (data as any)?.length > 1000 * 1024 * 10
173
+ ) {
174
+ reject(new InvalieParamsError(SCOPE, 'body too large'))
175
+ return
176
+ }
177
+
178
+ if (method === 'GET') {
179
+ let { data: getBody } = params
180
+ if (getBody) {
181
+ params.data = undefined
182
+ }
183
+ if (!isBuffer(getBody) && typeof getBody !== 'string') {
184
+ const list = Object.entries(getBody || {}).reduce(
185
+ (list, [key, value]: [string, string | number | boolean]) => {
186
+ list.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
187
+ return list
188
+ },
189
+ [],
190
+ )
191
+ if (list.length) {
192
+ getBody = list.join('&')
193
+ }
165
194
  }
166
195
 
167
- if (method === 'GET' && typeof params.data === 'string') {
196
+ if (typeof params.data === 'string') {
168
197
  const parsedUrl = parseURL(url)
169
198
  if (parsedUrl.search) {
170
- parsedUrl.search += params.data
199
+ parsedUrl.search += `&${params.data}`
171
200
  } else {
172
201
  parsedUrl.search = `?${params.data}`
173
202
  }
@@ -176,15 +205,6 @@ class CloudbaseContainers {
176
205
  }
177
206
  }
178
207
 
179
- if (
180
- data
181
- && (isBuffer(params.data) || typeof params.data === 'string')
182
- && (data as any)?.length > 1000 * 1024 * 10
183
- ) {
184
- reject(new InvalieParamsError(SCOPE, 'body too large'))
185
- return
186
- }
187
-
188
208
  callContainer({
189
209
  ...params,
190
210
  success: resolve,
@@ -206,15 +226,15 @@ class CloudbaseContainers {
206
226
  this.containerInitPromise = new Promise((resolve, reject) => {
207
227
  initContainer({
208
228
  config,
209
- success(res) {
229
+ success: (res) => {
210
230
  if (String(res.statusCode) !== '200') {
211
231
  reject(genContainerError(res.data, `${COMPONENT_NAME}.initContainer`, 'init container fail'))
212
232
  }
213
233
  resolve(res)
214
234
  },
215
- fail(res) {
235
+ fail: (res) => {
216
236
  reject(genContainerError(res.data, `${COMPONENT_NAME}.initContainer`, 'init container fail'))
217
- this._containerInitPromis = null
237
+ this.containerInitPromise = null
218
238
  },
219
239
  })
220
240
  })
@@ -251,116 +271,3 @@ export function registerContainers(app: Pick<ICloudbase, 'registerComponent'>) {
251
271
  console.warn(e)
252
272
  }
253
273
  }
254
-
255
- async function getExportFunction(url, module, mode = 'go') {
256
- async function instantiateStreaming(resp, importObject, brotliCompressed = false) {
257
- if (brotliCompressed || !WebAssembly.instantiateStreaming) {
258
- const source = await (await resp).arrayBuffer()
259
- const buffer = brotliCompressed ? decompress(new Int8Array(source)) : source
260
- return WebAssembly.instantiate(buffer, importObject)
261
- }
262
-
263
- return WebAssembly.instantiateStreaming(resp, importObject)
264
- }
265
-
266
- let importObject = {
267
- env: {
268
- memoryBase: 0,
269
- tableBase: 0,
270
- memory: new WebAssembly.Memory({
271
- initial: 256,
272
- }),
273
- // table: new WebAssembly.Table({
274
- // initial: 2,
275
- // element: 'anyfunc',
276
- // }),
277
- },
278
- ...module,
279
- }
280
- let go
281
- const brotliCompressed = isBrotliCompressed(url)
282
-
283
- if (mode === 'go') {
284
- go = new Go()
285
- go._initedModulePromise = new Promise((resolve) => {
286
- go._initedModuleResolve = resolve
287
- })
288
- importObject = {
289
- ...go.importObject,
290
- env: {
291
- ...go.importObject.env,
292
- exportModule(module) {
293
- return go._initedModuleResolve(module)
294
- },
295
- },
296
- }
297
- }
298
-
299
- const reuslt = await instantiateStreaming(fetch(url), importObject, brotliCompressed)
300
-
301
- if (mode === 'go') {
302
- await Promise.race([
303
- go.run(reuslt.instance),
304
- new Promise(resolve => setTimeout(() => {
305
- resolve(null)
306
- }, 500),),
307
- ])
308
-
309
- return {
310
- callContainer: (window as any).callContainer,
311
- initContainer: (window as any).initContainer,
312
- }
313
- }
314
-
315
- // if (mode === 'go') {
316
- // go.run(reuslt.instance)
317
- // const module = await go._initedModulePromise
318
- // return module
319
- // }
320
-
321
- return reuslt.instance.exports
322
- }
323
-
324
- function loadUmdModule(jsUrl: string, umdModuleName: string, targetDoc: Document = document) {
325
- return new Promise<any>((resolve, reject) => {
326
- const win = targetDoc.defaultView
327
-
328
- const script = targetDoc.createElement('script')
329
- script.setAttribute('src', jsUrl)
330
- script.setAttribute('class', umdModuleName)
331
- script.addEventListener('load', () => {
332
- if (Object.prototype.hasOwnProperty.call(win, umdModuleName)) {
333
- return resolve(win[umdModuleName as any])
334
- }
335
- const error = new Error(`Fail to load UMD module ${umdModuleName} from [${jsUrl}].`)
336
- return reject(error)
337
- })
338
-
339
- script.addEventListener('error', (e) => {
340
- const error = new Error(`main bundle [${umdModuleName}] load failed from [${jsUrl}]: ${e?.message || ''}`)
341
- reject(error)
342
- })
343
- targetDoc.body.appendChild(script)
344
- })
345
- }
346
-
347
- async function loadJSExportFunction(url) {
348
- return loadUmdModule(url, 'cloudbase_private_link')
349
- }
350
-
351
- function isBrotliCompressed(url) {
352
- let brotliCompressed = false
353
-
354
- let pathname = ''
355
- try {
356
- const location = parseURL(url)
357
- pathname = location.pathname
358
- } catch (e) {
359
- pathname = url
360
- }
361
-
362
- if (/\.br$/.test(pathname)) {
363
- brotliCompressed = true
364
- }
365
- return brotliCompressed
366
- }
@@ -15,15 +15,36 @@ export function isBuffer(buf: any) {
15
15
  return buf instanceof ArrayBuffer || ArrayBuffer.isView(buf)
16
16
  }
17
17
 
18
- export function serializeRequestBody<T>(headers, data: T): T | string {
18
+ function object2Qs(data) {
19
+ const list = Object.entries(data || {}).reduce((list, [key, value]: [string, string]) => {
20
+ list.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
21
+ return list
22
+ }, [])
23
+ if (list.length) {
24
+ return list.join('&')
25
+ }
26
+ }
27
+
28
+ export function serializeRequestBody<T>(headers, data: T, method = 'POST'): T | string {
19
29
  let res: T | string = data
20
- const contentType_key = 'Content-Type'
30
+ const contentTypeKey = 'Content-Type'
21
31
  if (typeof data === 'object' && !isBuffer(data)) {
22
- if (!headers[contentType_key] && !headers['content-type']) {
23
- headers[contentType_key] = 'application/json'
32
+ if (!headers[contentTypeKey] && !headers['content-type']) {
33
+ headers[contentTypeKey] = 'application/json'
24
34
  }
25
35
 
26
- const contentType = headers[contentType_key] || headers['content-type']
36
+ const contentType = headers[contentTypeKey] || headers['content-type']
37
+
38
+ if (method === 'GET') {
39
+ try {
40
+ return object2Qs(data) || ''
41
+ } catch (e) {
42
+ throw new Error(JSON.stringify({
43
+ code: ERRORS.INVALID_PARAMS,
44
+ msg: `[${COMPONENT_NAME}.callContainer] invalid data in query method, ${e.message}`,
45
+ }),)
46
+ }
47
+ }
27
48
 
28
49
  switch (contentType) {
29
50
  case 'application/json': {
@@ -39,12 +60,9 @@ export function serializeRequestBody<T>(headers, data: T): T | string {
39
60
  }
40
61
  case 'application/x-www-form-urlencoded': {
41
62
  try {
42
- const list = Object.entries(data || {}).reduce((list, [key, value]: [string, string]) => {
43
- list.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
44
- return list
45
- }, [])
46
- if (list.length) {
47
- res = list.join('&')
63
+ const qs = object2Qs(data)
64
+ if (qs) {
65
+ res = qs
48
66
  }
49
67
  } catch (e) {
50
68
  throw new Error(JSON.stringify({
@@ -0,0 +1,134 @@
1
+ import decompress from 'brotli/decompress'
2
+ import Go from '../go_wams_exec'
3
+ import { parseURL } from '.'
4
+
5
+ async function instantiateStreaming(resp, importObject, brotliCompressed = false) {
6
+ if (brotliCompressed || !WebAssembly.instantiateStreaming) {
7
+ const source = await (await resp).arrayBuffer()
8
+ const buffer = brotliCompressed ? decompress(new Int8Array(source)) : source
9
+ return WebAssembly.instantiate(buffer, importObject)
10
+ }
11
+
12
+ return WebAssembly.instantiateStreaming(resp, importObject)
13
+ }
14
+
15
+ function isBrotliCompressed(url) {
16
+ let brotliCompressed = false
17
+
18
+ let pathname = ''
19
+ try {
20
+ const location = parseURL(url)
21
+ pathname = location.pathname
22
+ } catch (e) {
23
+ pathname = url
24
+ }
25
+
26
+ if (/\.br$/.test(pathname)) {
27
+ brotliCompressed = true
28
+ }
29
+ return brotliCompressed
30
+ }
31
+
32
+ export async function getExportFunction(url, module, mode = 'go') {
33
+ let importObject = {
34
+ env: {
35
+ memoryBase: 0,
36
+ tableBase: 0,
37
+ memory: new WebAssembly.Memory({
38
+ initial: 256,
39
+ }),
40
+ // table: new WebAssembly.Table({
41
+ // initial: 2,
42
+ // element: 'anyfunc',
43
+ // }),
44
+ },
45
+ ...module,
46
+ }
47
+ let go
48
+ const brotliCompressed = isBrotliCompressed(url)
49
+
50
+ if (mode === 'go') {
51
+ go = new Go()
52
+ go._initedModulePromise = new Promise((resolve) => {
53
+ go._initedModuleResolve = resolve
54
+ })
55
+ importObject = {
56
+ ...go.importObject,
57
+ env: {
58
+ ...go.importObject.env,
59
+ exportModule(module) {
60
+ return go._initedModuleResolve(module)
61
+ },
62
+ },
63
+ }
64
+ }
65
+
66
+ const reuslt = await instantiateStreaming(fetch(url), importObject, brotliCompressed)
67
+
68
+ if (mode === 'go') {
69
+ await Promise.race([
70
+ go.run(reuslt.instance),
71
+ new Promise(resolve => setTimeout(() => {
72
+ resolve(null)
73
+ }, 500),),
74
+ ])
75
+
76
+ return {
77
+ callContainer: (window as any).callContainer,
78
+ initContainer: (window as any).initContainer,
79
+ }
80
+ }
81
+
82
+ // if (mode === 'go') {
83
+ // go.run(reuslt.instance)
84
+ // const module = await go._initedModulePromise
85
+ // return module
86
+ // }
87
+
88
+ return reuslt.instance.exports
89
+ }
90
+
91
+ export async function loadJSExportFunction(config?: { vm: string; vender?: string }) {
92
+ const { vm, vender } = config || {}
93
+ const VENDER_KEY = 'cloudbase_private_link_vender'
94
+
95
+ if (vender || !Object.prototype.hasOwnProperty.call(document.defaultView, VENDER_KEY)) {
96
+ await loadUmdModule(
97
+ vender
98
+ || 'https://cdn.jsdelivr.net/npm/@cloudbase/privatelink-vender@0.0.1-alpha.3/dist/cdn/cloudbase.privatelink.vender.js',
99
+ VENDER_KEY,
100
+ )
101
+ }
102
+
103
+ return loadUmdModule(
104
+ vm || 'https://cdn.jsdelivr.net/npm/@cloudbase/privatelink@0.0.1-alpha.0/dist/cdn/cloudbase.privatelink.vm.js',
105
+ 'cloudbase_private_link',
106
+ )
107
+ }
108
+
109
+ function loadUmdModule(jsUrl: string, umdModuleName: string, targetDoc: Document = document) {
110
+ return new Promise<any>((resolve, reject) => {
111
+ const win = targetDoc.defaultView
112
+
113
+ const script = targetDoc.createElement('script')
114
+ script.setAttribute('src', jsUrl)
115
+ script.setAttribute('class', umdModuleName)
116
+ script.addEventListener('load', () => {
117
+ if (Object.prototype.hasOwnProperty.call(win, umdModuleName)) {
118
+ return resolve(win[umdModuleName as any])
119
+ }
120
+ const error = new Error(`Fail to load UMD module ${umdModuleName} from [${jsUrl}].`)
121
+ return reject(error)
122
+ })
123
+
124
+ script.addEventListener('error', (e) => {
125
+ const error = new Error(`main bundle [${umdModuleName}] load failed from [${jsUrl}]: ${e?.message || ''}`)
126
+ reject(error)
127
+ })
128
+ if (targetDoc.body) {
129
+ targetDoc.body.appendChild(script)
130
+ } else {
131
+ targetDoc.head.appendChild(script)
132
+ }
133
+ })
134
+ }
@@ -0,0 +1,84 @@
1
+ const webpack = require('webpack')
2
+ const TerserPlugin = require('terser-webpack-plugin')
3
+ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
4
+
5
+ module.exports = function (options) {
6
+ const { context, entry, output, mode, watch, externals, definePlugin = {}, optimization = {} } = options
7
+ const isDevelopment = mode !== 'production'
8
+ let plugins = [
9
+ // new WatchRunPlugin()
10
+ new webpack.DefinePlugin(
11
+ Object.assign(
12
+ {
13
+ 'globalThis.IS_MP_BUILD': false,
14
+ },
15
+ definePlugin,
16
+ ),
17
+ ),
18
+ // new BundleAnalyzerPlugin(),
19
+ ].filter((item) => !!item)
20
+ return {
21
+ context,
22
+ entry,
23
+ mode,
24
+ watch,
25
+ watchOptions: {
26
+ ignored: [output.path],
27
+ },
28
+ output,
29
+ externals,
30
+ cache: {
31
+ type: 'memory',
32
+ },
33
+ devtool: false,
34
+ resolve: {
35
+ extensions: ['.ts', '.js', '.json'],
36
+ },
37
+ module: {
38
+ rules: [
39
+ {
40
+ test: /\.ts$/,
41
+ exclude: [/node_modules/],
42
+ use: ['babel-loader', 'ts-loader'],
43
+ },
44
+ {
45
+ test: /\.js$/,
46
+ exclude: [/node_modules/],
47
+ use: ['babel-loader'],
48
+ },
49
+ {
50
+ test: /package\.json$/,
51
+ loader: 'package-json-cleanup-loader',
52
+ options: {
53
+ only: ['version'],
54
+ },
55
+ },
56
+ ],
57
+ noParse: [/sjcl\.js$/],
58
+ },
59
+ plugins,
60
+ optimization: {
61
+ moduleIds: 'deterministic',
62
+ emitOnErrors: false,
63
+ removeEmptyChunks: true,
64
+ usedExports: true,
65
+ splitChunks: false,
66
+ ...optimization,
67
+ ...(isDevelopment
68
+ ? {
69
+ minimize: false,
70
+ removeAvailableModules: false,
71
+ concatenateModules: true,
72
+ }
73
+ : {
74
+ minimizer: [
75
+ new TerserPlugin({
76
+ test: /\.js(\?.*)?$/i,
77
+ cache: false,
78
+ parallel: true,
79
+ }),
80
+ ],
81
+ }),
82
+ },
83
+ }
84
+ }
@@ -0,0 +1,22 @@
1
+ const path = require('path')
2
+
3
+ const params = {
4
+ context: path.resolve(__dirname, '../../'),
5
+ mode: 'production',
6
+ watch: false,
7
+ entry: path.resolve(__dirname, '../src/index.ts'),
8
+ output: {
9
+ path: path.resolve(__dirname, '../dist/miniprogram'),
10
+ filename: 'index.js',
11
+ library: `cloudbase_container`,
12
+ libraryTarget: 'umd',
13
+ umdNamedDefine: true,
14
+ globalObject: 'typeof window !== "undefined"?window:this',
15
+ },
16
+ externals: {},
17
+ definePlugin: {
18
+ 'globalThis.IS_MP_BUILD': true, // 注入环境变量,用于业务代码判断
19
+ },
20
+ }
21
+
22
+ module.exports = require('./web.prod.js')(params)