Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

gas-client

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gas-client - npm Package Compare versions

Comparing version 0.3.0 to 1.0.0-pr.1

build/classes/function-host.d.ts

152

build/index.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _uuid = require("uuid");
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Util that returns true if allowedDevelopmentDomains matches origin
* @param {string|function} allowedDevelopmentDomains either a string of space-separated allowed subdomains or a function that accepts the origin as an argument and returns true if permitted
* @param {string} origin the target origin subdomain to compare against
*/
var checkAllowList = function checkAllowList(allowedDevelopmentDomains, origin) {
if (typeof allowedDevelopmentDomains === 'string') {
return allowedDevelopmentDomains.split(' ').some(function (permittedOrigin) {
return permittedOrigin === origin;
});
}
if (typeof allowedDevelopmentDomains === 'function') {
return allowedDevelopmentDomains(origin) === true;
}
return false;
};
var Server =
/**
* Accepts a single `config` object
* @param {object} [config] An optional config object for use in development.
* @param {string|function} [config.allowedDevelopmentDomains] An optional config to specify which domains are permitted for receiving communication from a parent window. This is a security setting, and if not specified, will block functionality in development. Will accept either a space-separated string of allowed subdomains, e.g. `https://localhost:3000 http://localhost:3000` (notice no trailing slash); or a function that takes in the requesting origin should return `true` to allow communication, e.g. `(origin) => /localhost:\d+$/.test(origin)`
* @param {string} [config.parentTargetOrigin] An optional config to specify which parent window domain this client can send communication to. Defaults to own domain for backward compatibility with Google Apps Script Webpack Dev Server development tool (domain where the client is running, e.g. localhost). Can be '*' to allow all parent domains.
*/
function Server() {
var _this = this;
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, Server);
// skip the reserved names: https://developers.google.com/apps-script/guides/html/reference/run
var ignoredFunctionNames = ['withFailureHandler', 'withLogger', 'withSuccessHandler', 'withUserObject'];
this.serverFunctions = {};
try {
// get the names of all of our publicly accessible server functions
var functionNames = Object.keys(google.script.run).filter( // filter out the reserved names -- we don't want those
function (functionName) {
return !ignoredFunctionNames.includes(functionName);
}); // attach Promise-based functions to the serverFunctions property
functionNames.forEach(function (functionName) {
_this.serverFunctions[functionName] = function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
Object.defineProperty(exports, "__esModule", { value: true });
exports.GASClient = void 0;
var is_gas_environment_1 = require("./utils/is-gas-environment");
var gas_promises_1 = require("./classes/gas-promises");
var server_proxy_1 = require("./classes/server-proxy");
var GASClient = /** @class */ (function () {
function GASClient(_config) {
this._config = _config;
if (is_gas_environment_1.isGASEnvironment()) {
this._functionHost = new gas_promises_1.GASPromises();
}
return new Promise(function (resolve, reject) {
var _google$script$run$wi;
(_google$script$run$wi = google.script.run.withSuccessHandler(resolve).withFailureHandler(reject))[functionName].apply(_google$script$run$wi, args);
});
};
});
} catch (err) {
if (typeof google === 'undefined') {
// we'll store and access the resolve/reject functions here by id
window.gasStore = {}; // this domain should be restricted to googleusercontent.com but the subdomain is variable
// supports window.location.origin as default for backward compatibility
var targetOrigin = config.parentTargetOrigin || window.location.origin; // set up the message 'receive' handler
var receiveMessageHandler = function receiveMessageHandler(event) {
var allowedDevelopmentDomains = config.allowedDevelopmentDomains; // check the allow list for the receiving origin
var allowOrigin = checkAllowList(allowedDevelopmentDomains, event.origin);
if (!allowOrigin) return; // we only care about the type: 'RESPONSE' messages here
if (event.data.type !== 'RESPONSE') return;
var _event$data = event.data,
response = _event$data.response,
status = _event$data.status,
id = _event$data.id; // look up the saved resolve and reject funtions in our global store based
// on the response id, and call the function depending on the response status
var _window$gasStore$id = window.gasStore[id],
resolve = _window$gasStore$id.resolve,
reject = _window$gasStore$id.reject;
if (status === 'ERROR') {
// TODO: return here so resolve doesn't get called on error
reject(response);
else {
this._functionHost = new server_proxy_1.ServerProxy(this._config);
}
resolve(response);
};
window.addEventListener('message', receiveMessageHandler, false);
var handler = {
get: function get(target, functionName) {
var id = (0, _uuid.v4)();
var promise = new Promise(function (resolve, reject) {
// store the new Promise's resolve and reject
window.gasStore[id] = {
resolve: resolve,
reject: reject
};
});
return function () {
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
// https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
window.parent.postMessage({
type: 'REQUEST',
id: id,
functionName: functionName,
args: [].concat(args)
}, targetOrigin);
return promise;
};
}
};
this.serverFunctions = new Proxy({}, handler);
}
}
};
exports["default"] = Server;
Object.defineProperty(GASClient.prototype, "serverFunctions", {
get: function () {
return this._functionHost.serverFunctions;
},
enumerable: false,
configurable: true
});
return GASClient;
}());
exports.GASClient = GASClient;
{
"name": "gas-client",
"version": "0.3.0",
"version": "1.0.0-pr.1",
"description": "A client-side utility class that can call server-side Google Apps Script functions",
"main": "build/index.js",
"files": [
"build",
"src"
"src",
"build"
],
"repository": "https://github.com/enuchi/gas-client.git",
"author": "Elisha Nuchi",
"contributors": [
"Guilherme Tod <guilhermetod@gmail.com> (https://github.com/guilhermetod)"
],
"license": "MIT",
"scripts": {
"prepack": "yarn build",
"pretest": "yarn build",
"test": "jest --coverage",
"test:watch": "jest --coverage --watch",
"prebuild": "rm -rf build",
"build": "babel src/index.js -d build"
"build": "tsc"
},

@@ -25,3 +29,3 @@ "bugs": {

"keywords": [
"Goole",
"Google",
"Apps",

@@ -37,7 +41,11 @@ "Script",

"@types/jest": "^26.0.15",
"@types/node": "^14.6.2",
"@types/uuid": "^8.3.0",
"@typescript-eslint/eslint-plugin": "3.10.1",
"@typescript-eslint/parser": "3.10.1",
"babel-eslint": "^10.1.0",
"eslint": "^7.5.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-config-airbnb-typescript": "^9.0.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-babel": "^5.3.1",
"eslint-plugin-import": "^2.22.0",

@@ -47,3 +55,4 @@ "eslint-plugin-jest": "^24.1.3",

"jest": "^26.6.3",
"prettier": "^2.0.5"
"prettier": "^2.0.5",
"typescript": "^4.0.2"
},

@@ -50,0 +59,0 @@ "dependencies": {

@@ -1,6 +0,6 @@

# gas-client
# gas-client v1.0.0
A client-side utility class that uses promises to call server-side Google Apps Script functions. This is a user-friendly wrapper of [google.script.run](https://developers.google.com/apps-script/guides/html/reference/run).
It can also optionally be used in local development and is designed to interact with the [Google Apps Script Dev Server](https://github.com/enuchi/Google-Apps-Script-Webpack-Dev-Server) used in the [React / Google Apps Script](https://github.com/enuchi/React-Google-Apps-Script) project.
It can also optionally be used in local development and is designed to work with [React Google Apps Script](https://github.com/enuchi/React-Google-Apps-Script) project.

@@ -12,2 +12,3 @@ ---

Install
```bash

@@ -20,4 +21,4 @@ > npm install gas-client

```javascript
import Server from 'gas-client';
const { serverFunctions } = new Server();
import { GASClient } from 'gas-client';
const { serverFunctions } = new GASClient();

@@ -36,5 +37,5 @@ // We now have access to all our server functions, which return promises

```javascript
import Server from 'gas-client';
import { GASClient } from 'gas-client';
const { serverFunctions } = new Server({
const { serverFunctions } = new GASClient({
allowedDevelopmentDomains: 'https://localhost:3000',

@@ -67,4 +68,4 @@ });

// With this package we can now do this:
import Server from 'gas-client';
const { serverFunctions } = new Server();
import { GASClient } from 'gas-client';
const { serverFunctions } = new GASClient();

@@ -92,11 +93,69 @@ // We now have access to all our server functions, which return promises

## Typescript
This project now supports typescript!
To use it, simply import your server functions and pass them as a type parameter when creating your server.
### On your server-side code
```typescript
// src/server/index.ts
interface SheetData {
name: string;
numOfRows: number;
}
const getSheetData = (): SheetData => {
const sheet = SpreadsheetApp.getActiveSheet();
return {
name: sheet.getName(),
numOfRows: sheet.getMaxRows(),
};
};
const appendRowsToSheet = (sheetName: string, rowsToAdd: number): void => {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
sheet.insertRowsAfter(sheet.getMaxRows(), rowsToAdd);
};
export { getSheetData, appendRowsToSheet };
```
### On your client-side code
```typescript
// src/client/add-rows.ts
import { GASClient } from 'gas-client';
import { showUserPrompt } from './show-user-prompt';
import * as server from '../server';
const { serverFunctions } = new GASClient<typeof server>();
const promptUser = async (): Promise<void> => {
const { name, numOfRows } = await serverFunctions.getSheetData();
const response = await showUserPrompt(`Sheet ${name} has ${numOfRows} rows. How many would you like to add?`);
serverFunctions.appendRowsToSheet(name, numOfRows);
};
```
Now you can have your function names, parameters and return types checked.
### Get better IDE support and catch errors ahead!
![Get-better-IDE](https://i.imgur.com/gPmOPqX.gif)
---
## API
The config object takes:
- `allowedDevelopmentDomains`: A config to specifiy which domains are permitted for communication with Google Apps Script Webpack Dev Server development tool. This is a security setting, and if not specified, will block functionality in development. `allowedDevelopmentDomains` will accept either a space-separated string of allowed subdomains, e.g. `'https://localhost:3000 https://localhost:8080'` (notice no trailing slashes); or a function that takes in the requesting origin and should return `true` to allow communication, e.g. `(origin) => /localhost:\d+$/.test(origin);`
- `parentTargetOrigin` An optional string to specify which parent window domain this client can send communication to. Defaults to own domain for backward compatibility with Google Apps Script Webpack Dev Server development tool (default uses domain where the client is running, e.g. localhost). Can be '*' to allow all parent domains if parent is unknown or variable.
- `allowedDevelopmentDomains`: A config to specifiy which domains are permitted for communication with Google Apps Script Webpack Dev Server development tool. This is a security setting, and if not specified, will block functionality in development. `allowedDevelopmentDomains` will accept either a space-separated string of allowed subdomains, e.g. `'https://localhost:3000 https://localhost:8080'` (notice no trailing slashes); or a function that should expect one argument, the requesting origin, and should return `true` to allow communication, e.g. `(origin) => /localhost:\d+$/.test(origin);`
### Production mode
In the normal Google Apps Script production environment, `new Server()` will have one available method:
In the normal Google Apps Script production environment, a `new GASClient()` instance will have one available method:

@@ -111,4 +170,15 @@ - `serverFunctions`: an object containing all publicly exposed server functions (see example above).

Calling `new Server({ allowedDevelopmentDomains })` will create an instance with the following method in development mode:
Calling `new GASClient({ allowedDevelopmentDomains })` will create an instance with the following method in development mode:
- `serverFunctions`: a proxy object, used for development purposes, that mimics calling `google.script.run`. It will dispatch a message to the parent iframe (our custom Dev Server), which will call an app that actually interacts with the `google.script.run` API. Development mode will also handle the response and resolve or reject based on the response type. See the implementation for details on the event signature.
## Contributors
@guilhermetod - Addition of TypeScript support and general improvements to this project!
## Change Log
Breaking changes in v1.0.0:
- `targetOrigin` is set to `'*'` due to deprecation of [Google Apps Script Dev Server](https://github.com/enuchi/Google-Apps-Script-Webpack-Dev-Server) and variability of the parent Google Apps Script environment's subdomains
- The main class is exported as named `{ GASClient }` export instead of as default export
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc