Meteor lepozepo:s3 - Reference Error S3 is not defined - meteor

I'm trying to use lepozepo:s3 for a new project.
On the client this seems to work fine:
console.log(S3);
S3.config = {
key: Meteor.settings.private.awsS3.access_key,
secret: Meteor.settings.private.awsS3.secret,
bucket: Meteor.settings.private.awsS3.bucket,
region: Meteor.settings.private.awsS3.region,
}
console.log(S3);
This shows clearly hat the S3 object is defined before the call to the configuration and then later updated.
On the client, however, I am getting a reference error when trying to implement the upload function or helper as per the documentation.
Template.upload.helpers({
"files": function () {
console.log(S3);
return S3.collection.find();
}
})
I'm not doing any imports but have tried before to import S3 from "meteor/lepozepo:s3" and S3 ended up being {} and empty object.

Related

SQL with Prisma under Electron

My Main goal is to create an Electron App (Windows) that locally stores data in an SQLite Database. And because of type safety I choose to use the Prisma framework instead of other SQLite Frameworks.
I took this Electron Sample Project and now try to include Prisma. Depending on what I try different problems do arrise.
1. PrismaClient is unable to be run in the Browser
I executed npx prisma generate and then try to execute this function via a button:
import { PrismaClient } from '#prisma/client';
onSqlTestAction(): void {
const prisma = new PrismaClient();
const newTestObject = prisma.testTable.create(
{
data: {
value: "TestValue"
}
}
);
}
When executing this in Electron I get this:
core.js:6456 ERROR Error: PrismaClient is unable to be run in the browser.
In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues
at new PrismaClient (index-browser.js:93)
at HomeComponent.onSqlTestAction (home.component.ts:19)
at HomeComponent_Template_button_click_7_listener (template.html:7)
at executeListenerWithErrorHandling (core.js:15281)
at wrapListenerIn_markDirtyAndPreventDefault (core.js:15319)
at HTMLButtonElement.<anonymous> (platform-browser.js:568)
at ZoneDelegate.invokeTask (zone.js:406)
at Object.onInvokeTask (core.js:28666)
at ZoneDelegate.invokeTask (zone.js:405)
at Zone.runTask (zone.js:178)
It somehow seems logical that Prisma cannot run in a browser. But I actually build a native app - with Electron that embeds a Browser. It seems to be a loophole.
2. BREAKING CHANGE: webpack < 5 used to include polyfills
So i found this Question: How to use Prisma with Electron
Seemed to be exactly what I looked for. But the error message is different (Debian binaries were not found).
The solution provided is to generate the prisma artifacts into the src folder instead of node_modules - and this leads to 19 polyfills errors. One for example:
./src/database/generated/index.js:20:11-26 - Error: Module not found: Error: Can't resolve 'path' in '[PATH_TO_MY_PROJECT]\src\database\generated'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
- install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "path": false }
And this repeats with 18 other modules. Since the error message to begin with was different I also doubt that this is the way to go.
I finally figured this out. What I needed to understand was, that all Electron apps consist of 2 parts: The Frontend Webapp (running in embedded Chromium) and a Node backend server. Those 2 parts are called IPC Main and IPC Renderer and they can communicate with each other. And since Prisma can only run on the main process which is the backend I had to send my SQL actions to the Electron backend and execute them there.
My minimal example
In the frontend (I use Angular)
// This refers to the node_modules folder of the Electron Backend, the folder where the main.ts file is located.
// I just use this import so that I can use the prisma generated classes for type safety.
import { TestTable } from '../../../app/node_modules/.prisma/client';
// Button action
onSqlTestAction(): void {
this.electronService.ipcRenderer.invoke("prisma-channel", 'Test input').then((value) => {
const testObject: TestTable = JSON.parse(value);
console.log(testObject);
});
The sample project I used already had this service to provide the IPC Renderer:
#Injectable({
providedIn: 'root'
})
export class ElectronService {
ipcRenderer: typeof ipcRenderer;
webFrame: typeof webFrame;
remote: typeof remote;
childProcess: typeof childProcess;
fs: typeof fs;
get isElectron(): boolean {
return !!(window && window.process && window.process.type);
}
constructor() {
// Conditional imports
if (this.isElectron) {
this.ipcRenderer = window.require('electron').ipcRenderer;
this.webFrame = window.require('electron').webFrame;
this.childProcess = window.require('child_process');
this.fs = window.require('fs');
// If you want to use a NodeJS 3rd party deps in Renderer process (like #electron/remote),
// it must be declared in dependencies of both package.json (in root and app folders)
// If you want to use remote object in renderer process, please set enableRemoteModule to true in main.ts
this.remote = window.require('#electron/remote');
}
}
And then in the Electron backend I first added "#prisma/client": "^3.0.1" to the package.json (for the Electron backend not the frontend). Then I added to the main.ts this function to handle the requests from the renderer:
// main.ts
ipcMain.handle("prisma-channel", async (event, args) => {
const prisma = new PrismaClient();
await prisma.testTable.create(
{
data: {
value: args
}
}
);
const readValue = await prisma.testTable.findMany();
return JSON.stringify(readValue);
})
This way of simply adding the IPC Main handler in the main.ts file of course is a big code smell but usefull as minimal example. I think I will move on with the achitecture concept presented in this article.

How to pass a parameter from the Jupyter backend to a frontend extension

I currently have a value that is stored as an environment variable the environment where a jupyter server is running. I would like to somehow pass that value to a frontend extension. It does not have to read the environment variable in real time, I am fine with just using the value of the variable at startup. Is there a canonical way to pass parameters a frontend extension on startup? Would appreciate an examples of both setting the parameter from the backend and accessing it from the frontend.
[update]
I have posted a solution that works for nbextentions, but I can't seem to find the equivalent pattern for labextensions (typescript), any help there would be much appreciated.
I was able to do this by adding the following code to my jupter_notebook_config.py
from notebook.services.config import ConfigManager
cm = ConfigManager()
cm.update('notebook', {'variable_being_set': value})
Then I had the parameters defined in my extension in my main.js
// define default values for config parameters
var params = {
variable_being_set : 'default'
};
// to be called once config is loaded, this updates default config vals
// with the ones specified by the server's config file
var update_params = function() {
var config = Jupyter.notebook.config;
for (var key in params) {
if (config.data.hasOwnProperty(key) ){
params[key] = config.data[key];
}
}
};
I also have the parameters declared in my main.yaml
Parameters:
- name: variable_being_set
description: ...
input_type: text
default: `default_value`
This took some trial and error to find out because there is very little documentation on the ConfigManager class and none of it has an end-to-end example.

Vue Firebase / Firestore Duplicates

I am trying to go through a tutorial (link below) to learn vue and firebase. There is a main dashboard page with a list of components, and I have gotten that to display a list of employees. Then there is a view employee component. When I started to build that, and just loaded data, I started getting this error:
Uncaught FirebaseError {code: "app/duplicate-app", message: "Firebase:
Firebase App named '[DEFAULT]' already exists (app/duplicate-app).",
name: "[DEFAULT]", stack: "[DEFAULT]: Firebase: Firebase App named
'[DEFAULT]…0)↵ at fn (http://localhost:8081/app.js:89:20)"}
The firebase code I added to view employee is as follows:
import db from "./firebaseInit.js";
export default {
name: "view-employee",
data() {
return {
employee_id: null,
name: null,
dept: null,
position: null
};
},
beforeRouteEnter(to, from, next) {
db
.collection("employees")
.where("employee_id", "==", to.params.employee_id),
get().then(querySnapShot => {
querySnapShot.forEach(doc => {
next(vm => {
vm.employee_id = doc.data().employee_id
vm.name = doc.data().name
vm.dept = doc.data().dept
vm.position = doc.data().position
})
});
});
}
};
When I comment out this script on the view employee page, the error goes away. From what I can tell, I have done everything the same as the tutorial in the video, and as my buddy who did the same project.
There is also a warning, which may be related, which states as follows:
There are multiple modules with names that only differ in casing. This
can lead to unexpected behavior when compiling on a filesystem with
other case-semantic. Use equal casing. Compare these module
identifiers: *
/Users/jdurell/code/employeemanager/node_modules/babel-loader/lib/index.js!/Users/jdurell/code/employeemanager/src/components/FirebaseInit.js
I am working on this tutorial / project:
https://www.youtube.com/watch?v=cjEzK4me1k8&index=4&list=PLillGF-RfqbYsOOycB67Raf9dwmL6Y31M
Nemesv had the correct answer. It was a casing issue. I had the issue FirebaseInit on the other component. I changed that to firebaseInit so it was the same case on both components, and the error resolved. Thanks!

JSZip and cfs:collection in Meteor app

So, Im using udondan:jszip, cfs:collection,
cfs:standard-packages and
cfs:filesystem packages in my meteor app. The problem is that I cant store my zip files in the FS.COllection. Here is some of the code :
//Defining the collection
Reports = new FS.Collection('reports',{
stores: [new FS.Store.FileSystem('reports', {path: "~/public"})]
});
//Trying to add a file to the collection
var zip = new JSZip();
Reports.insert(zip);
After running the code Im getting this error:
Error: DataMan constructor received data that it doesn't support
Is there any way to make those packages work with each other ?
The JSZip object is not a file by itself. You can generate a file from it with the generateAsync function. The file type you'll want to create depends on if you want this to run on the client or server and how you want to use this file. The file types supported by both libraries are: (as per documentation, I haven't tested all these myself)
Blob object (client only): { type: 'blob' }
Uint8Array: { type: 'uint8array' }
ArrayBuffer: { type: 'arraybuffer' }
Buffer object (server only): { type: 'nodebuffer' }
So for example this should work:
zip.generateAsync({ type: 'arraybuffer' })
.then(function (content) {
Reports.insert(content);
});

Meteor Iron-Router: why isn't this routing setup (with waitOn and data functions) working correctly?

Using Iron-Router 1.0.3 and Meteor 1.0.
I have this route defined:
Router.route('audit', {
path: '/audit/:audit_id/',
template: 'audit',
data: function() {
audit = Audits.findOne({_id: this.params.audit_id});
lineitems = LineItems.find(JSON.parse(audit.query));
return {
audit: audit,
lineitems: lineitems
}
},
waitOn: function () {
return [
Meteor.subscribe('audits'),
Meteor.subscribe('lineitems', this.params.audit_id),
]
}
});
Objects in the Audits collection have the following structure:
{
_id: 'timestamped-id-that-I-generate',
name: 'some name',
query: JSON.stringify({'$and': [list of query conditions here]})
}
When I go to this route I get the following error in my console:
Uncaught TypeError: Cannot read property 'query' of undefined
But if I go to my browser console, I can examine the Audits collections and I see that the Audit object with the appropriate _id and query exists as expected.
Incidentally, the publish method for the lineitems on the server side will simply look up the same audit object and publish the line items that match it's query.
(I have to serialize the query back and forth via JSON because otherwise the query object would contain field names that violate MongoDB regulations.)
As of this writing, Iron Router's data hook may run multiple times when a route is evaluated. You can assume it will run once before the subscriptions are ready, and again afterward. Because it will run prior to your subscriptions being ready, you need to assume that Audits.findOne will return undefined at least once. You have two choices:
Check for this.ready() in your data hook:
data: function() {
if (this.ready()) {
audit = Audits.findOne({_id: this.params.audit_id});
lineitems = LineItems.find(JSON.parse(audit.query));
return {audit: audit, lineitems: lineitems};
}
}
Use a guard:
data: function() {
audit = Audits.findOne({_id: this.params.audit_id});
if (audit && audit.query) {
lineitems = LineItems.find(JSON.parse(audit.query));
return {audit: audit, lineitems: lineitems};
}
}
A combination of the two may actually be appropriate if: (a) you don't have any audits, or (b) not all audits have a query.

Resources