{"id":40682089,"url":"https://github.com/felipechang/netsuite-starter","last_synced_at":"2026-01-21T10:35:06.271Z","repository":{"id":57310374,"uuid":"297842628","full_name":"felipechang/netsuite-starter","owner":"felipechang","description":"Scaffold to build NetSuite Account Customizations and SuiteApps. ","archived":false,"fork":false,"pushed_at":"2021-08-05T19:59:17.000Z","size":650,"stargazers_count":14,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-19T10:34:33.091Z","etag":null,"topics":["jest","netsuite","oracle","suitecloud","suitescript","suitescript2","typescript"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/felipechang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-09-23T03:35:12.000Z","updated_at":"2024-09-27T19:07:11.000Z","dependencies_parsed_at":"2022-09-07T20:21:27.172Z","dependency_job_id":null,"html_url":"https://github.com/felipechang/netsuite-starter","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/felipechang/netsuite-starter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipechang%2Fnetsuite-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipechang%2Fnetsuite-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipechang%2Fnetsuite-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipechang%2Fnetsuite-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/felipechang","download_url":"https://codeload.github.com/felipechang/netsuite-starter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipechang%2Fnetsuite-starter/sbom","scorecard":{"id":396047,"data":{"date":"2025-08-11","repo":{"name":"github.com/felipechang/netsuite-starter","commit":"a83a5a4a5d589d80f2c50fc3448380acf2c2b30c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.9,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":1,"reason":"9 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-phwq-j96m-2c2q","Warn: Project is vulnerable to: GHSA-ghr5-ch3p-vcr6","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-8hfj-j24r-96c4","Warn: Project is vulnerable to: GHSA-wc69-rhjr-hc9g","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T19:02:05.195Z","repository_id":57310374,"created_at":"2025-08-18T19:02:05.195Z","updated_at":"2025-08-18T19:02:05.195Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28631936,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T04:47:28.174Z","status":"ssl_error","status_checked_at":"2026-01-21T04:47:22.943Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jest","netsuite","oracle","suitecloud","suitescript","suitescript2","typescript"],"created_at":"2026-01-21T10:35:05.647Z","updated_at":"2026-01-21T10:35:06.263Z","avatar_url":"https://github.com/felipechang.png","language":"JavaScript","readme":"# NetSuite Starter\n\n## Instructions\n\n1. Install SuiteCloud CLI for Node.js: `npm install -g @oracle/suitecloud-cli`\n\n1. Install NetSuite Starter CLI: `npm install -g netsuite-starter`\n\n2. Create new project: `nsx project`\n\n3. Fill in prompted details\n\n4. Enter working directory: `cd my-project`\n\n5. Install dependencies: `npm install`\n\n6. **Read the generated README.md file for further instructions**\n\n## Libraries\n\n### Browser\n\n```typescript\n\nconst browserLibrary = new BrowserLibrary();\n\n// MESSAGE\n\n// Create a confirmation message on screen for 5 seconds\n// Methods available include: confirmation, error, info, and warning\nbrowserLibrary.message.confirmation({\n    message: \" This is a message\",\n    title: \"Hi\",\n    duration: 5000\n});\n\n// QUERY\n\n// Get an JSON with key/value query parameters\nbrowserLibrary.query.get();\n// =\u003e {foo: \"bar\"}\n\n// Get an JSON with key/value query parameters from the previous page\nbrowserLibrary.query.getPrevious();\n// =\u003e {foo: \"baz\"}\n\n// Use query parameters to populate current record body fields\nbrowserLibrary.query.populate(currentRecord, false);\n\n// STORAGE\n\n// Set key/value on session storage\nbrowserLibrary.storage.set(\"foo\", \"bar\");\n\n// Get session storage item by key\nbrowserLibrary.storage.get(\"foo\");\n// =\u003e \"bar\"\n\n// Get session storage item by key\nbrowserLibrary.storage.getAllKeys();\n// =\u003e [\"foo\"]\n\n// Remove key from session storage\nbrowserLibrary.storage.remove(\"foo\");\n\n// Clear session storage\nbrowserLibrary.storage.clear();\n```\n\n### Cache\n\n```typescript\n\nconst cacheLibrary = new CacheLibrary({\n\n    // Name\n    name: \"cooks\",\n\n    // Scope\n    scope: Scope.PRIVATE,\n\n    // ttl (optional) ==\u003e Defaults to 300. Has to be greater than 300\n    ttl: 60 * 15,\n\n    // Boolean control field (optional) ==\u003e Used as an on/off switch for the cache\n    // If a loader is provided it will return that value, if not it returns {key: null}\n    toggle: \"custscript_myscript_toggle\"\n});\n\n// Set a formatter for the cache key name\ncacheLibrary.formatCacheName((keyName) =\u003e {\n    return `my_prefix_${keyName}`;\n});\n\n// Set cache duration. The calculator is used for convenience\ncacheLibrary.setTTL(cacheLibrary.ttlCalculator(({\n    hours: 1,\n    minutes: 20,\n    seconds: 30\n})));\n\n// Set key-value pairs\ncacheLibrary.set({jim: {cook: true}, john: {cook: false}});\n\n// Get a single key\ncacheLibrary.get({name: \"jim\"});\n// =\u003e {jim: {cook: true}}\n\n// Get multiple keys\ncacheLibrary.get({name: [\"jim\", \"john\"]});\n// =\u003e {jim: {cook: true}, john: {cook: false}}\n\n// Get a single key and provide a loader if not found\ncacheLibrary.get({\n    name: \"jim\",\n    loader: (key) =\u003e {\n        // Here we just use the native NetSuite loader\n    }\n});\n// =\u003e {jim: {cook: true}}\n\n// Get multiple keys and provide a loader any are not found\ncacheLibrary.get({\n    name: [\"jim\", \"john\"],\n    loader: (key) =\u003e {\n        // Here we just use the native NetSuite loader\n    }\n});\n// All missing keys are cached, and the full result object is returned\n// =\u003e {jim: {cook: true}, john: {cook: false}}\n\n// Remove a single key\ncacheLibrary.remove(\"jim\");\n\n// Remove multiple keys\ncacheLibrary.remove([\"jim\", \"john\"]);\n```\n\n### CSV\n\n```typescript\n\n// Load CSV file by ID\n// At this point we can set two customizations:\n// - cellCleaner: RegEx used to clean cell contents, defaults to /\\s*(.*?)\\s*/g\n// - columnDelimiter: Used to split columns, defaults to \",\"\nconst csvLibrary = new CsvLibrary({\n    id: \"12345\",\n    cellCleaner: /\"/g,\n    columnDelimiter: \"','\"\n});\n\ncsvLibrary.getFile()\n// =\u003e Returns file object\n\ncsvLibrary.getRawContents()\n// =\u003e Returns CSV content string\n\ncsvLibrary.jsonToCSV([{foo:\"bar\"}, {foo:\"zoo\"}]);\n// =\u003e \"foo\\nbar\\nzoo\"\n\ncsvLibrary.toJSON();\n// =\u003e Returns JSON array with all headers as properties\n\ncsvLibrary.toJSON([\"Name\", \"Email\"]);\n// =\u003e Returns JSON array with named headers as properties\n```\n\n### GOVERNANCE\n\n```typescript\n\nconst governanceLibrary = new GovernanceLibrary();\n\n// Evaluate if we have governance points remaining\ngovernanceLibrary.hasRemaining();\n\n// Get governance points remaining\ngovernanceLibrary.getRemaining();\n\n// Update minimum points required\ngovernanceLibrary.updateFloor(200);\n\n// Run until we exhaust governance points\ngovernanceLibrary.runUntil(\n    (remaining) =\u003e {\n        // Perform record operations\n    },\n    () =\u003e {\n        // Optional callback for when we run out of governance\n    });\n```\n\n### Search\n\n```typescript\n\n// We create the response we want\ntype Response = { email: string, phone: string };\n\n// Create a search\nconst searchLibraryCreated = new SearchLibrary({\n    type: \"customer\",\n    filters: [{\n        name: \"firstname\",\n        operator: Operator.IS,\n        values: [\"Peter\"]\n    }],\n    columns: [{\n        name: \"phone\"\n    }]\n});\n\n// Load an existing search\nconst searchLibraryLoaded = new SearchLibrary({\n    type: \"customer\",\n    id: \"12345\",\n});\n\n// Add a column to the search\nsearchLibraryCreated.addColumn({\n    name: \"email\"\n});\n\n// Remove a column to the search\nsearchLibraryCreated.removeColumn({\n    name: \"email\"\n});\n\n// Add a filter to the search\nsearchLibraryCreated.addFilter({\n    name: \"lastname\",\n    operator: Operator.IS,\n    values: [\"Griffin\"]\n});\n\n// Remove a filter to the search\nsearchLibraryCreated.removeFilter({\n    name: \"lastname\",\n    operator: Operator.IS,\n    values: [\"Griffin\"]\n});\n\n// Set the transform function: This is mandatory and takes care of converting the results\n// Response must be in the format {continue: boolean, response: Response}\n// If continue is false the search will stop\nsearchLibraryCreated.setTransform \u003cResponse\u003e((result) =\u003e {\n    return {\n        continue: true,\n        response: {\n            email: result.getValue({\n                name: \"email\"\n            }),\n            phone: result.getValue({\n                name: \"phone\"\n            }),\n        }\n    };\n});\n\n// Get the first two records\nconst rangeResponse = searchLibraryCreated.getRange\u003cResponse\u003e({start: 1, end: 2});\n// =\u003e [\n// {email: \"peter1@gmail.com\", phone: \"9999999\"},\n// {email: \"peter2@gmail.com\", phone: \"9999999\"}\n// ]\n\n// Get the all records with a page size of 5\nsearchLibraryCreated.pageSize = 5;\nconst response = searchLibraryCreated.getResults\u003cResponse\u003e();\n// =\u003e [\n// {email: \"peter1@gmail.com\", phone: \"9999999\"},\n// {email: \"peter2@gmail.com\", phone: \"9999999\"},\n// {email: \"peter3@gmail.com\", phone: \"9999999\"},\n// ]\n\n// Async get the all records\nsearchLibraryCreated.getResultsClient\u003cResponse\u003e((response, error) =\u003e {\n\n    if (error) {\n        throw new Error(error);\n    }\n\n    // response =\u003e [\n    // {email: \"peter1@gmail.com\", phone: \"9999999\"},\n    // {email: \"peter2@gmail.com\", phone: \"9999999\"},\n    // {email: \"peter3@gmail.com\", phone: \"9999999\"},\n    // ]\n});\n```\n\n## License\n\nGNU GPL see LICENSE.\n\n## Author\n\nFelipe Chang \u003cfelipechang@hardcake.org\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelipechang%2Fnetsuite-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffelipechang%2Fnetsuite-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelipechang%2Fnetsuite-starter/lists"}